Externals 配置
Externals 配置
externals 配置选项提供了一种从输出 bundle 中排除依赖项的方法。相反,创建的 bundle 会依赖该依赖项在消费者(任何最终用户应用程序)的环境中存在。此功能通常对库开发人员最有用,但也有多种应用场景。
externals
string object function RegExp [string, object, function, RegExp]
阻止打包某些 import 的包,并在运行时检索这些 外部依赖项。
例如,要从 CDN 引入 jQuery 而不是打包它:
index.html
html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"
></script>
webpack.config.js
js
export default {
// ...
externals: {
jquery: "jQuery",
},
};
这样不会改动任何依赖模块,即下面的代码仍然可以正常工作:
js
import $ from "jquery";
$(".my-element").animate(/* ... */);
上面 webpack.config.js 中 externals 下指定的属性名 jquery 表示应从打包中排除 import $ from 'jquery' 中的 jquery 模块。为了替换该模块,将使用值 jQuery 来检索全局 jQuery 变量,因为默认的外部库类型是 var,请参见 externalsType。
虽然我们上面演示了如何使用外部全局变量,但外部依赖实际上可以是以下任意一种形式:全局变量、CommonJS、AMD、ES2015 模块,详见 externalsType。
string
根据 externalsType,这可以是全局变量的名称(参见 'global'、'this'、'var'、'window'),也可以是模块的名称(参见 amd、commonjs、module、umd)。
如果你只定义一个外部依赖,也可以使用简写语法:
js
export default {
// ...
externals: "jquery",
};
等同于
js
export default {
// ...
externals: {
jquery: "jquery",
},
};
你可以使用 ${externalsType} ${libraryName} 语法为外部依赖指定 外部库类型。这将覆盖在 externalsType 选项中指定的默认外部库类型。
例如,如果外部库是一个 CommonJS 模块,你可以指定:
js
export default {
// ...
externals: {
jquery: "commonjs jquery",
},
};
[string]
js
export default {
// ...
externals: {
subtract: ["./math", "subtract"],
},
};
subtract: ['./math', 'subtract'] 允许你选择模块的一部分,其中 ./math 是模块,而你的 bundle 只需要 subtract 变量下的子集。
当 externalsType 为 commonjs 时,此示例将转换为 require('./math').subtract; 而当 externalsType 为 window 时,此示例将转换为 window["./math"]["subtract"];。
与 string 语法 类似,你可以在数组的第一项中使用 ${externalsType} ${libraryName} 语法来指定外部库类型,例如:
js
export default {
// ...
externals: {
subtract: ["commonjs ./math", "subtract"],
},
};
object
警告: 具有
{ root, amd, commonjs, ... }的对象仅允许用于libraryTarget: 'umd'和externalsType: 'umd'。它不允许用于其他库目标。
警告: 自 webpack 5.109.0 起,对于所使用的 externals 类型,如果没有对应的条目,对象形式的外部依赖会在构建时报错,而不是在运行时静默解析为
undefined。
js
export default {
// ...
// 或
externals: {
react: "react",
},
};
js
export default {
// ...
// 或
externals: {
lodash: {
commonjs: "lodash",
amd: "lodash",
root: "_", // 表示全局变量
},
},
};
js
export default {
// ...
// 或
externals: {
subtract: {
root: ["math", "subtract"],
},
},
};
此语法用于描述外部库可以被使用的所有可能方式。这里的 lodash 在 AMD 和 CommonJS 模块系统中可以作为 lodash 使用,但在全局变量形式中可以用作 _。这里的 subtract 可以通过全局 math 对象上的 subtract 属性使用(例如 window['math']['subtract'])。
interop
5.109.0+
非 ESM 外部依赖(commonjs、amd、umd 等)是动态模块:在严格的 ES 模块(带有 "type": "module" 的包)中导入它们的 default 会得到整个导出对象,而非严格导入则会通过运行时的 __esModule 检查将其解包。对象形式外部依赖上的可选 interop 提示可以固定此行为,而不受导入方的影响,类似于 Rollup 的 output.interop:
'esModule'- 将外部依赖视为 ES 模块命名空间,因此default导入会解析为其.default导出。'default'- 将外部依赖视为 CommonJS 模块,因此default导入会解析为整个导出对象(Node.js 语义)。
js
export default {
// ...
externals: {
dep: {
amd: "dep",
interop: "esModule",
},
},
};
function
function ({ context, request, contextInfo, getResolve }, callback)function ({ context, request, contextInfo, getResolve }) => promise5.15.0+
定义你自己的函数来控制 webpack 要外部化的行为可能很有用。例如,webpack-node-externals 会排除 node_modules 目录中的所有模块,并提供选项来白名单包。
该函数可以接收以下参数:
ctx(object):包含文件详细信息的对象。ctx.context(string):包含导入的文件的目录。ctx.request(string):被请求的导入路径。ctx.contextInfo(object):包含有关发起者的信息(例如 layer 和 compiler)。ctx.getResolve5.15.0+:使用当前解析器选项获取一个 resolve 函数。
callback(function (err, result, type)):用于指示模块应如何被外部化的回调函数。
回调函数接收三个参数:
err(Error):用于指示外部化导入时是否出错。如果出错,这应该是唯一使用的参数。result(string[string]object):使用其他外部格式(string、[string]或object)描述外部模块。type(string):可选参数,指示模块的 外部类型(如果尚未在result参数中指明)。
例如,要外部化所有导入路径与正则表达式匹配的导入,你可以这样做:
webpack.config.js
js
export default {
// ...
externals: [
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
// 外部化为使用请求路径的 commonjs 模块
return callback(null, `commonjs ${request}`);
}
// 继续而不外部化导入
callback();
},
],
};
使用其他模块格式的其他示例:
webpack.config.js
js
export default {
externals: [
function (ctx, callback) {
// 外部化是位于 `@scope/library` 中的 `commonjs2` 模块
callback(null, "@scope/library", "commonjs2");
},
],
};
webpack.config.js
js
export default {
externals: [
function (ctx, callback) {
// 外部化是名为 `nameOfGlobal` 的全局变量
callback(null, "nameOfGlobal");
},
],
};
webpack.config.js
js
export default {
externals: [
function (ctx, callback) {
// 外部化是 `@scope/library` 模块中的命名导出
callback(null, ["@scope/library", "namedexport"], "commonjs");
},
],
};
webpack.config.js
js
export default {
externals: [
function (ctx, callback) {
// 外部化是一个 UMD 模块
callback(null, {
root: "componentsGlobal",
commonjs: "@scope/components",
commonjs2: "@scope/components",
amd: "components",
});
},
],
};
RegExp
与给定正则表达式匹配的每个依赖项都将从输出 bundle 中排除。
webpack.config.js
js
export default {
// ...
externals: /^(jquery|\$)$/i,
};
在这种情况下,任何名为 jQuery(无论大小写)或 $ 的依赖项都将被外部化。
组合语法
有时你可能希望使用上述语法的组合。可以通过以下方式实现:
webpack.config.js
js
export default {
// ...
externals: [
{
// 字符串
react: "react",
// 对象
lodash: {
commonjs: "lodash",
amd: "lodash",
root: "_", // 表示全局变量
},
// [string]
subtract: ["./math", "subtract"],
},
// 函数
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
return callback(null, `commonjs ${request}`);
}
callback();
},
// 正则
/^(jquery|\$)$/i,
],
};
警告: 如果你指定了没有类型的
externals,例如externals: { react: 'react' }而不是externals: { react: 'commonjs-module react' },将使用 默认类型。
有关如何使用此配置的更多信息,请参阅有关 如何编写一个库 的文章。
byLayer
function object
按 layer 指定外部依赖。
webpack.config.js
js
export default {
externals: {
byLayer: {
layer: {
external1: "var 43",
},
},
},
};
externalsType
string = 'var'
指定默认的外部依赖类型。amd、umd、system 和 jsonp 外部依赖依赖于 output.libraryTarget 被设置为相同的值,例如你只能在 amd 库中使用 amd 外部依赖。
支持的类型:
'amd''amd-async'- 通过异步 AMDrequire([...])API 加载外部依赖(异步模块) 5.109.0+'amd-require''assign'- 与'var'相同'commonjs''commonjs-module''global''import'- 使用import()加载原生 ECMAScript 模块(异步模块)'jsonp''module''module-import''node-commonjs''promise'- 与'var'相同,但会等待结果(异步模块)'self''system''script''this''umd''umd2''var''window'
webpack.config.js
js
export default {
// ...
externalsType: "promise",
};
externalsType.amd-async
5.109.0+
将 externals 的默认类型设置为 'amd-async'。与 'amd' 一样,外部依赖通过 AMD 加载器解析,但它在运行时通过异步 require([...]) API 加载,并作为异步模块公开。这意味着输出 bundle 本身不需要包装在 AMD 库中(不需要匹配的 output.library.type),因此可以从任何 chunk 格式使用仅 AMD 的外部依赖。
示例
js
import _ from "lodash";
webpack.config.js
js
export default {
// ...
externalsType: "amd-async",
externals: {
lodash: "lodash",
},
};
外部模块解析为类似下面的表达式,并通过 webpack 的异步模块运行时公开:
js
new Promise((resolve, reject) => {
if (typeof require !== "function") {
reject(
new Error(
"AMD 'require' is not available to load external module lodash",
),
);
return;
}
require(["lodash"], (module) => resolve(module), reject);
});
提示: 当设置了
output.library.amdContainer时,异步require调用将针对该容器对象发出,而不是全局 AMDrequire。
externalsType.commonjs
将 externals 的默认类型设置为 'commonjs'。webpack 将为模块中使用的外部依赖生成类似 const X = require('...') 的代码。
示例
js
import fs from "fs-extra";
webpack.config.js
js
export default {
// ...
externalsType: "commonjs",
externals: {
"fs-extra": "fs-extra",
},
};
将生成类似以下的内容:
js
import fs from "fs-extra";
请注意,输出 bundle 中会有一个 require()。
externalsType.global
将 externals 的默认类型设置为 'global'。webpack 将读取 globalObject 上的一个全局变量作为外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "global",
externals: {
jquery: "$",
},
output: {
globalObject: "global",
},
};
将生成类似以下的内容:
js
const jq = globalThis.$;
jq(".my-element").animate(/* ... */);
externalsType.module
将 externals 的默认类型设置为 'module'。webpack 将为模块中使用的外部依赖生成类似 import * as X from '...' 的代码。
请确保先启用 experiments.outputModule,否则 webpack 将抛出错误。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
experiments: {
outputModule: true,
},
externalsType: "module",
externals: {
jquery: "jquery",
},
};
将生成类似以下的内容:
js
import * as __WEBPACK_EXTERNAL_MODULE_jquery__ from "jquery";
const jq = __WEBPACK_EXTERNAL_MODULE_jquery__.default;
jq(".my-element").animate(/* ... */);
请注意,输出 bundle 中会有一个 import 语句。
保留阶段关键字
5.107.0+
defer 和 source 导入阶段关键字会像 导入属性 一样保留在 module 外部依赖上。针对 module 外部依赖的静态 import defer * as ns from "mod" 会作为原生 import defer * as ... 语句输出,而 import source v from "mod" 会变为 import source ... from "mod"。使用两种不同阶段导入相同外部依赖将产生不同的 ExternalModule 实例,因此不会静默丢失任何阶段。
js
// 输入
import defer * as ns from "external-mod";
import source v from "external-mod";
// 输出(使用 externalsType: "module")
import defer * as ns from "external-mod";
import source v from "external-mod";
externalsType.import
5.94.0+
将 externals 的默认类型设置为 'import'。webpack 将为模块中使用的外部依赖生成类似 import('...') 的代码。
示例
js
async function foo() {
const jq = await import("jQuery");
jq(".my-element").animate(/* ... */);
}
webpack.config.js
js
export default {
externalsType: "import",
externals: {
jquery: "jquery",
},
};
将生成类似下面的内容:
js
const __webpack_modules__ = {
jQuery: (module) => {
module.exports = import("jQuery");
},
};
// webpack 运行时...
async function foo() {
const jq = await Promise.resolve(/* import() */).then(
__webpack_require__.bind(__webpack_require__, "jQuery"),
);
jq(".my-element").animate(/* ... */);
}
请注意,输出 bundle 中会有一个 import() 语句。
保留阶段关键字
5.107.0+
当导入函数名是默认的 "import" 时,动态的 import.defer(...) 和 import.source(...) 也会保留在 import 外部依赖上。阶段关键字会输出到结果中,而不是被剥离。
js
// 输入
const ns = await import.defer("external-mod");
const src = await import.source("external-mod");
// 输出(使用 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 将抛出错误。
示例
js
import { attempt } from "lodash";
async function foo() {
const jq = await import("jQuery");
attempt(() => jq(".my-element").animate(/* ... */));
}
webpack.config.js
js
export default {
externalsType: "module-import",
externals: {
jquery: "jquery",
lodash: "lodash",
},
};
将生成类似下面的内容:
js
import * as __WEBPACK_EXTERNAL_MODULE_lodash__ from "lodash";
const lodash = __WEBPACK_EXTERNAL_MODULE_jquery__;
const __webpack_modules__ = {
jQuery: (module) => {
module.exports = import("jQuery");
},
};
// webpack 运行时...
async function foo() {
const jq = await Promise.resolve(/* import() */).then(
__webpack_require__.bind(__webpack_require__, "jQuery"),
);
(0, lodash.attempt)(() => jq(".my-element").animate(/* ... */));
}
请注意,输出 bundle 中会有一个 import 或 import() 语句。
当模块不是通过 import 或 import() 导入时,webpack 将使用 "module" 外部类型作为回退。如果你希望使用不同类型的外部依赖作为回退,可以在 externals 选项中用函数指定。例如:
js
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 将从 'module' 导入 createRequire 来构造一个 require 函数,用于加载模块中使用的外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
module.export = {
experiments: {
outputModule: true,
},
externalsType: "node-commonjs",
externals: {
jquery: "jquery",
},
};
将生成类似以下的内容:
js
import { createRequire } from "node:module";
const jq = createRequire(import.meta.url)("jquery");
jq(".my-element").animate(/* ... */);
请注意,输出 bundle 中会有一个 import 语句。
当依赖项依赖 Node.js 内置模块或需要 CommonJS 风格的 require 函数来保留原型时,这很有用,对于 util.inherits 等函数是必需的。更多细节请参考 此问题。
对于依赖原型结构的代码,例如:
js
function ChunkStream() {
Stream.call(this);
}
util.inherits(ChunkStream, Stream);
你可以使用 node-commonjs 来确保原型链得以保留:
js
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();
},
};
这会产生类似以下的内容:
js
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 将读取一个全局变量(类似于 'var')作为外部依赖,并 await 它。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "promise",
externals: {
jquery: "$",
},
};
将生成类似以下的内容:
js
const jq = await $;
jq(".my-element").animate(/* ... */);
externalsType.self
将 externals 的默认类型设置为 'self'。webpack 将读取 self 对象上的一个全局变量作为外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "self",
externals: {
jquery: "$",
},
};
将生成类似以下的内容:
js
const jq = globalThis.$;
jq(".my-element").animate(/* ... */);
externalsType.script
将 externals 的默认类型设置为 'script'。webpack 将使用 HTML <script> 元素加载外部依赖,该元素会暴露预定义的全局变量。脚本加载完成后,<script> 标签将被移除。
语法
js
export default {
externalsType: "script",
externals: {
packageName: [
"http://example.com/script.js",
"global",
"property",
"property",
], // 属性是可选的
},
};
如果你不打算指定任何属性,也可以使用简写语法:
js
export default {
externalsType: "script",
externals: {
packageName: "global@http://example.com/script.js", // 这里没有属性
},
};
请注意,output.publicPath 不会被添加到提供的 URL 中。
示例
让我们从 CDN 加载一个 lodash:
webpack.config.js
js
export default {
// ...
externalsType: "script",
externals: {
lodash: ["https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js", "_"],
},
};
然后在代码中使用它:
js
import _ from "lodash";
console.log(_.head([1, 2, 3]));
下面是我们如何为上面的示例指定属性:
js
export default {
// ...
externalsType: "script",
externals: {
lodash: [
"https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js",
"_",
"head",
],
},
};
当你 import lodash 时,局部变量 head 和全局变量 window._ 都会被暴露:
js
import head from "lodash";
console.log(head([1, 2, 3])); // 这里输出 1
console.log(globalThis._.head(["a", "b"])); // 这里输出 a
提示: 使用 HTML
<script>标签加载代码时,webpack 运行时将尝试查找与src属性匹配的现有<script>标签,或具有特定data-webpack属性的标签。对于 chunk 加载,data-webpack属性的值为'[output.uniqueName]:chunk-[chunkId]',而外部脚本的值为'[output.uniqueName]:[global]'。
提示:
output.chunkLoadTimeout、output.crossOriginLoading和output.scriptType等选项也会对以这种方式加载的外部脚本产生影响。
警告:
externalsType: "script"使用经典(非模块)<script src="...">标签加载外部依赖。外部文件必须与经典脚本兼容(即没有顶层的import/export)。如果加载的脚本包含 ESM 语法(例如import * as b from "b.js"),浏览器将无法执行它,webpack 会报告脚本加载失败(通常会显示为ScriptExternalLoadError: Loading script failed.)。
提示: 如果你需要模块到模块的依赖,最好使用
externalsType: "import"/externalsType: "module"/externalsType: "module-import"。如果必须保留externalsType: "script",请先加载依赖并通过全局变量(例如globalThis.SomeLib)访问它们,而不是使用import。
externalsType.this
将 externals 的默认类型设置为 'this'。webpack 将读取 this 对象上的一个全局变量作为外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "this",
externals: {
jquery: "$",
},
};
将生成类似以下的内容:
js
const jq = this.$;
jq(".my-element").animate(/* ... */);
externalsType.var
将 externals 的默认类型设置为 'var'。webpack 将读取一个全局变量作为外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "var",
externals: {
jquery: "$",
},
};
将生成类似以下的内容:
js
const jq = $;
jq(".my-element").animate(/* ... */);
externalsType.window
将 externals 的默认类型设置为 'window'。webpack 将读取 window 对象上的一个全局变量作为外部依赖。
示例
js
import jq from "jquery";
jq(".my-element").animate(/* ... */);
webpack.config.js
js
export default {
// ...
externalsType: "window",
externals: {
jquery: "$",
},
};
将生成类似以下的内容:
js
const jq = globalThis.$;
jq(".my-element").animate(/* ... */);
externalsPresets
object
为特定目标启用外部依赖预设。
| 选项 | 描述 | 输入类型 |
|---|---|---|
electron |
将主进程和预加载上下文中的常见 electron 内置模块(如 electron、ipc 或 shell)视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
electronMain |
将主进程上下文中的 electron 内置模块(如 app、ipc-main 或 shell)视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
electronPreload |
将预加载上下文中的 electron 内置模块(如 web-frame、ipc-renderer 或 shell)视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
electronRenderer |
将渲染进程上下文中的 electron 内置模块(如 web-frame、ipc-renderer 或 shell)视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
node |
将 node.js 内置模块(如 fs、path 或 vm)视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
nwjs |
将 NW.js 遗留的 nw.gui 模块视为外部依赖,并在使用时通过 require() 加载。 |
boolean |
web |
将 http(s)://... 和 std:... 引用视为外部依赖,并在使用时通过 import 加载。(请注意,这会改变执行顺序,因为外部依赖会在 chunk 中的任何其他代码之前执行)。 |
boolean |
webAsync |
将 http(s)://... 和 std:... 引用视为外部依赖,并在使用时通过 async import() 加载。(请注意,此外部类型是一个 async 模块,会对执行产生各种影响)。 |
boolean |
请注意,如果你打算使用这些与 node.js 相关的预设输出 ES 模块,webpack 会将默认的 externalsType 设置为 node-commonjs,这将使用 createRequire 构造一个 require 函数,而不是使用 require()。
示例
使用 node 预设不会打包内置模块,而是将它们视为外部依赖并在使用时通过 require() 加载。
webpack.config.js
js
export default {
// ...
externalsPresets: {
node: true,
},
};
帮助我们改进文档
发现翻译问题或内容错误?请告诉我们。
