Skip to content

Módulos: Pacotes

[Histórico]

VersãoMudanças
v14.13.0, v12.20.0Adiciona suporte para padrões de "exports".
v14.6.0, v12.19.0Adiciona o campo "imports" do pacote.
v13.7.0, v12.17.0Remove a flag de exports condicionais.
v13.7.0, v12.16.0Remove a opção --experimental-conditional-exports. Na versão 12.16.0, os exports condicionais ainda estão atrás de --experimental-modules.
v13.6.0, v12.16.0Remove a flag de auto-referência a um pacote usando seu nome.
v12.7.0Introduz o campo "exports" em package.json como uma alternativa mais poderosa ao campo clássico "main".
v12.0.0Adiciona suporte para módulos ES usando a extensão de arquivo .js através do campo "type" em package.json.

Introdução

Um pacote é uma árvore de pastas descrita por um arquivo package.json. O pacote consiste na pasta que contém o arquivo package.json e todas as subpastas até a próxima pasta que contém outro arquivo package.json, ou uma pasta chamada node_modules.

Esta página fornece orientação para autores de pacotes que escrevem arquivos package.json, juntamente com uma referência para os campos package.json definidos pelo Node.js.

Determinando o sistema de módulos

Introdução

O Node.js tratará o seguinte como módulos ES quando passados para node como entrada inicial, ou quando referenciados por instruções import ou expressões import():

  • Arquivos com extensão .mjs.
  • Arquivos com extensão .js quando o arquivo package.json pai mais próximo contém um campo de nível superior "type" com o valor "module".
  • Strings passadas como argumento para --eval, ou enviadas para node via STDIN, com a flag --input-type=module.
  • Código que contém sintaxe que só é analisada com sucesso como módulos ES, como instruções import ou export ou import.meta, sem um marcador explícito de como deve ser interpretado. Marcadores explícitos são extensões .mjs ou .cjs, campos "type" em package.json com valores "module" ou "commonjs", ou a flag --input-type. Expressões dinâmicas import() são suportadas em módulos CommonJS ou ES e não forçariam um arquivo a ser tratado como um módulo ES. Veja Detecção de Sintaxe.

O Node.js tratará o seguinte como CommonJS quando passados para node como entrada inicial, ou quando referenciados por instruções import ou expressões import():

  • Arquivos com extensão .cjs.
  • Arquivos com extensão .js quando o arquivo package.json pai mais próximo contém um campo de nível superior "type" com o valor "commonjs".
  • Strings passadas como argumento para --eval ou --print, ou enviadas para node via STDIN, com a flag --input-type=commonjs.
  • Arquivos com extensão .js sem arquivo package.json pai ou onde o arquivo package.json pai mais próximo não tem um campo type, e onde o código pode ser avaliado com sucesso como CommonJS. Em outras palavras, o Node.js tenta executar tais arquivos "ambíguos" como CommonJS primeiro e tentará avaliá-los novamente como módulos ES se a avaliação como CommonJS falhar porque o analisador encontrou sintaxe de módulo ES.

Escrever sintaxe de módulo ES em arquivos "ambíguos" acarreta um custo de desempenho e, portanto, é recomendado que os autores sejam explícitos sempre que possível. Em particular, os autores de pacotes devem sempre incluir o campo "type" em seus arquivos package.json, mesmo em pacotes onde todas as fontes são CommonJS. Ser explícito sobre o type do pacote irá preparar o pacote para o futuro, caso o tipo padrão do Node.js alguma vez mude, e também tornará mais fácil para ferramentas de construção e carregadores determinar como os arquivos no pacote devem ser interpretados.

Detecção de Sintaxe

[Histórico]

VersãoMudanças
v22.7.0A detecção de sintaxe é habilitada por padrão.
v21.1.0, v20.10.0Adicionado em: v21.1.0, v20.10.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1.2 - Candidato a lançamento

O Node.js inspecionará o código-fonte de entradas ambíguas para determinar se ele contém sintaxe de módulo ES; se tal sintaxe for detectada, a entrada será tratada como um módulo ES.

Entrada ambígua é definida como:

  • Arquivos com extensão .js ou sem extensão; e sem um arquivo package.json de controle ou um que não tenha um campo type.
  • Entrada de string (--eval ou STDIN) quando --input-type não é especificado.

A sintaxe do módulo ES é definida como a sintaxe que lançaria um erro quando avaliada como CommonJS. Isso inclui o seguinte:

  • Declarações import (mas não expressões import(), que são válidas em CommonJS).
  • Declarações export.
  • Referências import.meta.
  • await no nível superior de um módulo.
  • Redeclarações léxicas das variáveis do wrapper CommonJS (require, module, exports, __dirname, __filename).

Carregadores de Módulos

O Node.js possui dois sistemas para resolver um especificador e carregar módulos.

Existe o carregador de módulos CommonJS:

  • É totalmente síncrono.
  • É responsável por lidar com chamadas require().
  • Pode ser modificado por monkey patch.
  • Suporta pastas como módulos.
  • Ao resolver um especificador, se nenhuma correspondência exata for encontrada, ele tentará adicionar extensões (.js, .json e, finalmente, .node) e, em seguida, tentará resolver pastas como módulos.
  • Trata .json como arquivos de texto JSON.
  • Arquivos .node são interpretados como módulos de addon compilados carregados com process.dlopen().
  • Trata todos os arquivos que não possuem extensões .json ou .node como arquivos de texto JavaScript.
  • Ele só pode ser usado para carregar módulos ECMAScript de módulos CommonJS se o grafo do módulo for síncrono (que não contém await de nível superior). Quando usado para carregar um arquivo de texto JavaScript que não é um módulo ECMAScript, o arquivo será carregado como um módulo CommonJS.

Existe o carregador de módulos ECMAScript:

  • É assíncrono, a menos que esteja sendo usado para carregar módulos para require().
  • É responsável por lidar com declarações import e expressões import().
  • Não pode ser modificado por monkey patch, pode ser personalizado usando ganchos de carregador.
  • Não suporta pastas como módulos, os índices de diretório (por exemplo, './startup/index.js') devem ser totalmente especificados.
  • Não faz pesquisa de extensão. Uma extensão de arquivo deve ser fornecida quando o especificador é um URL de arquivo relativo ou absoluto.
  • Pode carregar módulos JSON, mas um atributo de tipo import é necessário.
  • Aceita apenas extensões .js, .mjs e .cjs para arquivos de texto JavaScript.
  • Pode ser usado para carregar módulos JavaScript CommonJS. Esses módulos são passados através do cjs-module-lexer para tentar identificar exports nomeados, que estão disponíveis se puderem ser determinados por meio de análise estática. Os módulos CommonJS importados têm seus URLs convertidos em caminhos absolutos e são carregados por meio do carregador de módulos CommonJS.

package.json e extensões de arquivo

Dentro de um pacote, o campo "type" do package.json define como o Node.js deve interpretar arquivos .js. Se um arquivo package.json não tiver um campo "type", os arquivos .js são tratados como CommonJS.

Um valor "type" de "module" em package.json diz ao Node.js para interpretar os arquivos .js dentro desse pacote como usando a sintaxe de módulo ES.

O campo "type" se aplica não apenas aos pontos de entrada iniciais (node my-app.js), mas também aos arquivos referenciados por declarações import e expressões import().

js
// my-app.js, tratado como um módulo ES porque existe um arquivo package.json
// na mesma pasta com "type": "module".

import './startup/init.js'
// Carregado como módulo ES, já que ./startup não contém nenhum arquivo package.json,
// e, portanto, herda o valor "type" de um nível acima.

import 'commonjs-package'
// Carregado como CommonJS, já que ./node_modules/commonjs-package/package.json
// não tem um campo "type" ou contém "type": "commonjs".

import './node_modules/commonjs-package/index.js'
// Carregado como CommonJS, já que ./node_modules/commonjs-package/package.json
// não tem um campo "type" ou contém "type": "commonjs".

Arquivos que terminam com .mjs são sempre carregados como módulos ES, independentemente do package.json pai mais próximo.

Arquivos que terminam com .cjs são sempre carregados como CommonJS, independentemente do package.json pai mais próximo.

js
import './legacy-file.cjs'
// Carregado como CommonJS, já que .cjs é sempre carregado como CommonJS.

import 'commonjs-package/src/index.mjs'
// Carregado como módulo ES, já que .mjs é sempre carregado como módulo ES.

As extensões .mjs e .cjs podem ser usadas para misturar tipos dentro do mesmo pacote:

  • Dentro de um pacote "type": "module", o Node.js pode ser instruído a interpretar um arquivo específico como CommonJS nomeando-o com a extensão .cjs (já que os arquivos .js e .mjs são tratados como módulos ES dentro de um pacote "module").
  • Dentro de um pacote "type": "commonjs", o Node.js pode ser instruído a interpretar um arquivo específico como um módulo ES nomeando-o com a extensão .mjs (já que os arquivos .js e .cjs são tratados como CommonJS dentro de um pacote "commonjs").

Flag --input-type

Adicionado em: v12.0.0

Strings passadas como argumento para --eval (ou -e), ou enviadas para node via STDIN, são tratadas como módulos ES quando a flag --input-type=module é definida.

bash
node --input-type=module --eval "import { sep } from 'node:path'; console.log(sep);"

echo "import { sep } from 'node:path'; console.log(sep);" | node --input-type=module

Para completude, também existe --input-type=commonjs, para executar explicitamente a entrada de string como CommonJS. Este é o comportamento padrão se --input-type não for especificado.

Determinando o gerenciador de pacotes

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

Embora todos os projetos Node.js devam ser instaláveis por todos os gerenciadores de pacotes uma vez publicados, suas equipes de desenvolvimento muitas vezes são obrigadas a usar um gerenciador de pacotes específico. Para facilitar esse processo, o Node.js é fornecido com uma ferramenta chamada Corepack que visa tornar todos os gerenciadores de pacotes transparentemente disponíveis em seu ambiente - desde que você tenha o Node.js instalado.

Por padrão, o Corepack não aplicará nenhum gerenciador de pacotes específico e usará as versões genéricas "Last Known Good" associadas a cada lançamento do Node.js, mas você pode melhorar essa experiência definindo o campo "packageManager" no package.json do seu projeto.

Pontos de entrada do pacote

No arquivo package.json de um pacote, dois campos podem definir os pontos de entrada para um pacote: "main" e "exports". Ambos os campos se aplicam tanto a pontos de entrada de módulos ES quanto a módulos CommonJS.

O campo "main" é suportado em todas as versões do Node.js, mas suas capacidades são limitadas: ele apenas define o ponto de entrada principal do pacote.

O campo "exports" fornece uma alternativa moderna para "main", permitindo que múltiplos pontos de entrada sejam definidos, suporte a resolução de entrada condicional entre ambientes e impedindo quaisquer outros pontos de entrada além daqueles definidos em "exports". Esse encapsulamento permite que os autores de módulos definam claramente a interface pública de seu pacote.

Para novos pacotes destinados às versões atualmente suportadas do Node.js, o campo "exports" é recomendado. Para pacotes que suportam Node.js 10 e inferiores, o campo "main" é obrigatório. Se ambos "exports" e "main" forem definidos, o campo "exports" tem precedência sobre "main" em versões suportadas do Node.js.

Exports condicionais podem ser usados dentro de "exports" para definir diferentes pontos de entrada de pacotes por ambiente, incluindo se o pacote é referenciado via require ou via import. Para obter mais informações sobre o suporte a módulos CommonJS e ES em um único pacote, consulte a seção de pacotes duplos CommonJS/ES.

Pacotes existentes que introduzem o campo "exports" impedirão que os consumidores do pacote usem quaisquer pontos de entrada que não estejam definidos, incluindo o package.json (por exemplo, require('seu-pacote/package.json')). Isso provavelmente será uma mudança interruptiva.

Para tornar a introdução de "exports" não interruptiva, certifique-se de que todos os pontos de entrada suportados anteriormente sejam exportados. É melhor especificar explicitamente os pontos de entrada para que a API pública do pacote seja bem definida. Por exemplo, um projeto que anteriormente exportava main, lib, feature e o package.json poderia usar o seguinte package.exports:

json
{
  "name": "meu-pacote",
  "exports": {
    ".": "./lib/index.js",
    "./lib": "./lib/index.js",
    "./lib/index": "./lib/index.js",
    "./lib/index.js": "./lib/index.js",
    "./feature": "./feature/index.js",
    "./feature/index": "./feature/index.js",
    "./feature/index.js": "./feature/index.js",
    "./package.json": "./package.json"
  }
}

Alternativamente, um projeto pode optar por exportar pastas inteiras com e sem subcaminhos estendidos usando padrões de exportação:

json
{
  "name": "meu-pacote",
  "exports": {
    ".": "./lib/index.js",
    "./lib": "./lib/index.js",
    "./lib/*": "./lib/*.js",
    "./lib/*.js": "./lib/*.js",
    "./feature": "./feature/index.js",
    "./feature/*": "./feature/*.js",
    "./feature/*.js": "./feature/*.js",
    "./package.json": "./package.json"
  }
}

Com o acima, fornecendo retrocompatibilidade para quaisquer versões menores de pacotes, uma futura mudança principal para o pacote pode então restringir adequadamente as exportações apenas às exportações de recursos específicos expostas:

json
{
  "name": "meu-pacote",
  "exports": {
    ".": "./lib/index.js",
    "./feature/*.js": "./feature/*.js",
    "./feature/internal/*": null
  }
}

Ponto de entrada principal exportado

Ao escrever um novo pacote, é recomendável usar o campo "exports":

json
{
  "exports": "./index.js"
}

Quando o campo "exports" é definido, todos os subcaminhos do pacote são encapsulados e não ficam mais disponíveis para os importadores. Por exemplo, require('pkg/subpath.js') gera um erro ERR_PACKAGE_PATH_NOT_EXPORTED.

Esse encapsulamento de exports oferece garantias mais confiáveis sobre as interfaces de pacotes para ferramentas e ao lidar com atualizações semver para um pacote. Não é um encapsulamento forte, pois um require direto de qualquer subcaminho absoluto do pacote, como require('/path/to/node_modules/pkg/subpath.js'), ainda carregará subpath.js.

Todas as versões atualmente suportadas do Node.js e ferramentas de build modernas oferecem suporte ao campo "exports". Para projetos que usam uma versão mais antiga do Node.js ou uma ferramenta de build relacionada, a compatibilidade pode ser alcançada incluindo o campo "main" junto com "exports" apontando para o mesmo módulo:

json
{
  "main": "./index.js",
  "exports": "./index.js"
}

Exports de subcaminho

Adicionado em: v12.7.0

Ao usar o campo "exports", subcaminhos personalizados podem ser definidos junto com o ponto de entrada principal, tratando o ponto de entrada principal como o subcaminho ".":

json
{
  "exports": {
    ".": "./index.js",
    "./submodule.js": "./src/submodule.js"
  }
}

Agora, apenas o subcaminho definido em "exports" pode ser importado por um consumidor:

js
import submodule from 'es-module-package/submodule.js'
// Carrega ./node_modules/es-module-package/src/submodule.js

Enquanto outros subcaminhos gerarão um erro:

js
import submodule from 'es-module-package/private-module.js'
// Gera ERR_PACKAGE_PATH_NOT_EXPORTED

Extensões em subcaminhos

Os autores de pacotes devem fornecer subcaminhos com extensão (import 'pkg/subpath.js') ou sem extensão (import 'pkg/subpath') em seus exports. Isso garante que haja apenas um subcaminho para cada módulo exportado, para que todos os dependentes importem o mesmo especificador consistente, mantendo o contrato do pacote claro para os consumidores e simplificando as conclusões de subcaminho do pacote.

Tradicionalmente, os pacotes tendiam a usar o estilo sem extensão, que tem os benefícios de legibilidade e de mascarar o caminho verdadeiro do arquivo dentro do pacote.

Com os mapas de importação agora fornecendo um padrão para resolução de pacotes em navegadores e outros tempos de execução JavaScript, usar o estilo sem extensão pode resultar em definições de mapa de importação inchadas. Extensões de arquivo explícitas podem evitar esse problema, permitindo que o mapa de importação utilize um mapeamento de pastas de pacotes para mapear vários subcaminhos onde possível, em vez de uma entrada de mapa separada por exportação de subcaminho de pacote. Isso também espelha a exigência de usar o caminho completo do especificador em especificadores de importação relativos e absolutos.

Exports sugar

Adicionado em: v12.11.0

Se a exportação "." for a única exportação, o campo "exports" fornece açúcar para este caso, sendo o valor direto do campo "exports".

json
{
  "exports": {
    ".": "./index.js"
  }
}

pode ser escrito:

json
{
  "exports": "./index.js"
}

Subpath imports

Adicionado em: v14.6.0, v12.19.0

Além do campo "exports", existe um campo "imports" de pacote para criar mapeamentos privados que se aplicam apenas a especificadores de importação de dentro do próprio pacote.

As entradas no campo "imports" devem sempre começar com # para garantir que sejam desambiguadas de especificadores de pacotes externos.

Por exemplo, o campo de imports pode ser usado para obter os benefícios de exports condicionais para módulos internos:

json
// package.json
{
  "imports": {
    "#dep": {
      "node": "dep-node-native",
      "default": "./dep-polyfill.js"
    }
  },
  "dependencies": {
    "dep-node-native": "^1.0.0"
  }
}

onde import '#dep' não obtém a resolução do pacote externo dep-node-native (incluindo seus exports por sua vez) e, em vez disso, obtém o arquivo local ./dep-polyfill.js relativo ao pacote em outros ambientes.

Ao contrário do campo "exports", o campo "imports" permite o mapeamento para pacotes externos.

As regras de resolução para o campo imports são, caso contrário, análogas ao campo exports.

Subpath patterns

[Histórico]

VersãoAlterações
v16.10.0, v14.19.0Suporte para trailers de padrão no campo "imports".
v16.9.0, v14.19.0Suporte para trailers de padrão.
v14.13.0, v12.20.0Adicionado em: v14.13.0, v12.20.0

Para pacotes com um pequeno número de exports ou imports, recomendamos listar explicitamente cada entrada de subpath de exports. Mas para pacotes que possuem um grande número de subpaths, isso pode causar inchaço no package.json e problemas de manutenção.

Para esses casos de uso, padrões de exportação de subpath podem ser usados em vez disso:

json
// ./node_modules/es-module-package/package.json
{
  "exports": {
    "./features/*.js": "./src/features/*.js"
  },
  "imports": {
    "#internal/*.js": "./src/internal/*.js"
  }
}

* os mapeamentos expõem subpaths aninhados, pois é apenas uma sintaxe de substituição de string.

Todas as instâncias de * no lado direito serão substituídas por este valor, incluindo se ele contiver algum separador /.

js
import featureX from 'es-module-package/features/x.js'
// Carrega ./node_modules/es-module-package/src/features/x.js

import featureY from 'es-module-package/features/y/y.js'
// Carrega ./node_modules/es-module-package/src/features/y/y.js

import internalZ from '#internal/z.js'
// Carrega ./node_modules/es-module-package/src/internal/z.js

Esta é uma correspondência e substituição estática direta, sem nenhum tratamento especial para extensões de arquivo. Incluir o "*.js" em ambos os lados do mapeamento restringe os exports de pacote expostos apenas a arquivos JS.

A propriedade de exports ser estaticamente enumerável é mantida com padrões de exports, uma vez que os exports individuais para um pacote podem ser determinados tratando o padrão de destino do lado direito como um glob ** em relação à lista de arquivos dentro do pacote. Como os caminhos node_modules são proibidos em destinos de exports, esta expansão depende apenas dos arquivos do próprio pacote.

Para excluir subpastas privadas de padrões, alvos null podem ser usados:

json
// ./node_modules/es-module-package/package.json
{
  "exports": {
    "./features/*.js": "./src/features/*.js",
    "./features/private-internal/*": null
  }
}
js
import featureInternal from 'es-module-package/features/private-internal/m.js'
// Lança: ERR_PACKAGE_PATH_NOT_EXPORTED

import featureX from 'es-module-package/features/x.js'
// Carrega ./node_modules/es-module-package/src/features/x.js

Exportações Condicionais

[Histórico]

VersãoAlterações
v13.7.0, v12.16.0Remove a sinalização das exportações condicionais.
v13.2.0, v12.16.0Adicionado em: v13.2.0, v12.16.0

As exportações condicionais fornecem uma maneira de mapear para diferentes caminhos, dependendo de certas condições. Elas são suportadas para importações de CommonJS e módulos ES.

Por exemplo, um pacote que deseja fornecer diferentes exportações de módulo ES para require() e import pode ser escrito:

json
// package.json
{
  "exports": {
    "import": "./index-module.js",
    "require": "./index-require.cjs"
  },
  "type": "module"
}

O Node.js implementa as seguintes condições, listadas em ordem da mais específica para a menos específica, pois as condições devem ser definidas:

  • "node-addons" - semelhante a "node" e corresponde a qualquer ambiente Node.js. Esta condição pode ser usada para fornecer um ponto de entrada que usa complementos nativos em C++, em oposição a um ponto de entrada que é mais universal e não depende de complementos nativos. Esta condição pode ser desativada por meio da flag --no-addons.
  • "node" - corresponde a qualquer ambiente Node.js. Pode ser um arquivo de módulo CommonJS ou ES. Na maioria dos casos, não é necessário chamar explicitamente a plataforma Node.js.
  • "import" - corresponde quando o pacote é carregado via import ou import(), ou via qualquer importação de nível superior ou operação de resolução pelo carregador de módulos ECMAScript. Aplica-se independentemente do formato do módulo do arquivo de destino. Sempre mutuamente exclusivo com "require".
  • "require" - corresponde quando o pacote é carregado via require(). O arquivo referenciado deve ser carregável com require(), embora a condição corresponda independentemente do formato do módulo do arquivo de destino. Os formatos esperados incluem CommonJS, JSON, complementos nativos e módulos ES. Sempre mutuamente exclusivo com "import".
  • "module-sync" - corresponde independentemente de o pacote ser carregado via import, import() ou require(). Espera-se que o formato seja de módulos ES que não contenham await de nível superior em seu gráfico de módulos - se contiver, ERR_REQUIRE_ASYNC_MODULE será lançado quando o módulo for require()-ed.
  • "default" - o fallback genérico que sempre corresponde. Pode ser um arquivo de módulo CommonJS ou ES. Esta condição deve sempre vir por último.

Dentro do objeto "exports", a ordem das chaves é significativa. Durante a correspondência de condições, as entradas anteriores têm maior prioridade e precedem as entradas posteriores. A regra geral é que as condições devem ser da mais específica para a menos específica na ordem do objeto.

O uso das condições "import" e "require" pode levar a alguns perigos, que são explicados com mais detalhes na seção de pacotes de módulos dual CommonJS/ES.

A condição "node-addons" pode ser usada para fornecer um ponto de entrada que usa complementos nativos em C++. No entanto, esta condição pode ser desativada por meio da flag --no-addons. Ao usar "node-addons", é recomendável tratar "default" como um aprimoramento que fornece um ponto de entrada mais universal, por exemplo, usando WebAssembly em vez de um complemento nativo.

As exportações condicionais também podem ser estendidas para subcaminhos de exportações, por exemplo:

json
{
  "exports": {
    ".": "./index.js",
    "./feature.js": {
      "node": "./feature-node.js",
      "default": "./feature.js"
    }
  }
}

Define um pacote onde require('pkg/feature.js') e import 'pkg/feature.js' podem fornecer implementações diferentes entre Node.js e outros ambientes JS.

Ao usar branches de ambiente, sempre inclua uma condição "default" sempre que possível. Fornecer uma condição "default" garante que qualquer ambiente JS desconhecido seja capaz de usar esta implementação universal, o que ajuda a evitar que esses ambientes JS tenham que fingir ser ambientes existentes para suportar pacotes com exportações condicionais. Por esta razão, usar branches de condição "node" e "default" geralmente é preferível a usar branches de condição "node" e "browser".

Condições aninhadas

Além dos mapeamentos diretos, o Node.js também suporta objetos de condição aninhados.

Por exemplo, para definir um pacote que tenha apenas pontos de entrada de modo duplo para uso no Node.js, mas não no navegador:

json
{
  "exports": {
    "node": {
      "import": "./feature-node.mjs",
      "require": "./feature-node.cjs"
    },
    "default": "./feature.mjs"
  }
}

As condições continuam a ser correspondidas em ordem, como nas condições planas. Se uma condição aninhada não tiver nenhum mapeamento, ela continuará verificando as condições restantes da condição pai. Desta forma, as condições aninhadas se comportam de forma análoga às instruções if aninhadas do JavaScript.

Resolvendo condições do usuário

Adicionado em: v14.9.0, v12.19.0

Ao executar o Node.js, condições de usuário personalizadas podem ser adicionadas com a flag --conditions:

bash
node --conditions=development index.js

que então resolveria a condição "development" nas importações e exportações de pacotes, enquanto resolve as condições existentes "node", "node-addons", "default", "import" e "require" conforme apropriado.

Qualquer número de condições personalizadas pode ser definido com flags repetidas.

Condições típicas devem conter apenas caracteres alfanuméricos, usando ":", "-" ou "=" como separadores, se necessário. Qualquer outra coisa pode causar problemas de compatibilidade fora do node.

No node, as condições têm muito poucas restrições, mas especificamente estas incluem:

Definições de Condições da Comunidade

Strings de condição diferentes das condições "import", "require", "node", "module-sync", "node-addons" e "default" implementadas no núcleo do Node.js são ignoradas por padrão.

Outras plataformas podem implementar outras condições e condições de usuário podem ser habilitadas no Node.js via a flag --conditions / -C.

Como as condições de pacote personalizadas exigem definições claras para garantir o uso correto, uma lista de condições de pacote comuns conhecidas e suas definições estritas é fornecida abaixo para auxiliar na coordenação do ecossistema.

  • "types" - pode ser usado por sistemas de tipagem para resolver o arquivo de tipagem para a exportação fornecida. Esta condição deve sempre ser incluída primeiro.
  • "browser" - qualquer ambiente de navegador web.
  • "development" - pode ser usado para definir um ponto de entrada de ambiente apenas para desenvolvimento, por exemplo, para fornecer contexto de depuração adicional, como mensagens de erro melhores ao executar em um modo de desenvolvimento. Deve sempre ser mutuamente exclusivo com "production".
  • "production" - pode ser usado para definir um ponto de entrada de ambiente de produção. Deve sempre ser mutuamente exclusivo com "development".

Para outros tempos de execução, definições de chaves de condição específicas da plataforma são mantidas pelo WinterCG na especificação da proposta de Chaves de Tempo de Execução.

Novas definições de condições podem ser adicionadas a esta lista criando um pull request para a documentação do Node.js para esta seção. Os requisitos para listar uma nova definição de condição aqui são que:

  • A definição deve ser clara e inequívoca para todos os implementadores.
  • O caso de uso para o motivo pelo qual a condição é necessária deve ser claramente justificado.
  • Deve existir uso de implementação existente suficiente.
  • O nome da condição não deve entrar em conflito com outra definição de condição ou condição em uso amplo.
  • A listagem da definição da condição deve fornecer um benefício de coordenação para o ecossistema que não seria possível de outra forma. Por exemplo, este não seria necessariamente o caso para condições específicas da empresa ou específicas da aplicação.
  • A condição deve ser tal que um usuário do Node.js esperaria que ela estivesse na documentação principal do Node.js. A condição "types" é um bom exemplo: Ela realmente não pertence à proposta de Chaves de Tempo de Execução, mas é adequada aqui na documentação do Node.js.

As definições acima podem ser movidas para um registro de condições dedicado no devido tempo.

Autorreferenciando um pacote usando seu nome

[Histórico]

VersãoMudanças
v13.6.0, v12.16.0Remove a flag de autorreferenciar um pacote usando seu nome.
v13.1.0, v12.16.0Adicionado em: v13.1.0, v12.16.0

Dentro de um pacote, os valores definidos no campo "exports" do package.json do pacote podem ser referenciados através do nome do pacote. Por exemplo, supondo que o package.json seja:

json
// package.json
{
  "name": "a-package",
  "exports": {
    ".": "./index.mjs",
    "./foo.js": "./foo.js"
  }
}

Então, qualquer módulo nesse pacote pode referenciar uma exportação no próprio pacote:

js
// ./a-module.mjs
import { something } from 'a-package' // Importa "something" de ./index.mjs.

A autorreferência só está disponível se package.json tiver "exports", e permitirá importar apenas o que o "exports" (no package.json) permitir. Portanto, o código abaixo, dado o pacote anterior, irá gerar um erro de tempo de execução:

js
// ./another-module.mjs

// Importa "another" de ./m.mjs. Falha porque
// o campo "exports" do "package.json"
// não fornece uma exportação chamada "./m.mjs".
import { another } from 'a-package/m.mjs'

A autorreferência também está disponível ao usar require, tanto em um módulo ES quanto em um CommonJS. Por exemplo, este código também funcionará:

js
// ./a-module.js
const { something } = require('a-package/foo.js') // Carrega de ./foo.js.

Finalmente, a autorreferência também funciona com pacotes com escopo. Por exemplo, este código também funcionará:

json
// package.json
{
  "name": "@my/package",
  "exports": "./index.js"
}
js
// ./index.js
module.exports = 42
js
// ./other.js
console.log(require('@my/package'))
bash
$ node other.js
42

Pacotes duplos CommonJS/módulo ES

Consulte o repositório de exemplos de pacotes para obter detalhes.

Definições de campos package.json do Node.js

Esta seção descreve os campos usados pelo runtime do Node.js. Outras ferramentas (como npm) usam campos adicionais que são ignorados pelo Node.js e não são documentados aqui.

Os seguintes campos em arquivos package.json são usados no Node.js:

  • "name" - Relevante ao usar importações nomeadas dentro de um pacote. Também usado por gerenciadores de pacotes como o nome do pacote.
  • "main" - O módulo padrão ao carregar o pacote, se exports não for especificado, e em versões do Node.js anteriores à introdução de exports.
  • "packageManager" - O gerenciador de pacotes recomendado ao contribuir para o pacote. Aproveitado pelos shims do Corepack.
  • "type" - O tipo de pacote que determina se deve carregar arquivos .js como CommonJS ou módulos ES.
  • "exports" - Exportações de pacotes e exportações condicionais. Quando presente, limita quais submódulos podem ser carregados de dentro do pacote.
  • "imports" - Importações de pacotes, para uso por módulos dentro do próprio pacote.

"name"

[Histórico]

VersãoMudanças
v13.6.0, v12.16.0Remove a opção --experimental-resolve-self.
v13.1.0, v12.16.0Adicionado em: v13.1.0, v12.16.0
json
{
  "name": "nome-do-pacote"
}

O campo "name" define o nome do seu pacote. A publicação no registro npm requer um nome que satisfaça certos requisitos.

O campo "name" pode ser usado em conjunto com o campo "exports" para autorreferenciar um pacote usando seu nome.

"main"

Adicionado em: v0.4.0

json
{
  "main": "./index.js"
}

O campo "main" define o ponto de entrada de um pacote quando importado por nome por meio de uma pesquisa node_modules. Seu valor é um caminho.

Quando um pacote tem um campo "exports", isso terá precedência sobre o campo "main" ao importar o pacote por nome.

Ele também define o script que é usado quando o diretório do pacote é carregado via require().

js
// Isso é resolvido para ./path/to/directory/index.js.
require('./path/to/directory')

"packageManager"

Adicionado em: v16.9.0, v14.19.0

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

json
{
  "packageManager": "<nome do gerenciador de pacotes>@<versão>"
}

O campo "packageManager" define qual gerenciador de pacotes deve ser usado ao trabalhar no projeto atual. Ele pode ser definido para qualquer um dos gerenciadores de pacotes suportados e garantirá que suas equipes usem as mesmas versões de gerenciador de pacotes sem ter que instalar nada além do Node.js.

Este campo é atualmente experimental e precisa ser ativado; verifique a página Corepack para obter detalhes sobre o procedimento.

"type"

[Histórico]

VersãoMudanças
v13.2.0, v12.17.0Remove a flag --experimental-modules.
v12.0.0Adicionado em: v12.0.0

O campo "type" define o formato de módulo que o Node.js usa para todos os arquivos .js que têm aquele arquivo package.json como seu pai mais próximo.

Arquivos terminados em .js são carregados como módulos ES quando o arquivo package.json pai mais próximo contém um campo de nível superior "type" com um valor de "module".

O package.json pai mais próximo é definido como o primeiro package.json encontrado ao pesquisar na pasta atual, na pasta pai dessa pasta e assim por diante, até que uma pasta node_modules ou a raiz do volume seja atingida.

json
// package.json
{
  "type": "module"
}
bash
# Na mesma pasta do package.json anterior {#in-same-folder-as-preceding-packagejson}
node my-app.js # Executa como módulo ES

Se o package.json pai mais próximo não tiver um campo "type" ou contiver "type": "commonjs", os arquivos .js são tratados como CommonJS. Se a raiz do volume for atingida e nenhum package.json for encontrado, os arquivos .js são tratados como CommonJS.

As instruções import de arquivos .js são tratadas como módulos ES se o package.json pai mais próximo contiver "type": "module".

js
// my-app.js, parte do mesmo exemplo acima
import './startup.js' // Carregado como módulo ES por causa do package.json

Independentemente do valor do campo "type", os arquivos .mjs são sempre tratados como módulos ES e os arquivos .cjs são sempre tratados como CommonJS.

"exports"

[Histórico]

VersãoMudanças
v14.13.0, v12.20.0Adiciona suporte para padrões "exports".
v13.7.0, v12.17.0Remove a flag de exports condicionais.
v13.7.0, v12.16.0Implementa a ordenação lógica de exports condicionais.
v13.7.0, v12.16.0Remove a opção --experimental-conditional-exports. Na versão 12.16.0, exports condicionais ainda estão atrás de --experimental-modules.
v13.2.0, v12.16.0Implementa exports condicionais.
v12.7.0Adicionado em: v12.7.0
json
{
  "exports": "./index.js"
}

O campo "exports" permite definir os pontos de entrada de um pacote quando importado por nome carregado por meio de uma pesquisa node_modules ou uma autorreferência ao seu próprio nome. É suportado no Node.js 12+ como uma alternativa ao "main" que pode suportar a definição de exports de subcaminho e exports condicionais enquanto encapsula módulos internos não exportados.

Exports Condicionais também podem ser usados ​​em "exports" para definir diferentes pontos de entrada de pacote por ambiente, incluindo se o pacote é referenciado via require ou via import.

Todos os caminhos definidos em "exports" devem ser URLs de arquivo relativos começando com ./.

"imports"

Adicionado em: v14.6.0, v12.19.0

json
// package.json
{
  "imports": {
    "#dep": {
      "node": "dep-node-native",
      "default": "./dep-polyfill.js"
    }
  },
  "dependencies": {
    "dep-node-native": "^1.0.0"
  }
}

As entradas no campo de imports devem ser strings que começam com #.

Os imports de pacotes permitem o mapeamento para pacotes externos.

Este campo define imports de subcaminho para o pacote atual.