دوال Module
يغطي هذا القسم كل الدوال المتاحة داخل الكود الذي تم تجميعه بواسطة webpack. عند استخدام webpack لتحزيم تطبيقك، يمكنك الاختيار بين عدة صيغ للـ modules، مثل ES6 وCommonJS وAMD.
رغم أن webpack يدعم عدة صيغ للـ modules، فإننا نوصي باتباع صيغة واحدة للمحافظة على الاتساق وتجنب السلوكيات الغريبة أو الأخطاء. في الواقع، يفرض webpack هذه التوصية على ملفات .mjs وملفات .cjs وملفات .js عندما يحتوي أقرب ملف package.json أب على حقل "type" بقيمة "module" أو "commonjs". انتبه لهذه القيود قبل المتابعة:
- ملفات
.mjsأو.jsمع"type": "module"فيpackage.json- لا يُسمح بـ CommonJS، مثل
requireأوmodule.exportsأوexports. - يجب كتابة امتدادات الملفات عند الاستيراد، مثل استخدام
import './src/App.mjs'بدلimport './src/App'. يمكنك تعطيل هذا القيد عبرRule.resolve.fullySpecified.
- لا يُسمح بـ CommonJS، مثل
- ملفات
.cjsأو.jsمع"type": "commonjs"فيpackage.json- لا تتوفر
importولاexport.
- لا تتوفر
- ملفات
.wasmمع"type": "module"فيpackage.json- يجب كتابة امتداد الملف عند استيراد ملف wasm.
ES6 (موصى به)
يدعم webpack 2 صيغة ES6 modules بشكل أصلي، وهذا يعني أنك تستطيع استخدام import وexport بدون أداة مثل babel للتعامل مع ذلك. مع ذلك، قد تحتاج إلى babel لميزات ES6+ الأخرى. يدعم webpack الدوال التالية:
import
يستورد exports من module آخر بشكل ثابت.
import MyModule from "./my-module.js";
import { NamedExport } from "./other-module.js";يمكنك أيضًا استيراد Data URI:
import "data:text/javascript;charset=utf-8;base64,Y29uc29sZS5sb2coJ2lubGluZSAxJyk7";
import {
fn,
number,
} from "data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==";export
صدّر أي شيء كـ default أو كتصدير مسمى.
// Named exports
export const Count = 5;
export function Multiply(a, b) {
return a * b;
}
// Default export
export default {
// Some data...
};import()
function(string path):Promise
يحمّل modules بشكل ديناميكي. يتعامل webpack مع استدعاءات import() كنقاط تقسيم، أي أن module المطلوب وأبناءه يُفصلون داخل chunk مستقل.
if (module.hot) {
import("lodash").then((_) => {
// افعل شيئًا باستخدام lodash، المعروف أيضًا باسم '_'
});
}Dynamic expressions in import()
لا يمكن استخدام عبارة import ديناميكية بالكامل مثل import(foo). السبب أن foo قد يكون أي مسار لأي ملف في نظامك أو مشروعك.
يجب أن تحتوي import() على قدر من المعلومات عن مكان module. يمكن حصر bundling في مجلد محدد أو مجموعة ملفات محددة، بحيث عند استخدام expression ديناميكي يتم تضمين كل module يمكن طلبه عبر import().
مثلًا، import(`./locale/${language}.json`) سيحزم فقط كل ملفات .json داخل مجلد ./locale ومجلداته الفرعية داخل chunk الجديد، وسيستبعد الملفات ذات الامتدادات الأخرى. وقت التشغيل، بعد حساب المتغير language، سيكون أي ملف مثل english.json أو german.json متاحًا للاستخدام.
// تخيل أن لدينا دالة لمعرفة اللغة من cookies أو تخزين آخر
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then((module) => {
// افعل شيئًا بالترجمات
});Magic Comments
عند إضافة comments إلى import، يمكننا فعل أشياء مثل تسمية chunk أو اختيار modes مختلفة. للاطلاع على القائمة الكاملة لهذه magic comments، راجع الكود أدناه ثم شرح وظيفة كل تعليق.
// هدف واحد
import(
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackExports: ["default", "named"] */
/* webpackFetchPriority: "high" */
"node:module"
);
// عدة أهداف محتملة
import(
/* webpackInclude: /\.json$/ */
/* webpackExclude: /\.noimport\.json$/ */
/* webpackChunkName: "my-chunk-name" */
/* webpackMode: "lazy" */
/* webpackPrefetch: true */
/* webpackPreload: true */
`./locale/${language}`
);
import(/* webpackIgnore: true */ "ignored-module.js");webpackIgnore
استخدام JavaScript
يعطل تحليل dynamic import عند ضبطه على true.
عند استخدام import.meta.url، لا يبقى كما هو؛ بل يُستبدل بناءً على baseURI. في modules، يُستبدل بـ new URL("./", import.meta.url)، وفي الحالات الأخرى تكون القيمة الافتراضية document.baseURI. هذا يضمن عمل relative URLs بشكل صحيح، بما يتوافق مع سياق base URL.
import(/* webpackIgnore: true */ "ignored-module.js");
new URL(/* webpackIgnore: true */ "./file1.css", import.meta.url);استخدام CSS
يمكن لتعليق webpackIgnore التحكم فيما إذا كان webpack سيعالج import أو مرجع URL محددًا.
يعمل في حالات معينة مباشرة، لكنه لا يدعم كل الحالات افتراضيًا لأسباب تتعلق بالأداء.
ندعم webpackIgnore في الحالات التالية:
@import /* webpackIgnore: false */ url(./basic.css);
.class {
color: red;
background: /* webpackIgnore: true */ url("./url/img.png");
}
.class {
background-image: image-set(
/*webpackIgnore: true*/ url(./url/img1x.png) 1x,
url(./url/img2x.png) 2x,
url(./url/img3x.png) 3x
);
}استخدام HTML
5.107.0+عند تفعيل experiments.html، يمكن وضع webpackIgnore كتعليق HTML مباشرة قبل الوسم لتجاوز حل URL لخصائص مثل src وhref وsrcset وما شابه. يُترك الوسم كما هو في HTML الصادر. هذا يعكس السلوك الذي يوفره html-loader.
<!-- webpackIgnore: true -->
<img src="https://cdn.example.com/logo.png" />
<!-- webpackIgnore: true -->
<script src="/legacy/external.js"></script>تُقرأ قيمة magic-comment بالسياق نفسه المستخدم في parsers الخاصة بـ JS وCSS؛ القيم غير boolean تصدر UnsupportedFeatureWarning.
webpackChunkName
اسم chunk الجديد. منذ webpack 2.6.0، يتم دعم placeholders [index] و[request] داخل النص المعطى، حيث تُستبدل برقم متزايد أو باسم الملف المحلول فعليًا على الترتيب. إضافة هذا التعليق تجعل chunk المنفصل يسمى [my-chunk-name].js بدل [id].js.
webpackFetchPriority
5.87.0+يضبط fetchPriority لاستيرادات ديناميكية محددة. ويمكن أيضًا ضبط قيمة افتراضية عامة لكل dynamic imports باستخدام خيار module.parser.javascript.dynamicImportFetchPriority.
import(
/* webpackFetchPriority: "high" */
"path/to/module"
);webpackMode
منذ webpack 2.6.0، يمكن تحديد modes مختلفة لحل dynamic imports. الخيارات التالية مدعومة:
'lazy'(الافتراضي): يولد chunk قابلًا للتحميل الكسول لكل module يتم استيراده عبرimport().'lazy-once': يولد chunk واحدًا قابلًا للتحميل الكسول يكفي كل استدعاءاتimport(). يتم جلب chunk عند أول استدعاء لـimport()، وتستخدم الاستدعاءات اللاحقة الاستجابة الشبكية نفسها. هذا لا يكون منطقيًا إلا في حالة عبارة ديناميكية جزئية، مثلimport(`./locales/${language}.json`)، حيث توجد عدة مسارات modules يمكن طلبها.'eager': لا يولد chunk إضافيًا. تُضمّن كل modules داخل chunk الحالي ولا تُرسل طلبات شبكة إضافية. ما زالت الدالة ترجعPromiseلكنها تكون محلولة مسبقًا. بخلاف static import، لا يُنفّذ module إلا عند استدعاءimport().'weak': يحاول تحميل module إذا كانت دالة module قد حُمّلت بطريقة أخرى، مثل أن chunk آخر استوردها أو script يحتوي على module تم تحميله. ما زالت الدالة ترجعPromise، لكنها لا تنجح إلا إذا كانت chunks موجودة بالفعل على client. إذا لم يكن module متاحًا، تُرفضPromise. لن يتم تنفيذ طلب شبكة أبدًا. هذا مفيد لـ universal rendering عندما تكون chunks المطلوبة مقدمة يدويًا دائمًا في الطلبات الأولية، مثل تضمينها داخل الصفحة، لكنه ليس مناسبًا عندما يؤدي تنقل المستخدم داخل التطبيق إلى import لم يكن مقدمًا أوليًا.
webpackPrefetch
يخبر المتصفح أن resource قد تكون مطلوبة غالبًا في تنقل مستقبلي. راجع الدليل لمزيد من المعلومات عن طريقة عمل webpackPrefetch.
webpackPreload
يخبر المتصفح أن resource قد تكون مطلوبة أثناء التنقل الحالي. راجع الدليل لمزيد من المعلومات عن طريقة عمل webpackPreload.
webpackInclude
تعبير regular expression تتم مطابقته أثناء حل import. فقط modules المطابقة سيتم حزمها.
webpackExclude
تعبير regular expression تتم مطابقته أثناء حل import. أي module يطابقه لن يتم حزمها.
webpackExports
يخبر webpack بأن يحزم فقط exports المحددة من module المستورد ديناميكيًا عبر import(). يمكن أن يقلل حجم output الخاص بـ chunk. متاح منذ webpack 5.0.0-beta.18.
CommonJS
هدف CommonJS هو تحديد منظومة JavaScript خارج المتصفح. يدعم webpack دوال CommonJS التالية:
require
require(dependency: String);يجلب exports من module آخر بشكل متزامن. سيضمن compiler توفر dependency داخل output bundle.
import $ from "jquery";
import myModule from "my-module";يمكن أيضًا تفعيل magic comments لـ require. راجع module.parser.javascript.commonjsMagicComments للمزيد.
require.resolve
require.resolve(dependency: String);يجلب ID الخاص بـ module بشكل متزامن. سيضمن compiler توفر dependency داخل output bundle. يُنصح بالتعامل معه كقيمة opaque لا تُستخدم إلا مع require.cache[id] أو __webpack_require__(id)، والأفضل تجنب هذا الاستخدام.
راجع module.id لمزيد من المعلومات.
require.cache
عدة استدعاءات require للـ module نفسه تؤدي إلى تنفيذ module مرة واحدة فقط وتصدير واحد فقط. لذلك يوجد cache في runtime. إزالة قيم من هذا cache تؤدي إلى تنفيذ جديد للـ module وتصدير جديد.
import d1 from "dependency";
// في ESM، تتم إدارة module caching تلقائيًا.
// حذف cache يدويًا كما في CommonJS غير مدعوم.
if (import.meta.webpackHot) {
import.meta.webpackHot.accept("dependency", (newModule) => {
// تعامل مع تحديث module هنا
});
}// in file.js
// في ESM، التلاعب اليدوي بالـ cache غير مدعوم.
// يتعامل webpack مع module caching داخليًا.require.ensure
require.ensure(
dependencies: String[],
callback: function(require),
errorCallback: function(error),
chunkName: String
)يفصل dependencies المحددة إلى bundle مستقل يتم تحميله بشكل غير متزامن. عند استخدام صيغة CommonJS modules، هذه هي الطريقة الوحيدة لتحميل dependencies ديناميكيًا. أي يمكن تشغيل هذا الكود أثناء التنفيذ، ولا تُحمّل dependencies إلا إذا تحققت شروط معينة.
const a = require("normal-dep");
if (module.hot) {
import("b").then(() => {
import("c").then((c) => {
// افعل شيئًا خاصًا...
});
});
}parameters التالية مدعومة بالترتيب الموضح أعلاه:
dependencies: array من strings تعلن كل modules المطلوبة لتنفيذ الكود داخلcallback.callback: دالة ينفذها webpack بعد تحميل dependencies. يتم إرسال implementation لدالةrequireكـ parameter إلى هذه الدالة. يمكن لجسم الدالة استخدامه لاستدعاءrequire()لأي modules إضافية يحتاجها للتنفيذ.errorCallback: دالة تُنفّذ عندما يفشل webpack في تحميل dependencies.chunkName: اسم يُعطى للـ chunk الذي ينشئه استدعاءrequire.ensure()هذا. عبر تمريرchunkNameنفسه لعدة استدعاءاتrequire.ensure()، يمكن دمج كودها داخل chunk واحد، مما ينتج bundle واحدًا فقط يحتاج المتصفح إلى تحميله.
AMD
Asynchronous Module Definition (AMD) هي مواصفة JavaScript تحدد واجهة لكتابة modules وتحميلها. يدعم webpack دوال AMD التالية:
define (with factory)
define([name: String], [dependencies: String[]], factoryMethod: function(...))إذا تم توفير dependencies، فسيتم استدعاء factoryMethod مع exports الخاصة بكل dependency بالترتيب نفسه. إذا لم يتم توفير dependencies، فسيتم استدعاء factoryMethod مع require وexports وmodule لأسباب توافقية. إذا أرجعت هذه الدالة قيمة، فسيتم تصدير تلك القيمة من module. يضمن compiler توفر كل dependency.
define(["jquery", "my-module"], ($, myModule) =>
// افعل شيئًا باستخدام $ وmyModule...
// صدّر دالة
function doSomething() {
// ...
});define (with value)
define(value: !Function)سيصدّر هذا value المقدمة. يمكن أن تكون value هنا أي شيء باستثناء دالة.
define({
answer: 42,
});require (amd-version)
require(dependencies: String[], [callback: function(...)])بشكل مشابه لـ require.ensure، ستُفصل dependencies المحددة إلى bundle مستقل يتم تحميله بشكل غير متزامن. سيتم استدعاء callback مع exports الخاصة بكل dependency داخل array المسماة dependencies.
import("b").then((b) => {
import("c").then((c) => {
// استخدم b و c
});
});Labeled Modules
يفعّل LabeledModulesPlugin الداخلي استخدام الدوال التالية للتصدير والطلب داخل modules:
export label
يصدّر value المحددة. يمكن أن تأتي label قبل function declaration أو variable declaration. يكون اسم الدالة أو اسم المتغير هو identifier الذي تُصدر تحته القيمة.
export: const answer = 42;
export: function method(value) {
// افعل شيئًا...
};require label
يجعل كل exports من dependency متاحة داخل النطاق الحالي. يمكن أن تظهر label الخاصة بـ require قبل string. يجب أن تصدّر dependency القيم باستخدام label الخاصة بـ export. لا يمكن استهلاك CommonJS أو AMD modules بهذه الطريقة.
some-dependency.js
export: const answer = 42;
export: function method(value) {
// افعل شيئًا...
};require: 'some-dependency';
console.log(answer);
method(...);Webpack
إلى جانب صيغ modules الموضحة أعلاه، يسمح webpack أيضًا بعدة دوال مخصصة خاصة به:
require.context
require.context(
(directory: String),
(includeSubdirs: Boolean) /* اختياري، الافتراضي true */,
(filter: RegExp) /* اختياري، الافتراضي /^\.\/.*$/ أي ملف */,
(mode: String) /* اختياري، 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once'، الافتراضي 'sync' */
);حدد مجموعة كاملة من dependencies باستخدام مسار إلى directory، وخيار includeSubdirs، وfilter للتحكم الأدق في modules المضمنة، وmode لتحديد طريقة التحميل. يمكن بعد ذلك حل modules الأساسية لاحقًا:
const context = import.meta.webpackContext("components", {
recursive: true,
regExp: /\.html$/,
});
const componentA = context.resolve("componentA");إذا تم ضبط mode على 'lazy'، فسيتم تحميل modules الأساسية بشكل غير متزامن:
const context = import.meta.webpackContext("locales", {
recursive: true,
regExp: /\.json$/,
mode: "lazy",
});
context("localeA").then((locale) => {
// افعل شيئًا باستخدام locale
});القائمة الكاملة للـ modes المتاحة وسلوكها موضحة في توثيق import().
require.include
require.include((dependency: String));يضمّن dependency بدون تنفيذه. يمكن استخدام ذلك لتحسين موضع module داخل output chunks.
import("a");
import("b");
import("c").then((moduleC) => {
// استخدم moduleC هنا
});سينتج عن ذلك output التالي:
- entry chunk:
file.jsوa. - anonymous chunk:
b. - anonymous chunk:
c.
بدون require.include('a') كان سيتم تكراره في كلا anonymous chunks.
require.resolveWeak
يشبه require.resolve، لكنه لا يسحب module إلى bundle. هذا ما يُعد dependency "ضعيفًا".
if (__webpack_modules__[require.resolveWeak("module")]) {
// افعل شيئًا عندما يكون module متاحًا...
}
if (require.cache[require.resolveWeak("module")]) {
// افعل شيئًا عندما يكون module قد حُمّل سابقًا...
}
// يمكنك تنفيذ resolves ديناميكية "context"
// بطريقة مشابهة لدوال require/import الأخرى.
const page = "Foo";
__webpack_modules__[require.resolveWeak(`./page/${page}`)];warning
إذا كان مصدر module يحتوي على require لا يمكن تحليله بشكل ثابت، فسيصدر تحذير critical dependencies.
مثال:
someFn(require);
require.bind(null);
require(variable);


