إدارة المخرجات (Output Management)
حتى الآن كنا نقوم بإضافة جميع الملفات يدويًا داخل ملف index.html، لكن مع نمو التطبيق، وعند البدء في استخدام الـ hashes داخل أسماء الملفات، أو إنشاء عدة bundles، ستصبح إدارة ملف index.html يدويًا أمرًا صعبًا. لحسن الحظ، توجد بعض الـ plugins التي تجعل هذه العملية أسهل بكثير.
التحضير
لنقم أولًا بتعديل بسيط على المشروع:
project
webpack-demo
├── package.json
├── package-lock.json
├── webpack.config.js
├── /dist
├── /src
│ ├── index.js
+ │ ├── print.js
└── /node_modulesلنضف بعض المنطق إلى ملف src/print.js:
src/print.js
export default function printMe() {
console.log("I get called from print.js!");
}ثم نستخدم هذه الدالة داخل src/index.js:
src/index.js
import _ from 'lodash';
+import printMe from './print.js';
function component() {
const element = document.createElement('div');
+ const btn = document.createElement('button');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
+ btn.innerHTML = 'اضغط هنا وتحقق من الـ console!';
+ btn.onclick = printMe;
+
+ element.appendChild(btn);
+
return element;
}
document.body.appendChild(component());دعنا أيضًا نحدّث ملف dist/index.html استعدادًا لأن يقوم webpack بفصل الـ entries:
dist/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
- <title>Asset Management</title>
+ <title>إدارة المخرجات</title>
+ <script src="./print.bundle.js"></script>
</head>
<body>
- <script src="bundle.js"></script>
+ <script src="./index.bundle.js"></script>
</body>
</html>والآن لنعدّل ملف الإعدادات. سنضيف src/print.js كنقطة دخول جديدة (print) وسنغيّر طريقة إنشاء أسماء الـ bundles بحيث يتم إنشاؤها ديناميكيًا اعتمادًا على أسماء نقاط الدخول:
webpack.config.js
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
- entry: './src/index.js',
+ entry: {
+ index: './src/index.js',
+ print: './src/print.js',
+ },
output: {
- filename: 'bundle.js',
+ filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};لنقم الآن بتشغيل:
npm run buildوسنحصل على ناتج مشابه لهذا:
...
[webpack-cli] Compilation finished
asset index.bundle.js 69.5 KiB [emitted] [minimized] (name: index) 1 related asset
asset print.bundle.js 316 bytes [emitted] [minimized] (name: print)
runtime modules 1.36 KiB 7 modules
cacheable modules 530 KiB
./src/index.js 406 bytes [built] [code generated]
./src/print.js 83 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 1996 msيمكننا أن نرى أن webpack قام بإنشاء الملفين print.bundle.js و index.bundle.js، وهما الملفان اللذان قمنا بإضافتهما داخل index.html.
إذا فتحت index.html في المتصفح، يمكنك تجربة الضغط على الزر ورؤية ما يحدث.
لكن ماذا سيحدث إذا قمنا بتغيير اسم إحدى نقاط الدخول أو أضفنا نقطة دخول جديدة؟ سيقوم webpack بإعادة تسمية الملفات الناتجة أثناء البناء، لكن index.html سيبقى يشير إلى الأسماء القديمة. لحل هذه المشكلة سنستخدم HtmlWebpackPlugin.
إعداد HtmlWebpackPlugin
قم أولًا بتثبيت الـ plugin ثم عدّل ملف webpack.config.js:
npm install --save-dev html-webpack-pluginwebpack.config.js
import path from 'node:path';
import { fileURLToPath } from 'node:url';
+import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
entry: {
index: './src/index.js',
print: './src/print.js',
},
+ plugins: [
+ new HtmlWebpackPlugin({
+ title: 'Output Management',
+ }),
+ ],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};قبل تشغيل البناء، يجب أن تعرف أن HtmlWebpackPlugin يقوم افتراضيًا بإنشاء ملف index.html خاص به، حتى لو كان لدينا ملف موجود مسبقًا داخل dist/.
وهذا يعني أنه سيستبدل الملف القديم بملف جديد يتم إنشاؤه تلقائيًا.
لنقم بتشغيل:
npm run buildوسيكون الناتج مشابهًا لهذا:
...
[webpack-cli] Compilation finished
asset index.bundle.js 69.5 KiB [compared for emit] [minimized] (name: index) 1 related asset
asset print.bundle.js 316 bytes [compared for emit] [minimized] (name: print)
asset index.html 253 bytes [emitted]
runtime modules 1.36 KiB 7 modules
cacheable modules 530 KiB
./src/index.js 406 bytes [built] [code generated]
./src/print.js 83 bytes [built] [code generated]
./node_modules/lodash/lodash.js 530 KiB [built] [code generated]
webpack 5.x.x compiled successfully in 2189 msإذا فتحت index.html داخل محرر الأكواد، ستلاحظ أن HtmlWebpackPlugin قام بإنشاء ملف جديد بالكامل وأضاف جميع الـ bundles تلقائيًا.
إذا أردت معرفة المزيد عن جميع الميزات والإعدادات التي يوفرها HtmlWebpackPlugin، يمكنك زيارة مستودعه الرسمي.
تنظيف مجلد /dist
كما لاحظت في الأدلة السابقة، أصبح مجلد /dist مليئًا بالملفات القديمة.
Webpack يقوم بإنشاء الملفات داخل /dist لكنه لا يحذف الملفات القديمة غير المستخدمة تلقائيًا.
لذلك من الأفضل تنظيف مجلد /dist قبل كل عملية build حتى يبقى فقط ما يحتاجه المشروع.
يمكننا فعل ذلك باستخدام الخيار output.clean.
webpack.config.js
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default {
entry: {
index: './src/index.js',
print: './src/print.js',
},
plugins: [
new HtmlWebpackPlugin({
title: 'Output Management',
}),
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
+ clean: true,
},
};الآن قم بتشغيل:
npm run buildثم افحص مجلد /dist، وستلاحظ أن webpack قام بحذف الملفات القديمة وأبقى فقط الملفات الحالية الناتجة عن البناء.
ملف Manifest
قد تتساءل كيف يعرف webpack والـ plugins الخاصة به الملفات التي يتم إنشاؤها.
الإجابة تكمن في ملف الـ manifest الذي يحتفظ به webpack لتتبع العلاقة بين الوحدات (modules) والـ bundles الناتجة.
إذا كنت مهتمًا بإدارة output بطرق متقدمة، فإن الـ manifest يُعتبر نقطة بداية ممتازة.
يمكن استخراج بيانات الـ manifest إلى ملف JSON باستخدام ManifestPlugin.
لن نتعمق هنا في مثال كامل، لكن يمكنك قراءة صفحة manifest concept ودليل caching لمعرفة كيف يتم استخدامه مع التخزين المؤقت طويل المدى.
الخاتمة
الآن بعد أن تعلمت كيفية إضافة الـ bundles إلى HTML بشكل ديناميكي، يمكنك الانتقال إلى دليل التطوير.
أو إذا كنت ترغب في التعمق أكثر في المواضيع المتقدمة، فنوصي بالانتقال إلى دليل تقسيم الكود.



