Error: Cannot find module './Utils/logger'que funciona perfeitamente na sua máquina e falha no momento em que é implantado. Essa classe de bug tem um pequeno número de causas e quase todas se resumem a uma diferença entre o ambiente de desenvolvimento e o servidor.
📋 Table of Contents
- Causa 1: Sensibilidade a maiúsculas e minúsculas (a mais comum)
- Causa 2: o pacote está em devDependencies
- Causa 3: node_modules copiado para o Docker
- Causa 4: Módulos nativos criados para a plataforma errada
- Causa 5: Extensões de arquivo ausentes no ESM
- Causa 6: Aliases de caminho TypeScript não resolvidos em tempo de execução
- Causa 7: A saída do build não foi implantada
- Diagnosticando Sistematicamente
- Prevenção
- Perguntas Frequentes
- Conclusão
Causa 1: Sensibilidade a maiúsculas e minúsculas (a mais comum)
macOS e Windows usam sistemas de arquivos que não diferenciam maiúsculas de minúsculas por padrão. Linux não. Entãorequire('./Utils/logger') resolve um arquivo chamadoutils/logger.js no seu laptop e falha no servidor.
// File on disk: src/utils/logger.js
const logger = require('./Utils/logger'); // works on macOS, fails on Linux
const logger = require('./utils/logger'); // ✅ correct everywhere
Encontre-os antes de implantar, verificando o que o Git realmente gravou, o que é oficial, independentemente do seu sistema de arquivos local.
# List tracked paths and eyeball the casing
git ls-files | grep -i utils
# Catch a rename that Git ignored because only the case changed
git config core.ignorecase false
git status
Se o Git registrou o caso errado, force a renomeação por meio de um nome intermediário.
git mv src/Utils src/utils-tmp
git mv src/utils-tmp src/utils
git commit -m "fix: correct directory casing for case-sensitive filesystems"
A prevenção confiável é um trabalho de CI executado no Linux. Ele detecta isso em cada solicitação pull, e não na implantação.
Causa 2: o pacote está em devDependencies
As instalações de produção ignoram as dependências de desenvolvimento, portanto, qualquer coisa importada pelo código de tempo de execução deve ser uma dependência regular.
npm ci --omit=dev # devDependencies are not installed
{
"dependencies": {
"express": "^5.0.0"
},
"devDependencies": {
"dotenv": "^17.0.0" // ❌ but required at runtime in server.js
}
}
# Move it
npm uninstall dotenv
npm install dotenv
Para encontrar todos os casos de uma vez, instale as dependências de produção em um diretório limpo e inicie o aplicativo.
rm -rf node_modules
npm ci --omit=dev
node dist/server.js
Causa 3: node_modules copiado para o Docker
Copiando um construído localmentenode_modules em uma imagem quebra módulos nativos, porque os binários compilados para macOS ou para sua arquitetura não serão carregados na plataforma do contêiner.
# .dockerignore — essential
node_modules
npm-debug.log
.git
dist
.env
# Dockerfile — install inside the image
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/dist ./dist
USER node
CMD ["node", "dist/server.js"]
Copiandopackage*.json antes do resto da fonte é uma escolha deliberada de cache de camada: as dependências só são reinstaladas quando o manifesto muda, não em cada edição da fonte.
Causa 4: Módulos nativos criados para a plataforma errada
Pacotes com componentes compilados —bcrypt, sharp, canvas, drivers de banco de dados — produzem binários específicos da plataforma.
Error: Cannot find module '.../node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node'
Recrie-os na plataforma de destino ou instale-os dentro do contêiner conforme acima.
npm rebuild bcrypt --build-from-source
# Alpine images need build tools for native compilation
RUN apk add --no-cache python3 make g++
Onde existe uma alternativa JavaScript puro —bcryptjs em vez debcrypt, por exemplo — usá-lo remove toda essa categoria de problema de implantação.
Causa 5: Extensões de arquivo ausentes no ESM
Os módulos ES exigem a extensão nas importações relativas. CommonJS não. A migração entre eles revela isso imediatamente.
// package.json has "type": "module"
import { logger } from './utils/logger'; // ❌ ERR_MODULE_NOT_FOUND
import { logger } from './utils/logger.js'; // ✅
Na compilação do TypeScript para ESM, o especificador de importação deve fazer referência aosaída arquivo, então você escreve.js mesmo que a fonte seja.ts.
import { logger } from './utils/logger.js'; // correct — refers to compiled output
Causa 6: Aliases de caminho TypeScript não resolvidos em tempo de execução
Aliases emtsconfig.json são uma conveniência em tempo de compilação. O compilador não os reescreve, portanto o JavaScript emitido ainda contém@/utils/logger, que o Node não pode resolver.
{
"compilerOptions": {
"paths": { "@/*": ["./src/*"] }
}
}
// Compiles fine, fails at runtime:
// Error: Cannot find module '@/utils/logger'
import { logger } from '@/utils/logger';
Reescreva os caminhos após a compilação ou registre um resolvedor de tempo de execução.
npm install -D tsc-alias
# package.json
"build": "tsc && tsc-alias"
O empacotamento com esbuild, tsup ou similar também resolve aliases durante a construção, e é por isso que as implantações empacotadas raramente atingem isso.
Causa 7: A saída do build não foi implantada
A .gitignore or .dockerignore entrada paradist está correto – mas a compilação deve ser executada no servidor ou no CI. Confirme o que realmente foi enviado.
# Inspect the running container
docker exec -it <container> ls -la /app/dist
docker exec -it <container> ls -la /app/node_modules | head
Diagnosticando Sistematicamente
# 1. Which exact path is Node looking for?
node dist/server.js
# Read the full error — it prints the resolved path it tried.
# 2. Does that path exist on the server?
ls -la /app/dist/utils/
# 3. Is the package installed?
ls /app/node_modules | grep package-name
npm ls package-name
# 4. Trace resolution in detail
NODE_DEBUG=module node dist/server.js 2>&1 | head -50
# 5. Confirm the Node version matches your local one
node --version
NODE_DEBUG=module imprime todas as verificações de nó de diretório, o que geralmente torna o problema óbvio em poucas linhas.
Prevenção
- Execute CI no Linux para que problemas de distinção entre maiúsculas e minúsculas falhem antes da mesclagem
- Teste com
npm ci --omit=devem CI para capturar dependências perdidas - Sempre
.dockerignoreseunode_modules - Confirme o arquivo de bloqueio e use
npm ci, nuncanpm install, em compilações - Fixe a versão principal do Node no Dockerfile e em
engines - Prefira pacotes JavaScript puro onde um módulo nativo não é necessário
Perguntas Frequentes
P: Por que funciona localmente, mas não no Docker?
R: Diferença entre maiúsculas e minúsculas no sistema de arquivos, plataforma diferente para binários nativos e um conjunto de dependências diferente se você instalar com dependências de desenvolvimento localmente. Todos os três são eliminados pela instalação dentro da imagem.
P: Devo confirmar node_modules?
R: Não. Confirme o arquivo de bloqueio e instale durante a compilação. As dependências comprometidas são interrompidas nas mudanças da plataforma e sobrecarregam gravemente o repositório.
P: npm ci ou npm install em produção?
A: npm ci. Ele instala exatamente o que o arquivo de bloqueio especifica e falha se o manifesto e o arquivo de bloqueio discordarem, que é o que você deseja em uma compilação.
P: Como encontro incompatibilidades de maiúsculas e minúsculas em uma base de código grande?
R: Crie no Linux em CI. Esse é o único método confiável — ferramentas locais em um sistema de arquivos que não diferencia maiúsculas de minúsculas não conseguem ver o problema.
P: O módulo está em node_modules, mas ainda não foi encontrado. Por que?
R: Geralmente um conflito de dependência aninhada, um link simbólico quebrado de uma configuração de espaço de trabalho ou um pacote cujoexports campo não expõe o subcaminho que você está importando. Verifique o pacoteexports mapa em seupackage.json.
Conclusão
Somente produçãoMODULE_NOT_FOUNDerros vêm de diferenças ambientais. Verifique-os em ordem:distinção entre maiúsculas e minúsculas no Linux, importações de tempo de execução em devDependencies, um node_modules construído localmente copiado na imagem, módulos nativos compilados para a plataforma errada, faltando.js extensões no ESM e aliases de caminho TypeScript não resolvidos. A correção estrutural para quase todos eles é a mesma – construir e instalar dentro do ambiente de destino, executar CI no Linux e usarnpm ci com um arquivo de bloqueio confirmado.
🔗 Share this article
✍️ Leave a Comment