Externals

يوفر خيار التخصيص externals طريقة لاستبعاد dependencies من output bundles. بدلاً من ذلك، يعتمد bundle الذي تم إنشاؤه على dependency ليكون موجودًا في بيئة المستهلك (أي تطبيق مستخدم نهائي). عادةً ما تكون هذه الميزة مفيدة للغاية لمطوري library، ولكن هناك مجموعة متنوعة من التطبيقات لها.

externals

string object function RegExp [string, object, function, RegExp]

منع التجميع لبعض imported packages وبدلاً من ذلك قم باسترداد هذه التبعيات الخارجية في runtime.

على سبيل المثال، لتضمين jQuery من CDN بدلاً من تجميعه:

index.html

<script
  src="https://code.jquery.com/jquery-3.1.0.js"
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous"
></script>

webpack.config.js

export default {
  // ...
  externals: {
    jquery: "jQuery",
  },
};

وهذا يترك أي تابع modules دون تغيير، أي أن الكود الموضح أدناه سيظل يعمل:

import $ from "jquery";

$(".my-element").animate(/* ... */);

يشير اسم الخاصية jquery المحدد ضمن externals في webpack.config.js أعلاه إلى أنه يجب استبعاد module jquery في import $ from 'jquery' من التجميع. لاستبدال module، سيتم استخدام القيمة jQuery لاسترداد متغير jQuery عام، حيث أن النوع الافتراضي external library هو var، راجع externalsType.

بينما أظهرنا مثالًا يستهلك external global variable أعلاه، يمكن أن يكون external متاحًا فعليًا في أي من هذه النماذج: global variable، CommonJS، AMD، ES2015 Module، راجع المزيد في externalsType.

string

اعتمادًا على externalsType، يمكن أن يكون هذا اسم global variable (راجع 'global'، 'this'، 'var'، 'window') أو اسم module (راجع amd، commonjs، module، umd).

يمكنك أيضًا استخدام صيغة الاختصار إذا كنت تحدد 1 external فقط:

export default {
  // ...
  externals: "jquery",
};

يساوي

export default {
  // ...
  externals: {
    jquery: "jquery",
  },
};

يمكنك تحديد external library النوع إلى external باستخدام بناء الجملة ${externalsType} ${libraryName}. وسوف يتجاوز النوع الافتراضي external library المحدد في الخيار externalsType.

على سبيل المثال، إذا كان external library هو CommonJS module، فيمكنك تحديد

export default {
  // ...
  externals: {
    jquery: "commonjs jquery",
  },
};

[string]

export default {
  // ...
  externals: {
    subtract: ["./math", "subtract"],
  },
};

subtract: ['./math', 'subtract'] يسمح لك بتحديد جزء من module، حيث ./math هو module وbundle الخاص بك يتطلب فقط المجموعة الفرعية ضمن المتغير subtract.

عندما يكون externalsType هو commonjs، سيترجم هذا المثال إلى require('./math').subtract; بينما عندما يكون externalsType هو window، سيترجم هذا المثال إلى window["./math"]["subtract"];

على غرار بناء الجملة string، يمكنك تحديد النوع external library باستخدام بناء الجملة ${externalsType} ${libraryName}، في العنصر الأول من array، على سبيل المثال:

export default {
  // ...
  externals: {
    subtract: ["commonjs ./math", "subtract"],
  },
};

object

export default {
  // ...
  // or
  externals: {
    react: "react",
  },
};
export default {
  // ...
  // or
  externals: {
    lodash: {
      commonjs: "lodash",
      amd: "lodash",
      root: "_", // indicates global variable
    },
  },
};
export default {
  // ...
  // or
  externals: {
    subtract: {
      root: ["math", "subtract"],
    },
  },
};

يتم استخدام بناء الجملة هذا لوصف جميع الطرق الممكنة لتوفير external library. lodash هنا متاح كـ lodash ضمن أنظمة AMD وCommonJS module ولكنه متاح كـ _ في شكل متغير عام. subtract هنا متاح عبر الخاصية subtract ضمن math object (على سبيل المثال window['math']['subtract']).

function

  • function ({ context, request, contextInfo, getResolve }, callback)
  • function ({ context, request, contextInfo, getResolve }) => promise 5.15.0+

قد يكون من المفيد تحديد function الخاص بك للتحكم في سلوك ما تريد إخراجه من webpack. على سبيل المثال، يستبعد webpack-node-externals جميع modules من الدليل node_modules ويوفر خيارات للقائمة المسموح بها packages.

فيما يلي الوسائط التي يمكن أن يستقبلها function:

  • ctx (object): Object يحتوي على تفاصيل الملف.
    • ctx.context (string): دليل الملف الذي يحتوي على الاستيراد.
    • ctx.request (string): مسار الاستيراد المطلوب.
    • ctx.contextInfo (object): يحتوي على معلومات حول جهة الإصدار (على سبيل المثال، الطبقة وcompiler)
    • ctx.getResolve 5.15.0+: احصل على resolve function مع خيارات resolver الحالية.
  • callback (function (err, result, type)): رد الاتصال function يستخدم للإشارة إلى كيفية module يجب أن يتم إضفاء الطابع الخارجي عليها.

يأخذ رد الاتصال function ثلاث وسائط:

  • err (Error): يُستخدم للإشارة إلى ما إذا كان هناك خطأ أثناء تنفيذ الاستيراد خارجيًا. إذا كان هناك خطأ، فيجب أن تكون هذه هي المعلمة الوحيدة المستخدمة.
  • result (string [string] object): يصف external module مع تنسيقات external الأخرى (string، [string]، أو object)
  • type (string): معلمة اختيارية تشير إلى module نوع external (إذا لم تتم الإشارة إليها بالفعل في المعلمة result).

على سبيل المثال، لإضفاء الطابع الخارجي على جميع عمليات الاستيراد حيث يتطابق مسار الاستيراد مع تعبير عادي، يمكنك القيام بما يلي:

webpack.config.js

export default {
  // ...
  externals: [
    function ({ context, request }, callback) {
      if (/^yourregex$/.test(request)) {
        // إضفاء الطابع الخارجي على Commonjs module باستخدام مسار الطلب
        return callback(null, `commonjs ${request}`);
      }

      // استمر دون الاستعانة بمصادر خارجية للاستيراد
      callback();
    },
  ],
};

أمثلة أخرى تستخدم تنسيقات module مختلفة:

webpack.config.js

export default {
  externals: [
    function (ctx, callback) {
      // external هو `commonjs2` module يقع في `@scope/library`
      callback(null, "@scope/library", "commonjs2");
    },
  ],
};

webpack.config.js

export default {
  externals: [
    function (ctx, callback) {
      // external هو متغير عام يسمى `nameOfGlobal`.
      callback(null, "nameOfGlobal");
    },
  ],
};

webpack.config.js

export default {
  externals: [
    function (ctx, callback) {
      // external عبارة عن تصدير مسمى في `@scope/library` module.
      callback(null, ["@scope/library", "namedexport"], "commonjs");
    },
  ],
};

webpack.config.js

export default {
  externals: [
    function (ctx, callback) {
      // external هو UMD module
      callback(null, {
        root: "componentsGlobal",
        commonjs: "@scope/components",
        commonjs2: "@scope/components",
        amd: "components",
      });
    },
  ],
};

RegExp

سيتم استبعاد كل dependency الذي يطابق التعبير العادي المحدد من output bundles.

webpack.config.js

export default {
  // ...
  externals: /^(jquery|\$)$/i,
};

في هذه الحالة، أي dependency مسمى jQuery، سواء كان مكتوبًا بأحرف كبيرة أم لا، أو في هذه الحالة، أي dependency مسمى jQuery`، سواء كان مكتوبًا بأحرف كبيرة أم لا، أو سيتم إضفاء الطابع الخارجي عليه.

الجمع بين النحو

في بعض الأحيان قد ترغب في استخدام مجموعة من بناء الجملة أعلاه. ويمكن القيام بذلك بالطريقة التالية:

webpack.config.js

export default {
  // ...
  externals: [
    {
      // String
      react: "react",
      // Object
      lodash: {
        commonjs: "lodash",
        amd: "lodash",
        root: "_", // indicates global variable
      },
      // [string]
      subtract: ["./math", "subtract"],
    },
    // Function
    function ({ context, request }, callback) {
      if (/^yourregex$/.test(request)) {
        return callback(null, `commonjs ${request}`);
      }
      callback();
    },
    // التعبير العادي
    /^(jquery|\$)$/i,
  ],
};

لمزيد من المعلومات حول كيفية استخدام هذا التخصيص، يرجى الرجوع إلى المقالة حول كيفية تأليف library.

byLayer

function object

حدد externals حسب الطبقة.

webpack.config.js

export default {
  externals: {
    byLayer: {
      layer: {
        external1: "var 43",
      },
    },
  },
};

ExternalsType

string = 'var'

حدد النوع الافتراضي لـ externals. amd، umd، system و jsonp externals تعتمد على output.libraryTarget التي تم ضبطها على نفس القيمة على سبيل المثال، يمكنك فقط استهلاك amd externals داخل amd library.

الأنواع المدعومة:

webpack.config.js

export default {
  // ...
  externalsType: "promise",
};

externalsType.commonjs

حدد النوع الافتراضي لـ externals كـ 'commonjs'. سيقوم webpack بإنشاء رمز مثل const X = require('...') لـ externals المستخدم في module.

مثال

import fs from "fs-extra";

webpack.config.js

export default {
  // ...
  externalsType: "commonjs",
  externals: {
    "fs-extra": "fs-extra",
  },
};

سوف تولد إلى شيء مثل:

import fs from "fs-extra";

لاحظ أنه سيكون هناك require() في output bundle.

externalsType.global

حدد النوع الافتراضي لـ externals كـ 'global'. webpack سوف يقرأ external كمتغير عام على globalObject.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "global",
  externals: {
    jquery: "$",
  },
  output: {
    globalObject: "global",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = globalThis.$;

jq(".my-element").animate(/* ... */);

externalsType.module

حدد النوع الافتراضي لـ externals كـ 'module'. سيقوم webpack بإنشاء رمز مثل import * as X from '...' لـ externals المستخدم في module.

تأكد من تمكين experiments.outputModule أولاً، وإلا فإن webpack سوف يؤدي إلى حدوث أخطاء.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  experiments: {
    outputModule: true,
  },
  externalsType: "module",
  externals: {
    jquery: "jquery",
  },
};

سوف تولد في شيء من هذا القبيل

import * as __WEBPACK_EXTERNAL_MODULE_jquery__ from "jquery";

const jq = __WEBPACK_EXTERNAL_MODULE_jquery__.default;
jq(".my-element").animate(/* ... */);

لاحظ أنه سيكون هناك عبارة import في output bundle.

Preserving phase keywords

5.107.0+

The defer and source import phase keywords are preserved on module externals the same way import attributes are. A static import defer * as ns from "mod" against a module external is emitted as a native import defer * as ... statement, and import source v from "mod" becomes import source ... from "mod". The same external imported with two different phases produces distinct ExternalModule instances, so neither phase is silently dropped.

// input
import defer * as ns from "external-mod";
import source v from "external-mod";

// emitted output (with externalsType: "module")
import defer * as ns from "external-mod";
import source v from "external-mod";

externalsType.import

5.94.0+

حدد النوع الافتراضي لـ externals كـ 'import'. سيقوم webpack بإنشاء رمز مثل import('...') لـ externals المستخدم في module.

مثال

async function foo() {
  const jq = await import("jQuery");
  jq(".my-element").animate(/* ... */);
}

webpack.config.js

export default {
  externalsType: "import",
  externals: {
    jquery: "jquery",
  },
};

سوف تولد شيئا مثل أدناه:

const __webpack_modules__ = {
  jQuery: (module) => {
    module.exports = import("jQuery");
  },
};

// webpack runtime...

async function foo() {
  const jq = await Promise.resolve(/* import() */).then(
    __webpack_require__.bind(__webpack_require__, "jQuery"),
  );
  jq(".my-element").animate(/* ... */);
}

لاحظ أن output bundle سيحتوي على عبارة import().

Preserving phase keywords

5.107.0+

Dynamic import.defer(...) and import.source(...) are also preserved on import externals when the import function name is the default "import". The phase keyword is emitted in the output instead of being stripped.

// input
const ns = await import.defer("external-mod");
const src = await import.source("external-mod");

// emitted output (with externalsType: "import")
const ns = await import.defer("external-mod");
const src = await import.source("external-mod");

externalsType.module-import

5.94.0+

حدد النوع الافتراضي لـ externals كـ 'module-import'. يجمع هذا بين 'module' و'import'. سيكتشف webpack تلقائيًا نوع صيغة الاستيراد، ويضبطه على 'module' للواردات الثابتة و'import' للواردات الديناميكية.

تأكد من تمكين experiments.outputModule أولاً في حالة وجود عمليات استيراد ثابتة، وإلا فسيؤدي webpack إلى ظهور أخطاء.

مثال

import { attempt } from "lodash";

async function foo() {
  const jq = await import("jQuery");
  attempt(() => jq(".my-element").animate(/* ... */));
}

webpack.config.js

export default {
  externalsType: "module-import",
  externals: {
    jquery: "jquery",
    lodash: "lodash",
  },
};

سوف تولد شيئا مثل أدناه:

import * as __WEBPACK_EXTERNAL_MODULE_lodash__ from "lodash";

const lodash = __WEBPACK_EXTERNAL_MODULE_jquery__;

const __webpack_modules__ = {
  jQuery: (module) => {
    module.exports = import("jQuery");
  },
};

// webpack runtime...

async function foo() {
  const jq = await Promise.resolve(/* import() */).then(
    __webpack_require__.bind(__webpack_require__, "jQuery"),
  );
  (0, lodash.attempt)(() => jq(".my-element").animate(/* ... */));
}

لاحظ أن output bundle سيحتوي على عبارة import أو import().

عندما لا يتم استيراد module عبر import أو import()، فإن webpack سيستخدم النوع "module" externals كبديل. إذا كنت تريد استخدام نوع مختلف من externals كبديل، يمكنك تحديده باستخدام function في الخيار externals. على سبيل المثال:

export default {
  externalsType: "module-import",
  externals: [
    function ({ request, dependencyType }, callback) {
      if (dependencyType === "commonjs") {
        return callback(null, `node-commonjs ${request}`);
      }
      callback();
    },
  ],
};

externalsType.node-commonjs

حدد النوع الافتراضي لـ externals كـ 'node-commonjs'. سوف يقوم webpack باستيراد createRequire من 'module' لإنشاء طلب function للتحميل externals المستخدم في module.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

module.export = {
  experiments: {
    outputModule: true,
  },
  externalsType: "node-commonjs",
  externals: {
    jquery: "jquery",
  },
};

سوف تولد في شيء من هذا القبيل

import { createRequire } from "node:module";

const jq = createRequire(import.meta.url)("jquery");
jq(".my-element").animate(/* ... */);

لاحظ أنه سيكون هناك عبارة import في output bundle.

يكون هذا مفيدًا عندما يعتمد dependencies على Node.js المضمن modules أو يتطلب نمط CommonJS require function للحفاظ على النماذج الأولية، وهو أمر ضروري لوظائف مثل util.inherits. راجع هذه المشكلة لمزيد من التفاصيل.

بالنسبة للتعليمات البرمجية التي تعتمد على بنيات النموذج الأولي، مثل:

function ChunkStream() {
  Stream.call(this);
}
util.inherits(ChunkStream, Stream);

يمكنك استخدام node-commonjs لضمان الحفاظ على سلسلة النموذج الأولي:

const { builtinModules } = require("node:module");

export default {
  experiments: { outputModule: true },
  externalsType: "node-commonjs",
  externals: ({ request }, callback) => {
    if (request.startsWith("node:") || builtinModules.includes(request)) {
      return callback(null, `node-commonjs ${request}`);
    }
    callback();
  },
};

وهذا ينتج شيئًا مثل:

import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "node:module";

const __webpack_modules__ = {
  // ...
  /***/ 2613: /***/ (module) => {
    module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)(
      "stream",
    );

    /***/
  },
  // ...
};

يحافظ هذا الإعداد على بنية النموذج الأولي سليمة، مما يؤدي إلى حل مشكلات Node.js المضمنة.

externalsType.promise

حدد النوع الافتراضي لـ externals كـ 'promise'. webpack سوف يقرأ external كمتغير عام (مشابه لـ 'var') وawait له.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "promise",
  externals: {
    jquery: "$",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = await $;

jq(".my-element").animate(/* ... */);

externalsType.self

حدد النوع الافتراضي لـ externals كـ 'self'. webpack سوف يقرأ external كمتغير عام على self object.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "self",
  externals: {
    jquery: "$",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = globalThis.$;

jq(".my-element").animate(/* ... */);

externalsType.script

حدّد النوع الافتراضي لـ externals كـ 'script'. سيحمّل webpack الـ external بوصفه script يعرّض global variables محددة مسبقًا عبر عنصر HTML <script>. وتُزال علامة <script> بعد تحميل script.

بناء الجملة

export default {
  externalsType: "script",
  externals: {
    packageName: [
      "http://example.com/script.js",
      "global",
      "property",
      "property",
    ], // properties are optional
  },
};

يمكنك أيضًا استخدام صيغة الاختصار إذا كنت لن تحدد أي خصائص:

export default {
  externalsType: "script",
  externals: {
    packageName: "global@http://example.com/script.js", // no properties here
  },
};

لاحظ أنه لن تتم إضافة output.publicPath إلى عنوان URL المقدم.

مثال

لنقم بتحميل lodash من CDN:

webpack.config.js

export default {
  // ...
  externalsType: "script",
  externals: {
    lodash: ["https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js", "_"],
  },
};

ثم استخدمه في الكود:

import _ from "lodash";

console.log(_.head([1, 2, 3]));

إليك كيفية تحديد خصائص المثال أعلاه:

export default {
  // ...
  externalsType: "script",
  externals: {
    lodash: [
      "https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js",
      "_",
      "head",
    ],
  },
};

سيتم عرض كل من المتغير المحلي head وglobal variable window._ عندما تقوم import lodash:

import head from "lodash";

console.log(head([1, 2, 3])); // logs 1 here
console.log(globalThis._.head(["a", "b"])); // logs a here

externalsType.this

حدد النوع الافتراضي لـ externals كـ 'this'. webpack سوف يقرأ external كمتغير عام على this object.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "this",
  externals: {
    jquery: "$",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = this.$;

jq(".my-element").animate(/* ... */);

externalsType.var

حدد النوع الافتراضي لـ externals كـ 'var'. webpack سوف يقرأ external كمتغير عام.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "var",
  externals: {
    jquery: "$",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = $;

jq(".my-element").animate(/* ... */);

externalsType.window

حدد النوع الافتراضي لـ externals كـ 'window'. webpack سوف يقرأ external كمتغير عام على window object.

مثال

import jq from "jquery";

jq(".my-element").animate(/* ... */);

webpack.config.js

export default {
  // ...
  externalsType: "window",
  externals: {
    jquery: "$",
  },
};

سوف تولد في شيء من هذا القبيل

const jq = globalThis.$;

jq(".my-element").animate(/* ... */);

ExternalsPresets

object

تمكين الإعدادات المسبقة لـ externals لـ targets محدد.

الخيارالوصفنوع الإدخال
electronتعامل مع الإلكترون المشترك المدمج modules في السياق الرئيسي وسياق التحميل المسبق مثل electron أو ipc أو shell كـ external وقم بتحميلها عبر require() عند الاستخدام.boolean
electronMainتعامل مع الإلكترون المدمج modules في السياق الرئيسي مثل app أو ipc-main أو shell كـ external وقم بتحميلها عبر require() عند استخدامها.boolean
electronPreloadتعامل مع الإلكترون المدمج modules في سياق التحميل المسبق مثل web-frame أو ipc-renderer أو shell كـ external وقم بتحميلها عبر require() عند استخدامها.boolean
electronRendererتعامل مع الإلكترون المدمج modules في سياق العارض مثل web-frame أو ipc-renderer أو shell كـ external وقم بتحميلها عبر require() عند استخدامها.boolean
nodeتعامل مع Node.js المضمنة modules مثل fs أو path أو vm كـ external وقم بتحميلها عبر require() عند استخدامها.boolean
nwjsتعامل مع NW.js القديم nw.gui module كـ external وقم بتحميله عبر require() عند الاستخدام.boolean
webتعامل مع الإشارات إلى http(s)://... وstd:... على أنها external وقم بتحميلها عبر import عند استخدامها. (لاحظ أن هذا يغير ترتيب التنفيذ حيث يتم تنفيذ externals قبل أي كود آخر في chunk).boolean
webAsyncتعامل مع المراجع إلى http(s)://... وstd:... على أنها external وقم بتحميلها عبر async import() عند استخدامها (لاحظ أن هذا النوع external هو async module، والذي له تأثيرات مختلفة على التنفيذ).boolean

لاحظ أنه إذا كنت ستنتقل إلى output ES Modules مع تلك الإعدادات المسبقة المرتبطة بـnode.js، فإن webpack سيعين الإعداد الافتراضي externalsType إلى node-commonjs والذي سيستخدم createRequire لإنشاء طلب function بدلاً من استخدام require().

Example

لن يؤدي استخدام الإعداد المسبق node إلى bundle المدمج في modules ويعاملها على أنها external ويقوم بتحميلها عبر require() عند الاستخدام.

webpack.config.js

export default {
  // ...
  externalsPresets: {
    node: true,
  },
};
Edit this page·

1 Contributor

RlxChap2