Otra forma de usar Webpack 4 y separación de código

Antecedentes


No es ningún secreto que con el lanzamiento de Webpack 4, la estrategia de intercambio de código ha cambiado mucho. Es incluso mejor decir que fue inventado nuevamente, porque el enfoque anterior simplemente dejó de funcionar y el nuevo no tiene claro cómo usarlo.


Para aquellos que aún no están actualizados, el complemento webpack.optimize.CommonsChunkPlugin ya no está. Absolutamente En cambio, se sugiere escribir lo siguiente en la configuración:


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

Eso debería funcionar como magia. Es decir Ahora no le decimos a webpack qué hacer como una parte común, pero él hará todo por sí mismo, e incluso mejor que nosotros.


Y la felicidad vendrá. Un chiste En realidad no ...


Preparaciones básicas


Aquí hay un ejemplo de la documentación:


 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' } } }; 

El resultado del ensamblado será 3 archivos: otro.bundle.js, index.bundle.js, proveedores ~ otro ~ 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 

Ahora, para lanzar nuestras aplicaciones web, en un caso, debemos conectar proveedores ~ otro ~ index.bundle.js e index.bundle.js, y en los segundos proveedores ~ otro ~ index.bundle.js y otro. bundle.js.


Cual es el problema


El problema es el nombre de proveedores ~ otro ~ índice .bundle.js. Mientras tengamos menos de tres puntos de entrada, no pasa nada malo. Aquí todo parece lógico: el paquete contiene módulos npm (también son proveedores) y módulos generales para index y otro. En cada una de las páginas incluimos 2 archivos y no tenemos problemas.


Sin embargo, si tenemos tres o más puntos de entrada, puede que haya muchos más paquetes nuevos (son fragmentos) y ya no sabemos su número o nombre. Todo se vuelve aún más divertido si también extraemos CSS en archivos separados. Y ese es el problema.


¿Cómo resolver este problema?


Después de completar el paquete web, no tenemos ningún archivo que contenga información sobre qué paquetes en esta o aquella página deben conectarse. Y en que orden.


Sin embargo, en la salida podemos encontrar estas líneas:


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

De hecho, esto es casi lo que necesitamos. Es decir webpack sabe muy bien qué paquetes se necesitan para cada punto de entrada, pero por alguna razón no quiere compartir esta información con nosotros.


El manifiesto no nos ayuda aquí. Sí, sabemos que existe dicho paquete (proveedores ~ otro ~ index.bundle.js). Sabemos dónde se encuentra. Pero no sabemos quién lo necesita. Es decir El manifiesto es inútil.


Entonces decidí que dado que webpack conoce la información necesaria, posiblemente se pueda obtener utilizando complementos. No encontré ninguno listo y decidí escribir el mío. Y, solo por demostrar este complemento, estoy escribiendo este artículo.


 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 }; }); } } 

En el archivo webpack.config. (Ts | js), agregue un nuevo complemento:


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

y espera el resultado. El resultado será un archivo entrypoints.json con este contenido:


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

Si se usa extract-css, además de la sección js también habrá css.


Lo último que nos queda, al formar la página HTML, es leer el archivo entrypoints.json, encontrar el punto de entrada deseado, conectar los archivos js y css de las listas correspondientes.


Problema resuelto


Algo asi.

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


All Articles