Outra maneira de usar o Webpack 4 e a separação de código

Antecedentes


Não é segredo que, com o lançamento do Webpack 4, a estratégia de compartilhamento de código mudou muito. É ainda melhor dizer que foi inventado novamente, porque a abordagem antiga parou de funcionar e a nova não está clara como usá-la.


Para aqueles que ainda não estão atualizados, o plug-in webpack.optimize.CommonsChunkPlugin desapareceu. Absolutamente. Em vez disso, é recomendável escrever o seguinte na configuração:


module.exports = { // ... optimization: { splitChunks: { chunks: "all" } } // ... } 

Isso deve funcionar como mágica. I.e. Agora, não dizemos ao webpack o que fazer como um pedaço comum, mas ele fará tudo sozinho e ainda melhor que nós.


E a felicidade virá. Uma piada. Na verdade não ...


Preparações básicas


Aqui está um exemplo da documentação:


 module.exports = { mode: 'development', entry: { index: './src/index.js', another: './src/another-module.js' }, output: { filename: '[name].bundle.js', path: path.resolve(__dirname, 'dist') }, optimization: { splitChunks: { chunks: 'all' } } }; 

O resultado da montagem será de 3 arquivos: another.bundle.js, index.bundle.js, fornecedores ~ outro ~ index.bundle.js


 Hash: ac2ac6042ebb4f20ee54 Version: webpack 4.7.0 Time: 316ms Asset Size Chunks Chunk Names another.bundle.js 5.95 KiB another [emitted] another index.bundle.js 5.89 KiB index [emitted] index vendors~another~index.bundle.js 547 KiB vendors~another~index [emitted] vendors~another~index Entrypoint index = vendors~another~index.bundle.js index.bundle.js Entrypoint another = vendors~another~index.bundle.js another.bundle.js [./node_modules/webpack/buildin/global.js] (webpack)/buildin/global.js 489 bytes {vendors~another~index} [built] [./node_modules/webpack/buildin/module.js] (webpack)/buildin/module.js 497 bytes {vendors~another~index} [built] [./src/another-module.js] 88 bytes {another} [built] [./src/index.js] 86 bytes {index} [built] + 1 hidden module 

Agora, para iniciar nossos aplicativos da Web, em um caso, devemos conectar fornecedores ~ outro ~ index.bundle.js e index.bundle.js, e nos segundos fornecedores ~ outro ~ index.bundle.js e outro. bundle.js.


Qual é o problema?


O problema é o nome de fornecedores ~ outro ~ índice .bundle.js. Enquanto tivermos menos de três pontos de entrada, nada de ruim acontece. Tudo parece lógico aqui - o pacote contém módulos npm (eles também são fornecedores) e módulos gerais para índice e outro. Em cada uma das páginas, incluímos 2 arquivos e não temos problemas.


No entanto, se tivermos três ou mais pontos de entrada, poderá haver muito mais novos pacotes configuráveis ​​(eles são pedaços) e não saberemos mais o número ou os nomes deles. Tudo se torna ainda mais divertido se também extrairmos o CSS em arquivos separados. E esse é o problema.


Como resolver este problema?


Depois de concluir o webpack, não temos mais arquivos que contenham informações sobre quais pacotes nesta ou naquela página devem ser conectados. E em que ordem.


No entanto, na saída, podemos encontrar estas linhas:


 Entrypoint index = vendors~another~index.bundle.js index.bundle.js Entrypoint another = vendors~another~index.bundle.js another.bundle.js 

De fato, isso é quase o que precisamos. I.e. O webpack sabe muito bem quais pacotes são necessários para cada ponto de entrada, mas, por algum motivo, ele próprio não deseja compartilhar essas informações conosco.


O manifesto não nos ajuda aqui. Sim, sabemos que existe um pacote (fornecedores ~ outro ~ index.bundle.js). Nós sabemos onde ele está. Mas não sabemos quem precisa. I.e. o manifesto é inútil.


Então decidi que, como o webpack conhece as informações necessárias, elas podem ser obtidas usando plugins. Não encontrei nenhum já pronto e resolvi escrever o meu. E, apenas para demonstrar este plugin, estou escrevendo este artigo.


 import * as webpack from "webpack"; export interface IChunkDescription { readonly id: string | number; readonly name: string; readonly files: string[]; } export interface IEntrypointsPluginOptions { readonly filename: string; readonly replacer?: (key: string, value: any) => any; readonly space?: string | number; readonly filter?: (chunk: IChunkDescription) => boolean; } export default class EntrypointsPlugin { private readonly options: IEntrypointsPluginOptions; public constructor(options: IEntrypointsPluginOptions) { this.options = Object.assign<IEntrypointsPluginOptions, IEntrypointsPluginOptions>({ filename: "entrypoints.json", replacer: null, space: null, filter: null }, options); } public apply(compiler: webpack.Compiler): void { compiler.hooks.emit.tap("entrypoints", (compilation: webpack.compilation.Compilation) => { let data = {}; let entrypoints = {}; const filter = this.options.filter; const publicPath = compilation.compiler.options.output.publicPath; for (let [key, value] of compilation.entrypoints.entries()) { const chunks: IChunkDescription[] = value.chunks.map(data => { const chunk: IChunkDescription = { id: data.id, name: data.name, files: data.files }; return filter == null || filter(chunk) ? chunk : null; }); const files = ([] as string[]).concat(...chunks.filter(c => c != null) .map(c => c.files.map(f => publicPath + f))); const js = files.filter(f => /.js/.test(f) && !/.js.map/.test(f)); const css = files.filter(f => /.css/.test(f) && !/.css.map/.test(f)); let entrypoint = {}; if (js.length) entrypoint["js"] = js; if (css.length) entrypoint["css"] = css; data[key] = entrypoint; } const json = JSON.stringify(data, this.options.replacer, this.options.space); compilation.assets[this.options.filename] = { source: () => json, size: () => json.length }; }); } } 

No arquivo webpack.config. (Ts | js), adicione um novo plug-in:


 plugins: [ new EntrypointsPlugin({ filename: "entrypoints.json", space: 2 }) ] 

e aguarde o resultado. O resultado será um arquivo entrypoints.json com este conteúdo:


 { "index": { "js": ["vendors~another~index.bundle.js", "index.bundle.js"] }, "another": { "js": ["vendors~another~index.bundle.js", "another.bundle.js"] } } 

Se extract-css for usado, além da seção js, ​​também haverá css.


A última coisa que resta para nós, ao formar a página HTML, é ler o arquivo entrypoints.json, encontrar o ponto de entrada desejado, conectar arquivos js e css nas listas correspondentes.


Problema resolvido


Algo assim.

Source: https://habr.com/ru/post/pt423693/


All Articles