الخلفية
ليس سراً أنه مع إصدار Webpack 4 ، تغيرت إستراتيجية مشاركة التعليمات البرمجية كثيرًا. من الأفضل أن نقول أنه تم اختراعه مرة أخرى ، لأنه توقف النهج القديم للتو عن العمل ، والأسلوب الجديد ليس واضحًا كيفية استخدامه.
بالنسبة لأولئك الذين لا يزالون غير محدثين ، اختفى المكون الإضافي webpack.optimize.CommonsChunkPlugin. إطلاقا. بدلاً من ذلك ، يُقترح كتابة ما يلي في التكوين:
module.exports = {
يجب أن يعمل مثل السحر. على سبيل المثال الآن لا نخبر حزمة الويب بما يجب فعله كمجموعة شائعة ، ولكنه سيفعل كل شيء بنفسه ، وحتى أفضل منا.
وستأتي السعادة. مزحة. ليس حقا ...
الاستعدادات الأساسية
هنا مثال من الوثائق:
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' } } };
ستكون نتيجة التجميع 3 ملفات: other.bundle.js ، index.bundle.js ، البائعين ~ آخر ~ 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
الآن ، من أجل تشغيل تطبيقات الويب الخاصة بنا ، في حالة واحدة ، يجب علينا توصيل البائعين ~ آخر ~ index.bundle.js و index.bundle.js ، وفي البائعين الثاني ~ آخر ~ index.bundle.js وآخر. bundle.js.
ما هي المشكلة؟
المشكلة تكمن في أسماء البائعين ~ ~ ~ فهرس .bundle.js آخر. طالما لدينا أقل من ثلاث نقاط دخول ، لا يحدث شيء سيئ. يبدو كل شيء منطقيًا هنا - تحتوي الحزمة على وحدات npm (وهم أيضًا بائعون) ووحدات عامة للفهرس وأخرى. في كل صفحة ندرج ملفين ولا توجد مشاكل.
ومع ذلك ، إذا كان لدينا ثلاث نقاط دخول أو أكثر ، فقد يكون هناك المزيد من الحزم الجديدة (إنها قطع) ولم نعد نعرف عددهم أو أسمائهم. يصبح كل شيء أكثر متعة إذا استخرجنا أيضًا css في ملفات منفصلة. وهذه هي المشكلة.
كيف تحل هذه المشكلة؟
بعد إكمال حزمة الويب ، ليس لدينا أي ملفات تحتوي على معلومات حول الحزم في هذه الصفحة أو تلك التي يجب توصيلها. وبأي ترتيب.
ومع ذلك ، في الإخراج يمكننا العثور على هذه السطور:
Entrypoint index = vendors~another~index.bundle.js index.bundle.js Entrypoint another = vendors~another~index.bundle.js another.bundle.js
في الواقع ، هذا هو ما نحتاجه تقريبًا. على سبيل المثال تعرف webpack جيدًا ما هي الحزم اللازمة لكل نقطة دخول ، ولكن لسبب ما لا يريد مشاركة هذه المعلومات معنا.
البيان لا يساعدنا هنا. نعم ، نعلم أن هناك حزمة (بائعون ~ آخر ~ index.bundle.js). نحن نعرف أين يكذب. لكننا لا نعرف من يحتاجها. على سبيل المثال البيان غير مجدي.
ثم قررت أنه نظرًا لأن حزمة الويب تعرف المعلومات اللازمة ، فمن الممكن الحصول عليها باستخدام المكونات الإضافية. لم أجد أي شيء جاهز وقررت كتابة خاصتي. وفقط من أجل توضيح هذا البرنامج المساعد ، أنا أكتب هذا المقال.
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 }; }); } }
في ملف webpack.config. (Ts | js) ، أضف مكونًا إضافيًا جديدًا:
plugins: [ new EntrypointsPlugin({ filename: "entrypoints.json", space: 2 }) ]
وانتظر النتيجة. ستكون النتيجة ملف entrypoints.json بهذا المحتوى:
{ "index": { "js": ["vendors~another~index.bundle.js", "index.bundle.js"] }, "another": { "js": ["vendors~another~index.bundle.js", "another.bundle.js"] } }
إذا تم استخدام extract-css ، فسيكون هناك أيضًا css إلى جانب قسم js.
آخر ما تبقى لنا ، عند تكوين صفحة HTML ، هو قراءة ملف entrypoints.json ، والعثور على نقطة الدخول المطلوبة ، وربط ملفات js و css من القوائم المقابلة.
تم حل المشكلة
شيء من هذا القبيل.