Antes da proposta da especificação CommonJs, o Javascript não possuía um sistema de módulos, o que dificultava o desenvolvimento de aplicações em larga escala porque a organização do código seria mais difícil.
Em primeiro lugar, CommonJS não é exclusivo do Node. CommonJS é uma especificação de módulo que define como referenciar e exportar módulos. O Nodejs apenas implementa esta especificação. A especificação do módulo CommonJS é dividida principalmente em três partes: referência do módulo, definição do módulo e identificação do módulo. .
Referência de módulo
Referência de módulo significa que podemos introduzir outros módulos através de require
.
const { adicionar } = exigir('./add'); const result = add(1,2);
Módulo define
um arquivo como um módulo, e o módulo fornecerá duas variáveis, nomeadamente módulo e exportações. module é o próprio módulo atual, exports é o conteúdo a ser exportado e exports é um atributo do módulo, ou seja, exports é module.exports. O conteúdo importado por outros módulos através de require é o conteúdo de module.exports.
//adicionar.js exportações.add = (a, b) => { retornar a + b; }
Identificação do módulo
A identificação do módulo é o conteúdo em require('./add')
, então a identificação do módulo é ./add
.
O mecanismo de importação e exportação de módulos construído por meio do CommonJS permite que os usuários criem facilmente aplicativos em grande escala sem ter que considerar a poluição variável.
Implementação do módulo de nó
O Node implementa a especificação CommonJs e adiciona alguns recursos necessários. O Node faz principalmente as três coisas a seguir para implementar a especificação CommonJs:
Posicionamento do arquivo de
análise de caminho
, compilação e execução da
análise de caminho
Quando require() é executado, o parâmetro recebido por require é o identificador do módulo, e o nó realiza a análise do caminho através do identificador do módulo. O objetivo da análise de caminho é encontrar o caminho onde este módulo está localizado através do identificador do módulo. Em primeiro lugar, os módulos de nó são divididos em duas categorias, nomeadamente módulos principais e módulos de arquivo. O módulo principal é o módulo que vem com o nó, e o módulo de arquivo é o módulo escrito pelo usuário. Ao mesmo tempo, os módulos de arquivo são divididos em módulos de arquivo na forma de caminhos relativos, módulos de arquivo na forma de caminhos absolutos e módulos de arquivo na forma de não caminhos (como expresso).
Quando o nó encontra um módulo de arquivo, ele irá compilar, executar e armazenar em cache o módulo. O princípio geral é usar o caminho completo do módulo como chave e o conteúdo compilado como valor. pela segunda vez, execute a análise do caminho, localização do arquivo, compilação e execução dessas etapas. O conteúdo compilado pode ser lido diretamente do cache.
//Diagrama do módulo de cache: const cachedModule = { '/Usr/file/src/add.js': 'Conteúdo compilado de add.js', 'http': 'Conteúdo compilado do módulo http que vem com o Node', 'express': 'Conteúdo compilado do módulo de arquivo personalizado sem caminho expresso' // ... }
Quando você deseja encontrar o módulo importado por require, a ordem de busca do módulo é primeiro verificar se o módulo já está no cache. Se não estiver no cache, verifique o módulo principal e procure. o módulo de arquivo. Entre eles, os módulos de arquivo na forma de caminhos são mais fáceis de encontrar. O caminho completo do arquivo pode ser obtido com base no caminho relativo ou absoluto. É relativamente problemático encontrar módulos de arquivo personalizados em formato sem caminho. O Node procurará o arquivo na pasta node_modules.
Onde está o diretório node_modules. Por exemplo, o arquivo que estamos executando atualmente é /Usr/file/index.js
; * /Usr/file/index.js; */ const {adicionar} = require('adicionar'); const result = add(1, 2);
Neste módulo, introduzimos um módulo add. Este add não é um módulo principal nem um módulo de arquivo na forma de um caminho.
O módulo tem um atributo path. O caminho para encontrar o módulo add está no atributo paths. Podemos digitar este atributo para dar uma olhada:
/**. * /Usr/file/index.js; */ console.log(module.paths);
Podemos imprimir o valor dos caminhos executando node index.js no diretório do arquivo. O valor em caminhos é uma matriz, como segue:
[ '/Usr/arquivo/node_modules', '/Usr/node_modules', '/node_modules', ]
Ou seja, o Node pesquisará sequencialmente no diretório acima para ver se ele contém o módulo add. O princípio é semelhante à cadeia de protótipos. Primeiro, comece a pesquisar na pasta node_modules no diretório do mesmo nível do arquivo atualmente executado. Se o diretório node_modules não for encontrado ou não existir, continue pesquisando para o nível superior.
A análise do caminhoda localização do arquivo
e a localização do arquivo são usadas juntas. O identificador do arquivo pode não ter um sufixo ou um diretório ou pacote pode ser encontrado por meio da análise do caminho.
Análise de extensão de arquivo
const { add } = require('./add');
Por exemplo, no código acima, o identificador de arquivo não possui uma extensão. Neste momento, o nó irá procurar a existência de .js, .json. e .node no documento sequencial.
A análise de diretório e pacote
é igual ao código acima. O que é encontrado por meio de ./add
pode não ser um arquivo, mas pode ser um diretório ou pacote (julgar se é um diretório ou um pacote julgando se existe um pacote. json na pasta add). Neste momento, as etapas para posicionamento do arquivo são as seguintes:
Se não houver campo principal em package.json, o índice também será usado como um arquivo e, em seguida, será realizada uma análise de extensão para encontrar o arquivo com o sufixo correspondente .
Compilação de módulos
Os principais módulos que encontramos no desenvolvimento são módulos json e módulos js.
compilação do módulo json
Quando precisamos de um módulo json, o Node realmente nos ajudará a usar fs.readFilcSync para ler o arquivo json correspondente, obter a string json e, em seguida, chamar JSON.parse para analisar para obter o objeto json e, em seguida, atribuí-lo a o módulo exporta e, em seguida, forneça-o para exigir.
compilação do módulo js
Quando precisamos de um módulo js, como
// index.js const { adicionar } = require('./add')
; exportações.add = (a, b) => { retornar a + b; }
O que aconteceu neste momento? Por que podemos usar o módulo de variáveis, exportar e exigir diretamente no módulo. Isso ocorre porque o Node agrupa o conteúdo do módulo primeiro e por último ao compilar o módulo js.
Por exemplo, o módulo add.js será empacotado em uma estrutura semelhante a esta quando realmente compilado:
(function(require, exports, module) { exportações.add = (a, b) => { retornar a + b; } retornar módulo.exportações; })(require, module.exports, module)
Ou seja, o arquivo js que escrevemos será empacotado em uma função. O que escrevemos é apenas o conteúdo desta função, e o processo de empacotamento subsequente do Node fica oculto para nós. Esta função suporta a passagem de alguns parâmetros, incluindo require, exports e module.
Após a compilação do arquivo js, o arquivo será executado. O Node passará os parâmetros correspondentes para esta função e, em seguida, executará e retornará o valor module.exports para a função require.
O texto acima é o processo básico para o Node implementar as especificações CommonJs.