Cara lain untuk menggunakan Webpack 4 dan pemisahan kode

Latar belakang


Bukan rahasia lagi bahwa dengan rilis Webpack 4, strategi berbagi kode telah banyak berubah. Lebih baik mengatakan bahwa itu diciptakan lagi, karena pendekatan lama berhenti bekerja, dan yang baru tidak jelas bagaimana menggunakannya.


Bagi mereka yang masih belum mutakhir, plugin webpack.optimize.CommonsChunkPlugin hilang. Tentu saja Sebagai gantinya, disarankan untuk menulis yang berikut di konfigurasi:


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

Itu seharusnya bekerja seperti sihir. Yaitu Sekarang kami tidak memberi tahu webpack apa yang harus dilakukan sebagai bagian yang umum, tetapi dia akan melakukan semuanya sendiri, dan bahkan lebih baik dari kita.


Dan kebahagiaan akan datang. Lelucon. Tidak juga ...


Persiapan dasar


Berikut ini adalah contoh dari dokumentasi:


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

Hasil perakitan akan menjadi 3 file: another.bundle.js, index.bundle.js, vendor ~ another ~ 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 

Sekarang, untuk meluncurkan aplikasi web kami, dalam satu kasus, kita harus menghubungkan vendor ~ yang lain ~ index.bundle.js dan index.bundle.js, dan pada vendor kedua ~ lain ~ index.bundle.js dan yang lain. bundle.js.


Apa masalahnya?


Masalahnya adalah nama vendor ~ yang lain ~ index .bundle.js. Selama kita memiliki kurang dari tiga titik masuk, tidak ada hal buruk yang terjadi. Semuanya tampak logis di sini - bundel berisi modul npm (mereka juga vendor) dan modul umum untuk indeks dan lainnya. Pada setiap halaman kami menyertakan 2 file dan tidak memiliki masalah.


Namun, jika kita memiliki tiga titik masuk atau lebih, maka mungkin ada lebih banyak bundel baru (mereka adalah bongkahan) dan kita tidak lagi tahu nomor atau nama mereka. Semuanya menjadi lebih menyenangkan jika kita juga mengekstraksi css ke file terpisah. Dan itu masalahnya.


Bagaimana cara mengatasi masalah ini?


Setelah menyelesaikan paket web, kami tidak memiliki file apa pun yang akan berisi informasi tentang bundel mana di halaman ini atau itu yang harus terhubung. Dan dalam urutan apa.


Namun, dalam output kita dapat menemukan baris-baris ini:


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

Sebenarnya, inilah yang hampir kita butuhkan. Yaitu webpack tahu betul bundel apa yang diperlukan untuk setiap titik masuk, tetapi untuk beberapa alasan sendiri tidak ingin berbagi informasi ini dengan kami.


Manifes tidak membantu kita di sini. Ya, kita tahu bahwa ada bundel (vendor ~ yang lain ~ index.bundle.js). Kita tahu di mana dia berada. Tapi kami tidak tahu siapa yang membutuhkannya. Yaitu manifes tidak berguna.


Kemudian saya memutuskan bahwa karena webpack mengetahui informasi yang diperlukan, itu mungkin dapat diperoleh dengan menggunakan plugin. Saya tidak menemukan yang sudah jadi dan memutuskan untuk menulis milik saya. Dan, hanya untuk menunjukkan plugin ini, saya menulis artikel ini.


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

Dalam file webpack.config. (Ts | js), tambahkan plugin baru:


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

dan tunggu hasilnya. Hasilnya akan menjadi file entrypoints.json dengan konten ini:


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

Jika ekstrak-css digunakan, maka selain bagian js juga akan ada css.


Hal terakhir yang tersisa bagi kita, ketika membentuk halaman HTML, adalah membaca file entrypoints.json, menemukan titik entri yang diinginkan, menghubungkan file js dan css dari daftar yang sesuai.


Masalah terselesaikan


Sesuatu seperti itu.

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


All Articles