تأليف المكتبات
إلى جانب التطبيقات، يمكن استخدام webpack أيضًا لتجميع مكتبات JavaScript. هذا الدليل موجه لمؤلفي المكتبات الذين يريدون تبسيط استراتيجية التجميع لديهم.
تأليف مكتبة
لنفترض أننا نكتب مكتبة صغيرة باسم webpack-numbers تتيح للمستخدمين تحويل الأرقام من 1 إلى 5 من تمثيلها الرقمي إلى تمثيل نصي والعكس، مثل تحويل 2 إلى 'two'.
ستبدو بنية المشروع الأساسية هكذا:
project
+ ├── webpack.config.js
+ ├── package.json
+ └── /src
+ ├── index.js
+ └── ref.jsonقم بتهيئة المشروع باستخدام npm، ثم ثبّت webpack وwebpack-cli وlodash كتبِعيات تطوير:
npm init -y
npm install --save-dev webpack webpack-cli lodashنثبّت lodash كـ devDependency لأننا سنقوم في البداية بتجميعها داخل مكتبتنا. وبما أنها ستكون مضمنة في المخرج النهائي، فلن يحتاج مستهلكو مكتبتنا إلى تثبيتها بأنفسهم.
src/ref.json
[
{
"num": 1,
"word": "One"
},
{
"num": 2,
"word": "Two"
},
{
"num": 3,
"word": "Three"
},
{
"num": 4,
"word": "Four"
},
{
"num": 5,
"word": "Five"
},
{
"num": 0,
"word": "Zero"
}
]src/index.js
import _ from "lodash";
import numRef from "./ref.json";
export function numToWord(num) {
return _.reduce(
numRef,
(accum, ref) => (ref.num === num ? ref.word : accum),
"",
);
}
export function wordToNum(word) {
return _.reduce(
numRef,
(accum, ref) => (ref.word === word && word.toLowerCase() ? ref.num : accum),
-1,
);
}إعدادات Webpack
لنبدأ بإعداد webpack الأساسي التالي:
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",
output: {
path: path.resolve(__dirname, "dist"),
filename: "webpack-numbers.js",
},
};في المثال أعلاه، نخبر webpack بتجميع src/index.js داخل dist/webpack-numbers.js.
إضافة Source Maps
عند تجميع مكتبة، يوصى بتوليد source maps. تسمح source maps لمستهلكي مكتبتك بتصحيح الكود المصدري الأصلي بدلًا من الحزمة المصغّرة. يمكن فعل ذلك باستخدام خيار devtool:
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',
+ devtool: 'source-map',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
},
};كشف المكتبة
حتى الآن، يجب أن يكون كل شيء مشابهًا لتجميع تطبيق، وهنا يأتي الجزء المختلف: نحتاج إلى كشف الصادرات من نقطة الدخول عبر خيار output.library.
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',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
+ library: 'webpackNumbers',
},
};كشفنا نقطة الدخول باسم webpackNumbers حتى يتمكن المستخدمون من استخدامها عبر وسم script:
<script src="https://example.org/webpack-numbers.js"></script>
<script>
window.webpackNumbers.wordToNum("Five");
</script>لكن هذا يعمل فقط عند الإشارة إليها عبر وسم script، ولا يمكن استخدامها في بيئات أخرى مثل CommonJS أو AMD أو Node.js وغيرها.
بصفتنا مؤلفي مكتبة، نريدها أن تكون متوافقة مع بيئات مختلفة، أي يجب أن يتمكن المستخدمون من استهلاك المكتبة المجمعة بعدة طرق كما يلي:
-
استدعاء وحدة CommonJS عبر require:
const webpackNumbers = require("webpack-numbers"); // ... webpackNumbers.wordToNum("Two"); -
استدعاء وحدة AMD عبر require:
require(["webpackNumbers"], (webpackNumbers) => { // ... webpackNumbers.wordToNum("Two"); }); -
وسم script:
<!DOCTYPE html> <html> ... <script src="https://example.org/webpack-numbers.js"></script> <script> // ... // متغير عام webpackNumbers.wordToNum("Five"); // خاصية في كائن window window.webpackNumbers.wordToNum("Five"); // ... </script> </html>
لنحدّث خيار output.library مع ضبط type الخاص به على 'umd':
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',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
- library: 'webpackNumbers',
+ globalObject: 'this',
+ library: {
+ name: 'webpackNumbers',
+ type: 'umd',
+ },
},
};الآن سيجمع webpack مكتبة يمكنها العمل مع CommonJS وAMD ووسم script.
جعل Lodash خارجية
الآن، إذا شغّلت npx webpack، فستجد أنه تم إنشاء حزمة كبيرة نسبيًا. وإذا فحصت الملف، سترى أن lodash جُمّعت مع كودك. لتجنب تجميع lodash وتضخيم مكتبتنا، يمكننا إعداد webpack للتعامل معها كوحدة خارجية. وبما أننا لم نعد نجمعها، سيحتاج المستهلك إلى توفيرها. لذلك، يجب نقل lodash من devDependencies إلى dependencies (أو peerDependencies) حتى تثبّتها مديري الحزم تلقائيًا لمستهلكي مكتبتك.
يمكن فعل ذلك باستخدام إعداد externals:
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',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
library: {
name: 'webpackNumbers',
type: 'umd',
},
},
+ externals: {
+ lodash: {
+ commonjs: 'lodash',
+ commonjs2: 'lodash',
+ amd: 'lodash',
+ root: '_',
+ },
+ },
};هذا يعني أن مكتبتك تتوقع توفر تبعية باسم lodash في بيئة المستهلك.
قيود الوحدات الخارجية
بالنسبة إلى المكتبات التي تستخدم عدة ملفات من تبعية:
import A from "library/one";
import B from "library/two";
// ...لن تتمكن من استبعادها من الحزمة بتحديد library في externals. ستحتاج إما إلى استبعادها واحدة تلو الأخرى أو استخدام تعبير منتظم.
export default {
// ...
externals: [
"library/one",
"library/two",
// كل ما يبدأ بـ "library/"
/^library\/.+$/,
],
};الخطوات النهائية
حسّن مخرجاتك للإنتاج باتباع الخطوات المذكورة في دليل الإنتاج. ولنضف أيضًا مسار الحزمة المولّدة إلى حقل main الخاص بالحزمة داخل package.json:
package.json
{
...
"main": "dist/webpack-numbers.js",
...
}أو لإضافتها كوحدة قياسية وفقًا لـ هذا الدليل:
{
...
"module": "src/index.js",
...
}يشير المفتاح main إلى المعيار من package.json، بينما يشير module إلى اقتراح آخر للسماح لمنظومة JavaScript بالترقية لاستخدام وحدات ES2015 دون كسر التوافق مع الإصدارات السابقة.
يمكنك الآن نشرها كحزمة npm والعثور عليها في unpkg.com لتوزيعها على المستخدمين.



