Módulos: módulos CommonJS
[Estável: 2 - Estável]
Estável: 2 Estabilidade: 2 - Estável
Os módulos CommonJS são a maneira original de empacotar código JavaScript para o Node.js. O Node.js também suporta o padrão módulos ECMAScript usado por navegadores e outros ambientes de execução JavaScript.
No Node.js, cada arquivo é tratado como um módulo separado. Por exemplo, considere um arquivo chamado foo.js
:
const circle = require('./circle.js')
console.log(`A área de um círculo de raio 4 é ${circle.area(4)}`)
Na primeira linha, foo.js
carrega o módulo circle.js
que está no mesmo diretório que foo.js
.
Aqui está o conteúdo de circle.js
:
const { PI } = Math
exports.area = r => PI * r ** 2
exports.circumference = r => 2 * PI * r
O módulo circle.js
exportou as funções area()
e circumference()
. Funções e objetos são adicionados à raiz de um módulo especificando propriedades adicionais no objeto especial exports
.
Variáveis locais para o módulo serão privadas, porque o módulo é envolvido em uma função pelo Node.js (veja wrapper do módulo). Neste exemplo, a variável PI
é privada para circle.js
.
A propriedade module.exports
pode receber um novo valor (como uma função ou objeto).
No código a seguir, bar.js
faz uso do módulo square
, que exporta uma classe Square:
const Square = require('./square.js')
const mySquare = new Square(2)
console.log(`A área do meu quadrado é ${mySquare.area()}`)
O módulo square
é definido em square.js
:
// Atribuir a exports não modificará o módulo, deve-se usar module.exports
module.exports = class Square {
constructor(width) {
this.width = width
}
area() {
return this.width ** 2
}
}
O sistema de módulos CommonJS é implementado no módulo principal module
.
Habilitando
O Node.js possui dois sistemas de módulos: módulos CommonJS e módulos ECMAScript.
Por padrão, o Node.js tratará o seguinte como módulos CommonJS:
- Arquivos com extensão
.cjs
; - Arquivos com extensão
.js
quando o arquivopackage.json
pai mais próximo contém um campo de nível superior"type"
com um valor de"commonjs"
. - Arquivos com extensão
.js
ou sem extensão, quando o arquivopackage.json
pai mais próximo não contém um campo de nível superior"type"
ou não hápackage.json
em nenhuma pasta pai; a menos que o arquivo contenha uma sintaxe que apresente erros, a menos que seja avaliado como um módulo ES. Os autores do pacote devem incluir o campo"type"
, mesmo em pacotes onde todas as fontes são CommonJS. Ser explícito sobre otype
do pacote tornará as coisas mais fáceis para as ferramentas de construção e carregadores determinarem como os arquivos no pacote devem ser interpretados. - Arquivos com uma extensão que não seja
.mjs
,.cjs
,.json
,.node
ou.js
(quando o arquivopackage.json
pai mais próximo contém um campo de nível superior"type"
com um valor de"module"
, esses arquivos serão reconhecidos como módulos CommonJS apenas se forem incluídos viarequire()
, não quando usados como o ponto de entrada da linha de comando do programa).
Consulte Determinando o sistema de módulos para mais detalhes.
Chamar require()
sempre usa o carregador de módulos CommonJS. Chamar import()
sempre usa o carregador de módulos ECMAScript.
Acessando o módulo principal
Quando um arquivo é executado diretamente a partir do Node.js, require.main
é definido para seu module
. Isso significa que é possível determinar se um arquivo foi executado diretamente testando require.main === module
.
Para um arquivo foo.js
, isso será true
se executado via node foo.js
, mas false
se executado por require('./foo')
.
Quando o ponto de entrada não é um módulo CommonJS, require.main
é undefined
, e o módulo principal está fora de alcance.
Dicas para gerenciadores de pacotes
A semântica da função require()
do Node.js foi projetada para ser geral o suficiente para suportar estruturas de diretórios razoáveis. Programas gerenciadores de pacotes como dpkg
, rpm
e npm
provavelmente acharão possível construir pacotes nativos a partir de módulos do Node.js sem modificação.
A seguir, apresentamos uma estrutura de diretórios sugerida que poderia funcionar:
Digamos que quiséssemos que a pasta em /usr/lib/node/\<algum-pacote\>/\<alguma-versão\>
contivesse o conteúdo de uma versão específica de um pacote.
Pacotes podem depender uns dos outros. Para instalar o pacote foo
, pode ser necessário instalar uma versão específica do pacote bar
. O pacote bar
pode ter suas próprias dependências e, em alguns casos, elas podem até mesmo entrar em conflito ou formar dependências cíclicas.
Como o Node.js procura o realpath
de qualquer módulo que ele carrega (ou seja, ele resolve os links simbólicos) e então procura por suas dependências em pastas node_modules
, essa situação pode ser resolvida com a seguinte arquitetura:
/usr/lib/node/foo/1.2.3/
: Conteúdo do pacotefoo
, versão 1.2.3./usr/lib/node/bar/4.3.2/
: Conteúdo do pacotebar
do qualfoo
depende./usr/lib/node/foo/1.2.3/node_modules/bar
: Link simbólico para/usr/lib/node/bar/4.3.2/
./usr/lib/node/bar/4.3.2/node_modules/*
: Links simbólicos para os pacotes dos quaisbar
depende.
Assim, mesmo que um ciclo seja encontrado, ou se houver conflitos de dependência, cada módulo poderá obter uma versão de sua dependência que possa usar.
Quando o código no pacote foo
fizer require('bar')
, ele obterá a versão que está linkada simbolicamente em /usr/lib/node/foo/1.2.3/node_modules/bar
. Então, quando o código no pacote bar
chamar require('quux')
, ele obterá a versão que está linkada simbolicamente em /usr/lib/node/bar/4.3.2/node_modules/quux
.
Além disso, para tornar o processo de pesquisa de módulos ainda mais otimizado, em vez de colocar pacotes diretamente em /usr/lib/node
, poderíamos colocá-los em /usr/lib/node_modules/\<nome\>/\<versão\>
. Então, o Node.js não se preocupará em procurar por dependências ausentes em /usr/node_modules
ou /node_modules
.
Para disponibilizar módulos para o REPL do Node.js, pode ser útil também adicionar a pasta /usr/lib/node_modules
à variável de ambiente $NODE_PATH
. Como as pesquisas de módulos usando pastas node_modules
são todas relativas e baseadas no caminho real dos arquivos que fazem as chamadas para require()
, os pacotes em si podem estar em qualquer lugar.
Carregando módulos ECMAScript usando require()
[Histórico]
Versão | Mudanças |
---|---|
v23.5.0 | Este recurso não emite mais um aviso experimental por padrão, embora o aviso ainda possa ser emitido por --trace-require-module. |
v23.0.0 | Este recurso não está mais atrás da flag CLI --experimental-require-module . |
v23.0.0 | Suporte para interop de exportação 'module.exports' em require(esm) . |
v22.0.0, v20.17.0 | Adicionado em: v22.0.0, v20.17.0 |
[Estável: 1 - Experimental]
Estável: 1 Estabilidade: 1.2 - Candidato a lançamento
A extensão .mjs
é reservada para Módulos ECMAScript. Consulte a seção Determinando o sistema de módulos para obter mais informações sobre quais arquivos são analisados como módulos ECMAScript.
require()
oferece suporte apenas para carregar módulos ECMAScript que atendam aos seguintes requisitos:
- O módulo é totalmente síncrono (não contém
await
de nível superior); e - Uma destas condições é atendida:
Se o módulo ES que está sendo carregado atender aos requisitos, require()
pode carregá-lo e retornar o objeto namespace do módulo. Nesse caso, é semelhante a import()
dinâmico, mas é executado de forma síncrona e retorna o objeto namespace diretamente.
Com os seguintes Módulos ES:
// distance.mjs
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
// point.mjs
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
Um módulo CommonJS pode carregá-los com require()
:
const distance = require('./distance.mjs')
console.log(distance)
// [Module: null prototype] {
// distance: [Function: distance]
// }
const point = require('./point.mjs')
console.log(point)
// [Module: null prototype] {
// default: [class Point],
// __esModule: true,
// }
Para interoperabilidade com ferramentas existentes que convertem Módulos ES em CommonJS, que poderiam então carregar módulos ES reais por meio de require()
, o namespace retornado conteria uma propriedade __esModule: true
se tiver uma exportação default
, para que o código consumidor gerado por ferramentas possa reconhecer as exportações padrão em módulos ES reais. Se o namespace já definir __esModule
, isso não seria adicionado. Essa propriedade é experimental e pode mudar no futuro. Ela só deve ser usada por ferramentas que convertem módulos ES em módulos CommonJS, seguindo as convenções do ecossistema existentes. O código escrito diretamente em CommonJS deve evitar depender dela.
Quando um módulo ES contém exportações nomeadas e uma exportação padrão, o resultado retornado por require()
é o objeto namespace do módulo, que coloca a exportação padrão na propriedade .default
, semelhante aos resultados retornados por import()
. Para personalizar o que deve ser retornado por require(esm)
diretamente, o módulo ES pode exportar o valor desejado usando o nome de string "module.exports"
.
// point.mjs
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
}
// `distance` é perdido para consumidores CommonJS deste módulo, a menos que seja
// adicionado a `Point` como uma propriedade estática.
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export { Point as 'module.exports' }
const Point = require('./point.mjs')
console.log(Point) // [class Point]
// As exportações nomeadas são perdidas quando 'module.exports' é usado
const { distance } = require('./point.mjs')
console.log(distance) // undefined
Observe no exemplo acima, quando o nome de exportação module.exports
é usado, as exportações nomeadas serão perdidas para os consumidores CommonJS. Para permitir que os consumidores CommonJS continuem acessando as exportações nomeadas, o módulo pode garantir que a exportação padrão seja um objeto com as exportações nomeadas anexadas a ele como propriedades. Por exemplo, com o exemplo acima, distance
pode ser anexado à exportação padrão, a classe Point
, como um método estático.
export function distance(a, b) {
return (b.x - a.x) ** 2 + (b.y - a.y) ** 2
}
export default class Point {
constructor(x, y) {
this.x = x
this.y = y
}
static distance = distance
}
export { Point as 'module.exports' }
const Point = require('./point.mjs')
console.log(Point) // [class Point]
const { distance } = require('./point.mjs')
console.log(distance) // [Function: distance]
Se o módulo que está sendo require()
'd contiver await
de nível superior, ou o gráfico do módulo que ele import
contém await
de nível superior, ERR_REQUIRE_ASYNC_MODULE
será lançado. Nesse caso, os usuários devem carregar o módulo assíncrono usando import()
.
Se --experimental-print-required-tla
estiver habilitado, em vez de lançar ERR_REQUIRE_ASYNC_MODULE
antes da avaliação, o Node.js avaliará o módulo, tentará localizar os awaits de nível superior e imprimirá sua localização para ajudar os usuários a corrigi-los.
O suporte para carregar módulos ES usando require()
é atualmente experimental e pode ser desativado usando --no-experimental-require-module
. Para imprimir onde este recurso é usado, use --trace-require-module
.
Este recurso pode ser detectado verificando se process.features.require_module
é true
.
Tudo junto
Para obter o nome de arquivo exato que será carregado quando require()
é chamado, use a função require.resolve()
.
Juntando tudo o que foi dito acima, aqui está o algoritmo de alto nível em pseudocódigo do que require()
faz:
require(X) de um módulo no caminho Y
1. Se X for um módulo principal,
a. retorne o módulo principal
b. PARE
2. Se X começar com '/'
a. defina Y para ser a raiz do sistema de arquivos
3. Se X começar com './' ou '/' ou '../'
a. LOAD_AS_FILE(Y + X)
b. LOAD_AS_DIRECTORY(Y + X)
c. LANCE "não encontrado"
4. Se X começar com '#'
a. LOAD_PACKAGE_IMPORTS(X, dirname(Y))
5. LOAD_PACKAGE_SELF(X, dirname(Y))
6. LOAD_NODE_MODULES(X, dirname(Y))
7. LANCE "não encontrado"
MAYBE_DETECT_AND_LOAD(X)
1. Se X for analisado como um módulo CommonJS, carregue X como um módulo CommonJS. PARE.
2. Caso contrário, se o código-fonte de X puder ser analisado como um módulo ECMAScript usando
<a href="esm#resolver-algorithm-specification">DETECT_MODULE_SYNTAX definido no
resolutor ESM</a>,
a. Carregue X como um módulo ECMAScript. PARE.
3. LANCE o SyntaxError ao tentar analisar X como CommonJS em 1. PARE.
LOAD_AS_FILE(X)
1. Se X for um arquivo, carregue X como seu formato de extensão de arquivo. PARE
2. Se X.js for um arquivo,
a. Encontre o escopo de pacote SCOPE mais próximo de X.
b. Se nenhum escopo foi encontrado
1. MAYBE_DETECT_AND_LOAD(X.js)
c. Se o SCOPE/package.json contiver o campo "type",
1. Se o campo "type" for "module", carregue X.js como um módulo ECMAScript. PARE.
2. Se o campo "type" for "commonjs", carregue X.js como um módulo CommonJS. PARE.
d. MAYBE_DETECT_AND_LOAD(X.js)
3. Se X.json for um arquivo, carregue X.json para um objeto JavaScript. PARE
4. Se X.node for um arquivo, carregue X.node como um complemento binário. PARE
LOAD_INDEX(X)
1. Se X/index.js for um arquivo
a. Encontre o escopo de pacote SCOPE mais próximo de X.
b. Se nenhum escopo foi encontrado, carregue X/index.js como um módulo CommonJS. PARE.
c. Se o SCOPE/package.json contiver o campo "type",
1. Se o campo "type" for "module", carregue X/index.js como um módulo ECMAScript. PARE.
2. Caso contrário, carregue X/index.js como um módulo CommonJS. PARE.
2. Se X/index.json for um arquivo, analise X/index.json para um objeto JavaScript. PARE
3. Se X/index.node for um arquivo, carregue X/index.node como um complemento binário. PARE
LOAD_AS_DIRECTORY(X)
1. Se X/package.json for um arquivo,
a. Analise X/package.json e procure o campo "main".
b. Se "main" for um valor falso, GOTO 2.
c. seja M = X + (campo principal json)
d. LOAD_AS_FILE(M)
e. LOAD_INDEX(M)
f. LOAD_INDEX(X) DEPRECATED
g. LANCE "não encontrado"
2. LOAD_INDEX(X)
LOAD_NODE_MODULES(X, START)
1. seja DIRS = NODE_MODULES_PATHS(START)
2. para cada DIR em DIRS:
a. LOAD_PACKAGE_EXPORTS(X, DIR)
b. LOAD_AS_FILE(DIR/X)
c. LOAD_AS_DIRECTORY(DIR/X)
NODE_MODULES_PATHS(START)
1. seja PARTS = path split(START)
2. seja I = contagem de PARTS - 1
3. seja DIRS = []
4. enquanto I >= 0,
a. se PARTS[I] = "node_modules", GOTO d.
b. DIR = path join(PARTS[0 .. I] + "node_modules")
c. DIRS = DIR + DIRS
d. seja I = I - 1
5. retorne DIRS + GLOBAL_FOLDERS
LOAD_PACKAGE_IMPORTS(X, DIR)
1. Encontre o escopo de pacote SCOPE mais próximo de DIR.
2. Se nenhum escopo foi encontrado, retorne.
3. Se o "imports" de SCOPE/package.json for nulo ou indefinido, retorne.
4. Se `--experimental-require-module` estiver habilitado
a. seja CONDITIONS = ["node", "require", "module-sync"]
b. Caso contrário, seja CONDITIONS = ["node", "require"]
5. seja MATCH = PACKAGE_IMPORTS_RESOLVE(X, pathToFileURL(SCOPE),
CONDITIONS) <a href="esm#resolver-algorithm-specification">definido no resolvedor ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH).
LOAD_PACKAGE_EXPORTS(X, DIR)
1. Tente interpretar X como uma combinação de NAME e SUBPATH onde o nome
pode ter um prefixo @scope/ e o subpath começa com uma barra (`/`).
2. Se X não corresponder a este padrão ou DIR/NAME/package.json não for um arquivo,
retorne.
3. Analise DIR/NAME/package.json e procure o campo "exports".
4. Se "exports" for nulo ou indefinido, retorne.
5. Se `--experimental-require-module` estiver habilitado
a. seja CONDITIONS = ["node", "require", "module-sync"]
b. Caso contrário, seja CONDITIONS = ["node", "require"]
6. seja MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH,
`package.json` "exports", CONDITIONS) <a href="esm#resolver-algorithm-specification">definido no resolvedor ESM</a>.
7. RESOLVE_ESM_MATCH(MATCH)
LOAD_PACKAGE_SELF(X, DIR)
1. Encontre o escopo de pacote SCOPE mais próximo de DIR.
2. Se nenhum escopo foi encontrado, retorne.
3. Se "exports" de SCOPE/package.json for nulo ou indefinido, retorne.
4. Se "name" de SCOPE/package.json não for o primeiro segmento de X, retorne.
5. seja MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(SCOPE),
"." + X.slice("name".length), `package.json` "exports", ["node", "require"])
<a href="esm#resolver-algorithm-specification">definido no resolvedor ESM</a>.
6. RESOLVE_ESM_MATCH(MATCH)
RESOLVE_ESM_MATCH(MATCH)
1. seja RESOLVED_PATH = fileURLToPath(MATCH)
2. Se o arquivo em RESOLVED_PATH existir, carregue RESOLVED_PATH como seu formato de extensão
. PARE
3. LANCE "não encontrado"
Cache
Os módulos são armazenados em cache após serem carregados pela primeira vez. Isso significa (entre outras coisas) que cada chamada para require('foo')
retornará exatamente o mesmo objeto, caso resolva para o mesmo arquivo.
Desde que require.cache
não seja modificado, várias chamadas para require('foo')
não farão com que o código do módulo seja executado várias vezes. Esta é uma característica importante. Com ela, objetos "parcialmente feitos" podem ser retornados, permitindo assim que dependências transitivas sejam carregadas, mesmo quando causariam ciclos.
Para que um módulo execute o código várias vezes, exporte uma função e chame essa função.
Advertências de cache de módulo
Os módulos são armazenados em cache com base em seu nome de arquivo resolvido. Como os módulos podem ser resolvidos para um nome de arquivo diferente com base na localização do módulo de chamada (carregando das pastas node_modules
), não é uma garantia que require('foo')
sempre retornará exatamente o mesmo objeto, caso seja resolvido para arquivos diferentes.
Além disso, em sistemas de arquivos ou sistemas operacionais que não diferenciam maiúsculas de minúsculas, diferentes nomes de arquivo resolvidos podem apontar para o mesmo arquivo, mas o cache ainda os tratará como módulos diferentes e recarregará o arquivo várias vezes. Por exemplo, require('./foo')
e require('./FOO')
retornam dois objetos diferentes, independentemente de ./foo
e ./FOO
serem ou não o mesmo arquivo.
Módulos internos
[Histórico]
Versão | Alterações |
---|---|
v16.0.0, v14.18.0 | Adicionado suporte para importação node: para require(...) . |
O Node.js possui vários módulos compilados no binário. Esses módulos são descritos com mais detalhes em outras partes desta documentação.
Os módulos internos são definidos dentro do código-fonte do Node.js e estão localizados na pasta lib/
.
Os módulos internos podem ser identificados usando o prefixo node:
, caso em que ele ignora o cache require
. Por exemplo, require('node:http')
sempre retornará o módulo HTTP interno, mesmo que haja uma entrada require.cache
com esse nome.
Alguns módulos internos são sempre carregados preferencialmente se seu identificador for passado para require()
. Por exemplo, require('http')
sempre retornará o módulo HTTP interno, mesmo que haja um arquivo com esse nome. A lista de módulos internos que podem ser carregados sem usar o prefixo node:
é exposta em module.builtinModules
, listada sem o prefixo.
Módulos integrados com prefixo node:
obrigatório
Ao serem carregados por require()
, alguns módulos integrados devem ser solicitados com o prefixo node:
. Esse requisito existe para evitar que módulos integrados recém-introduzidos entrem em conflito com pacotes do usuário que já adotaram o nome. Atualmente, os módulos integrados que exigem o prefixo node:
são:
A lista desses módulos é exposta em module.builtinModules
, incluindo o prefixo.
Ciclos
Quando há chamadas circulares de require()
, um módulo pode não ter terminado de ser executado quando é retornado.
Considere esta situação:
a.js
:
console.log('a starting')
exports.done = false
const b = require('./b.js')
console.log('in a, b.done = %j', b.done)
exports.done = true
console.log('a done')
b.js
:
console.log('b starting')
exports.done = false
const a = require('./a.js')
console.log('in b, a.done = %j', a.done)
exports.done = true
console.log('b done')
main.js
:
console.log('main starting')
const a = require('./a.js')
const b = require('./b.js')
console.log('in main, a.done = %j, b.done = %j', a.done, b.done)
Quando main.js
carrega a.js
, então a.js
por sua vez carrega b.js
. Nesse ponto, b.js
tenta carregar a.js
. Para evitar um loop infinito, uma cópia inacabada do objeto de exports de a.js
é retornada para o módulo b.js
. b.js
então termina de carregar, e seu objeto exports
é fornecido ao módulo a.js
.
Quando main.js
carrega ambos os módulos, eles já terminaram. A saída deste programa seria, portanto:
$ node main.js
main starting
a starting
b starting
in b, a.done = false
b done
in a, b.done = true
a done
in main, a.done = true, b.done = true
É necessário um planejamento cuidadoso para permitir que dependências de módulos cíclicos funcionem corretamente dentro de um aplicativo.
Módulos de Arquivo
Se o nome exato do arquivo não for encontrado, o Node.js tentará carregar o nome do arquivo solicitado com as extensões adicionadas: .js
, .json
e, finalmente, .node
. Ao carregar um arquivo que tenha uma extensão diferente (por exemplo, .cjs
), seu nome completo deve ser passado para require()
, incluindo sua extensão de arquivo (por exemplo, require('./file.cjs')
).
Arquivos .json
são analisados como arquivos de texto JSON, arquivos .node
são interpretados como módulos complementares compilados carregados com process.dlopen()
. Arquivos que usam qualquer outra extensão (ou nenhuma extensão) são analisados como arquivos de texto JavaScript. Consulte a seção Determinação do sistema de módulos para entender qual objetivo de análise será usado.
Um módulo solicitado com o prefixo '/'
é um caminho absoluto para o arquivo. Por exemplo, require('/home/marco/foo.js')
carregará o arquivo em /home/marco/foo.js
.
Um módulo solicitado com o prefixo './'
é relativo ao arquivo que chama require()
. Ou seja, circle.js
deve estar no mesmo diretório de foo.js
para que require('./circle')
o encontre.
Sem um '/'
, './'
ou '../'
inicial para indicar um arquivo, o módulo deve ser um módulo principal ou ser carregado de uma pasta node_modules
.
Se o caminho fornecido não existir, require()
lançará um erro MODULE_NOT_FOUND
.
Pastas como módulos
[Estável: 3 - Legado]
Estável: 3 Estabilidade: 3 - Legado: Use exportações de subcaminho ou importações de subcaminho em vez disso.
Existem três maneiras pelas quais uma pasta pode ser passada para require()
como um argumento.
A primeira é criar um arquivo package.json
na raiz da pasta, que especifica um módulo main
. Um exemplo de arquivo package.json
pode ser assim:
{ "name": "some-library", "main": "./lib/some-library.js" }
Se isso estivesse em uma pasta em ./some-library
, então require('./some-library')
tentaria carregar ./some-library/lib/some-library.js
.
Se não houver um arquivo package.json
presente no diretório, ou se a entrada "main"
estiver faltando ou não puder ser resolvida, o Node.js tentará carregar um arquivo index.js
ou index.node
desse diretório. Por exemplo, se não houvesse um arquivo package.json
no exemplo anterior, então require('./some-library')
tentaria carregar:
./some-library/index.js
./some-library/index.node
Se essas tentativas falharem, o Node.js relatará todo o módulo como ausente com o erro padrão:
Erro: Não é possível encontrar o módulo 'some-library'
Em todos os três casos acima, uma chamada import('./some-library')
resultaria em um erro ERR_UNSUPPORTED_DIR_IMPORT
. O uso de exportações de subcaminho ou importações de subcaminho de pacotes pode fornecer os mesmos benefícios de organização de contenção que pastas como módulos e funcionar para require
e import
.
Carregando de pastas node_modules
Se o identificador do módulo passado para require()
não for um módulo embutido e não começar com '/'
, '../'
ou './'
, então o Node.js começa no diretório do módulo atual, adiciona /node_modules
e tenta carregar o módulo desse local. O Node.js não anexará node_modules
a um caminho que já termine em node_modules
.
Se não for encontrado lá, ele se move para o diretório pai e assim por diante, até que a raiz do sistema de arquivos seja alcançada.
Por exemplo, se o arquivo em '/home/ry/projects/foo.js'
chamar require('bar.js')
, então o Node.js procuraria nos seguintes locais, nesta ordem:
/home/ry/projects/node_modules/bar.js
/home/ry/node_modules/bar.js
/home/node_modules/bar.js
/node_modules/bar.js
Isso permite que os programas localizem suas dependências, para que não entrem em conflito.
É possível exigir arquivos específicos ou submódulos distribuídos com um módulo, incluindo um sufixo de caminho após o nome do módulo. Por exemplo, require('example-module/path/to/file')
resolveria path/to/file
em relação a onde example-module
está localizado. O caminho sufixado segue a mesma semântica de resolução de módulo.
Carregando das pastas globais
Se a variável de ambiente NODE_PATH
for definida como uma lista de caminhos absolutos delimitados por dois pontos, o Node.js pesquisará esses caminhos por módulos se eles não forem encontrados em outros lugares.
No Windows, NODE_PATH
é delimitado por ponto e vírgula (;
) em vez de dois pontos.
NODE_PATH
foi originalmente criado para oferecer suporte ao carregamento de módulos de caminhos variáveis antes que o algoritmo atual de resolução de módulos fosse definido.
NODE_PATH
ainda é suportado, mas é menos necessário agora que o ecossistema do Node.js estabeleceu uma convenção para localizar módulos dependentes. Às vezes, as implantações que dependem de NODE_PATH
apresentam um comportamento surpreendente quando as pessoas não estão cientes de que NODE_PATH
deve ser definido. Às vezes, as dependências de um módulo mudam, fazendo com que uma versão diferente (ou mesmo um módulo diferente) seja carregada enquanto NODE_PATH
é pesquisado.
Além disso, o Node.js pesquisará na seguinte lista de GLOBAL_FOLDERS:
- 1:
$HOME/.node_modules
- 2:
$HOME/.node_libraries
- 3:
$PREFIX/lib/node
Onde $HOME
é o diretório inicial do usuário e $PREFIX
é o node_prefix
configurado do Node.js.
Estes são principalmente por razões históricas.
É altamente recomendável colocar as dependências na pasta local node_modules
. Elas serão carregadas mais rapidamente e de forma mais confiável.
O invólucro do módulo
Antes que o código de um módulo seja executado, o Node.js o envolverá com um invólucro de função que se parece com o seguinte:
;(function (exports, require, module, __filename, __dirname) {
// O código do módulo realmente vive aqui
})
Ao fazer isso, o Node.js alcança algumas coisas:
- Mantém as variáveis de nível superior (definidas com
var
,const
oulet
) com escopo para o módulo, em vez do objeto global. - Ajuda a fornecer algumas variáveis com aparência global que são realmente específicas do módulo, como:
- Os objetos
module
eexports
que o implementador pode usar para exportar valores do módulo. - As variáveis de conveniência
__filename
e__dirname
, contendo o nome de arquivo absoluto do módulo e o caminho do diretório.
- Os objetos
O escopo do módulo
__dirname
Adicionado em: v0.1.27
O nome do diretório do módulo atual. Isso é o mesmo que o path.dirname()
de __filename
.
Exemplo: executando node example.js
de /Users/mjr
console.log(__dirname)
// Imprime: /Users/mjr
console.log(path.dirname(__filename))
// Imprime: /Users/mjr
__filename
Adicionado em: v0.0.1
O nome do arquivo do módulo atual. Este é o caminho absoluto do arquivo do módulo atual com links simbólicos resolvidos.
Para um programa principal, isso não é necessariamente o mesmo que o nome de arquivo usado na linha de comando.
Consulte __dirname
para o nome do diretório do módulo atual.
Exemplos:
Executando node example.js
de /Users/mjr
console.log(__filename)
// Imprime: /Users/mjr/example.js
console.log(__dirname)
// Imprime: /Users/mjr
Dados dois módulos: a
e b
, onde b
é uma dependência de a
e há uma estrutura de diretório de:
/Users/mjr/app/a.js
/Users/mjr/app/node_modules/b/b.js
Referências a __filename
dentro de b.js
retornarão /Users/mjr/app/node_modules/b/b.js
enquanto referências a __filename
dentro de a.js
retornarão /Users/mjr/app/a.js
.
exports
Adicionado em: v0.1.12
Uma referência a module.exports
que é mais curta para digitar. Consulte a seção sobre o atalho exports para obter detalhes sobre quando usar exports
e quando usar module.exports
.
module
Adicionado em: v0.1.16
Uma referência ao módulo atual, consulte a seção sobre o objeto module
. Em particular, module.exports
é usado para definir o que um módulo exporta e disponibiliza por meio de require()
.
require(id)
Adicionado em: v0.1.13
Usado para importar módulos, JSON
e arquivos locais. Os módulos podem ser importados de node_modules
. Módulos locais e arquivos JSON podem ser importados usando um caminho relativo (por exemplo, ./
, ./foo
, ./bar/baz
, ../foo
) que será resolvido em relação ao diretório nomeado por __dirname
(se definido) ou o diretório de trabalho atual. Os caminhos relativos do estilo POSIX são resolvidos de forma independente do sistema operacional, o que significa que os exemplos acima funcionarão no Windows da mesma forma que funcionariam em sistemas Unix.
// Importando um módulo local com um caminho relativo ao `__dirname` ou ao diretório de
// trabalho atual. (No Windows, isso seria resolvido para .\path\myLocalModule.)
const myLocalModule = require('./path/myLocalModule')
// Importando um arquivo JSON:
const jsonData = require('./path/filename.json')
// Importando um módulo de node_modules ou um módulo integrado do Node.js:
const crypto = require('node:crypto')
require.cache
Adicionado em: v0.3.0
Os módulos são armazenados em cache neste objeto quando são exigidos. Ao excluir um valor-chave deste objeto, o próximo require
recarregará o módulo. Isso não se aplica a addons nativos, para os quais a recarga resultará em um erro.
Adicionar ou substituir entradas também é possível. Este cache é verificado antes dos módulos integrados e, se um nome correspondente a um módulo integrado for adicionado ao cache, apenas as chamadas require com o prefixo node:
receberão o módulo integrado. Use com cuidado!
const assert = require('node:assert')
const realFs = require('node:fs')
const fakeFs = {}
require.cache.fs = { exports: fakeFs }
assert.strictEqual(require('fs'), fakeFs)
assert.strictEqual(require('node:fs'), realFs)
require.extensions
Adicionado em: v0.3.0
Obsoleto desde: v0.10.6
[Estável: 0 - Obsoleto]
Estável: 0 Estabilidade: 0 - Obsoleto
Instrua o require
sobre como lidar com certas extensões de arquivo.
Processar arquivos com a extensão .sjs
como .js
:
require.extensions['.sjs'] = require.extensions['.js']
Obsoleto. No passado, esta lista era usada para carregar módulos não JavaScript no Node.js, compilando-os sob demanda. No entanto, na prática, existem maneiras muito melhores de fazer isso, como carregar módulos por meio de algum outro programa Node.js ou compilá-los para JavaScript antecipadamente.
Evite usar require.extensions
. O uso pode causar bugs sutis e a resolução das extensões fica mais lenta a cada extensão registrada.
require.main
Adicionado em: v0.1.17
O objeto Module
representando o script de entrada carregado quando o processo Node.js foi iniciado, ou undefined
se o ponto de entrada do programa não for um módulo CommonJS. Consulte "Acessando o módulo principal".
No script entry.js
:
console.log(require.main)
node entry.js
Module {
id: '.',
path: '/absolute/path/to',
exports: {},
filename: '/absolute/path/to/entry.js',
loaded: false,
children: [],
paths:
[ '/absolute/path/to/node_modules',
'/absolute/path/node_modules',
'/absolute/node_modules',
'/node_modules' ] }
require.resolve(request[, options])
[Histórico]
Versão | Mudanças |
---|---|
v8.9.0 | A opção paths agora é suportada. |
v0.3.0 | Adicionado em: v0.3.0 |
request
<string> O caminho do módulo a ser resolvido.options
<Object>paths
<string[]> Caminhos para resolver a localização do módulo. Se presente, esses caminhos são usados em vez dos caminhos de resolução padrão, com exceção de GLOBAL_FOLDERS como$HOME/.node_modules
, que são sempre incluídos. Cada um desses caminhos é usado como ponto de partida para o algoritmo de resolução de módulos, o que significa que a hierarquianode_modules
é verificada a partir deste local.
Retorna: <string>
Use o mecanismo interno require()
para procurar a localização de um módulo, mas em vez de carregar o módulo, apenas retorne o nome de arquivo resolvido.
Se o módulo não puder ser encontrado, um erro MODULE_NOT_FOUND
será lançado.
require.resolve.paths(request)
Adicionado em: v8.9.0
request
<string> O caminho do módulo cujos caminhos de pesquisa estão sendo recuperados.- Retorna: <string[]> | <null>
Retorna um array contendo os caminhos pesquisados durante a resolução de request
ou null
se a string request
referenciar um módulo principal, por exemplo, http
ou fs
.
O objeto module
Adicionado em: v0.1.16
Em cada módulo, a variável livre module
é uma referência ao objeto que representa o módulo atual. Por conveniência, module.exports
também é acessível através do módulo global exports
. module
não é realmente global, mas sim local para cada módulo.
module.children
Adicionado em: v0.1.16
Os objetos de módulo requeridos pela primeira vez por este.
module.exports
Adicionado em: v0.1.16
O objeto module.exports
é criado pelo sistema Module
. Às vezes, isso não é aceitável; muitos querem que seu módulo seja uma instância de alguma classe. Para fazer isso, atribua o objeto de exportação desejado a module.exports
. Atribuir o objeto desejado a exports
simplesmente reassociará a variável local exports
, o que provavelmente não é o desejado.
Por exemplo, suponha que estivéssemos criando um módulo chamado a.js
:
const EventEmitter = require('node:events')
module.exports = new EventEmitter()
// Faça algum trabalho e, após algum tempo, emita
// o evento 'ready' do próprio módulo.
setTimeout(() => {
module.exports.emit('ready')
}, 1000)
Então, em outro arquivo, poderíamos fazer:
const a = require('./a')
a.on('ready', () => {
console.log('módulo "a" está pronto')
})
A atribuição a module.exports
deve ser feita imediatamente. Não pode ser feita em nenhum callback. Isso não funciona:
x.js
:
setTimeout(() => {
module.exports = { a: 'hello' }
}, 0)
y.js
:
const x = require('./x')
console.log(x.a)
Atalho exports
Adicionado em: v0.1.16
A variável exports
está disponível no escopo de nível de arquivo de um módulo, e recebe o valor de module.exports
antes que o módulo seja avaliado.
Isso permite um atalho, de modo que module.exports.f = ...
possa ser escrito de forma mais concisa como exports.f = ...
. No entanto, esteja ciente de que, como qualquer variável, se um novo valor for atribuído a exports
, ele não estará mais vinculado a module.exports
:
module.exports.hello = true // Exportado do require do módulo
exports = { hello: false } // Não exportado, disponível apenas no módulo
Quando a propriedade module.exports
está sendo completamente substituída por um novo objeto, é comum também reatribuir exports
:
module.exports = exports = function Constructor() {
// ... etc.
}
Para ilustrar o comportamento, imagine esta implementação hipotética de require()
, que é bastante semelhante ao que é realmente feito por require()
:
function require(/* ... */) {
const module = { exports: {} }
;((module, exports) => {
// Código do módulo aqui. Neste exemplo, define uma função.
function someFunc() {}
exports = someFunc
// Neste ponto, exports não é mais um atalho para module.exports, e
// este módulo ainda exportará um objeto padrão vazio.
module.exports = someFunc
// Neste ponto, o módulo agora exportará someFunc, em vez do
// objeto padrão.
})(module, module.exports)
return module.exports
}
module.filename
Adicionado em: v0.1.16
O nome de arquivo totalmente resolvido do módulo.
module.id
Adicionado em: v0.1.16
O identificador do módulo. Normalmente, este é o nome de arquivo totalmente resolvido.
module.isPreloading
Adicionado em: v15.4.0, v14.17.0
- Tipo: <boolean>
true
se o módulo estiver sendo executado durante a fase de pré-carregamento do Node.js.
module.loaded
Adicionado em: v0.1.16
Indica se o módulo já terminou de carregar ou está em processo de carregamento.
module.parent
Adicionado em: v0.1.16
Obsoleto desde: v14.6.0, v12.19.0
[Estável: 0 - Obsoleto]
Estável: 0 Estabilidade: 0 - Obsoleto: Por favor, use require.main
e module.children
em vez disso.
O módulo que primeiro requisitou este, ou null
se o módulo atual for o ponto de entrada do processo atual, ou undefined
se o módulo foi carregado por algo que não é um módulo CommonJS (Ex: REPL ou import
).
module.path
Adicionado em: v11.14.0
O nome do diretório do módulo. Geralmente é o mesmo que o path.dirname()
do module.id
.
module.paths
Adicionado em: v0.4.0
Os caminhos de pesquisa para o módulo.
module.require(id)
Adicionado em: v0.5.1
O método module.require()
fornece uma maneira de carregar um módulo como se require()
fosse chamado a partir do módulo original.
Para fazer isso, é necessário obter uma referência ao objeto module
. Como require()
retorna module.exports
, e module
normalmente só está disponível dentro do código de um módulo específico, ele deve ser explicitamente exportado para ser usado.
O objeto Module
Esta seção foi movida para Módulos: módulo principal module
.
Suporte para mapa de origem v3
Esta seção foi movida para Módulos: módulo principal module
.