Como um "leão de cerco" de front-end, o Webpack é muito familiar. Ele pode empacotar todos os recursos (incluindo JS, TS, JSX, imagens, fontes, CSS, etc.) e colocá-los em dependências. ., permitindo referenciar dependências para usar recursos de acordo com suas necessidades. O Webpack fez um excelente trabalho ao traduzir vários recursos de arquivo no front-end e analisar dependências complexas de módulos. Também podemos personalizar o carregador e carregar nossos próprios recursos livremente. Venha e dê uma olhada hoje.
1. O que é necessário?
Quando se trata de require, a primeira coisa que vem à mente pode ser import. Import é um padrão de sintaxe do es6
– require é uma chamada de tempo de execução, então require pode teoricamente ser usado em qualquer lugar do código –
import é um tempo de compilação
;call, portanto deve ser colocado no início do arquivo.
Quando usarmos Webpack para compilar, usaremos babel para traduzir import em require. . AMD e CMD também usam o método require para fazer referência.
Por exemplo:
var add = require('./a.js');Em termos simples,
add(1,2)
requer é na verdade uma função, e o ./a.js
referenciado é apenas um parâmetro da função.
2. O que são exportações?
Aqui podemos pensar nas exportações como um objeto. Você pode ver o uso específico da exportação MDN.
Vamos primeiro dar uma olhada na estrutura do código após a nossa embalagem. Podemos descobrir que a exigência e as exportações aparecerão após a embalagem.
Nem todos os navegadores podem executar require exports. Você mesmo deve implementar require e exports para garantir a operação normal do código. O código empacotado é uma função autoexecutável. Os parâmetros possuem informações de dependência e o código do arquivo executado executa o código por meio de eval.
O desenho geral do projeto é o seguinte:
Etapa 1: Escreva nosso arquivo de configuração
O arquivo de configuração configura nossa entrada e saída do pacote para preparar os arquivos gerados subsequentes.
const caminho = require("caminho"); módulo.exportações = { entrada: "./src/index.js", saída: { caminho: path.resolve(__dirname, "./dist"),//A saída do endereço do arquivo após o empacotamento requer um caminho absoluto, portanto o caminho é obrigatório nome do arquivo: "main.js" }, modo: "desenvolvimento"
Etapa 2: A ideia geral da análise do módulo
: Em resumo, é usar o arquivo fs para ler o arquivo de entrada e obter o caminho do arquivo dependente de importação através do AST. tem dependências, continue recorrendo até que a análise de dependência seja clara, mantida em um mapa.
Análise detalhada : Algumas pessoas podem se perguntar por que o AST é usado, porque o AST nasceu com essa função. Afinal, o arquivo é um arquivo. string após ser lida. Ao escrever O incrível regex é útil para obter caminhos de dependência de arquivos, mas não é elegante o suficiente.
arquivo index.js
import { str } from "./a.js"; console.log(`${str} Webpack`)importação de
arquivo a.js
{ b} de "./b.js" export const str = "hello"
b.js file
export const b="bbb"
análise do módulo Webpack: use @babel/parser do AST para converter a string lida do arquivo em uma árvore AST e @babel/traverse para sintaxe Analise e use ImportDeclaration para filtrar importações e localizar dependências de arquivos.
conteúdo const = fs.readFileSync(entryFile, "utf-8"); const ast = parser.parse(content, { sourceType: "module" }); const dirname = caminho.dirname(entryFile); dependentes const = {}; atravessar(ast, { ImportDeclaration({nó}) { //Filtrar importações const newPathName = "./" + path.join(dirname, node.source.value); dependentes[node.source.value] = novoNomeCaminho; } }) const { código } = transformFromAst(ast, null, { predefinições: ["@babel/preset-env"] }) retornar { arquivo de entrada, dependentes, código }
Os resultados são os seguintes:
Use recursão ou loop para importar arquivos um por um para análise de dependência. Observe aqui que usamos loop for para analisar todas as dependências. novas dependências, module.length mudará.
for (seja i = 0; i < this.modules.length; i++) { const item = this.modules[i]; const {dependentes} = item; if (dependentes) { for (deixe j em dependentes) { this.modules.push(this.parse(dependentes[j])); } } }
Etapa 3: Escreva a função WebpackBootstrap + gere o arquivo de saída.
Escreva a função WebpackBootstrap : A primeira coisa que precisamos fazer aqui é a função WebpackBootstrap. Após a compilação, a importação de nosso código-fonte será analisada em require. não reconhece require, então devemos declará-lo primeiro. Afinal, require é um método. Ao escrever funções, você também precisa prestar atenção ao isolamento do escopo para evitar poluição variável. Também precisamos declarar as exportações em nosso código para garantir que as exportações já existam quando o código for executado.
Gere o arquivo de saída : Já escrevemos o endereço do arquivo gerado no arquivo de configuração e, em seguida, usamos fs.writeFileSync para gravá-lo na pasta de saída.
arquivo(código) { const filePath = path.join(this.output.path, this.output.filename) const novoCode = JSON.stringify(código); // Gera o conteúdo do arquivo do pacote const bundle = `(function(modules){ função requer(módulo){ function pathRequire(caminhorelativo){ retornar requer (módulos[módulo].dependentes[caminhorelativo]) } exportações const={}; (função(requer,exportações,código){ avaliação (código) })(pathRequire,exportações,módulos[módulo].código); devolver exportações } require('${this.entry}') })(${novoCódigo})`; //WebpackBoostrap //Gerar arquivo. Coloque-o no diretório dist fs.writeFileSync(filePath,bundle,'utf-8') }
Passo 4: Analise a sequência de execução
Podemos executar o resultado empacotado no console do navegador. Se funcionar normalmente, hello Webpack deverá ser impresso.
Através da análise acima, devemos ter uma compreensão básica do processo geral do Webpack. Usar AST para analisar o código é apenas uma forma de demonstração, não a implementação real do Webpack. O Webpack possui seu próprio método de análise AST. em constante mudança. O ecossistema Webpack é muito completo. As crianças interessadas podem considerar as seguintes três questões: