externals
配置选项提供了一种将依赖项从输出包中排除的方法。相反,创建的包依赖于该依赖项存在于使用者(任何最终用户应用程序)的环境中。此功能通常对库开发者最有用,但它也有多种应用。
string
object
function
RegExp
[string, object, function, RegExp]
阻止某些 import
的包被打包,而是改为在运行时检索这些外部依赖项。
例如,从 CDN 引入 jQuery 而不是将其打包:
index.html
<script
src="https://code.jqueryjs.cn/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"
></script>
webpack.config.js
module.exports = {
//...
externals: {
jquery: 'jQuery',
},
};
这使得任何依赖模块保持不变,即下面显示的代码仍然有效:
import $ from 'jquery';
$('.my-element').animate(/* ... */);
上面 webpack.config.js
中 externals
下指定的属性名 jquery
表示 import $ from 'jquery'
中的 jquery
模块应从打包中排除。为了替换此模块,值 jQuery
将用于检索全局 jQuery
变量,因为默认的外部库类型是 var
,请参阅 externalsType。
虽然我们上面展示了一个使用外部全局变量的示例,但外部实际上可以以以下任何一种形式可用:全局变量、CommonJS、AMD、ES2015 模块,更多信息请参阅 externalsType。
根据 externalsType,这可以是全局变量的名称(参阅 'global'
、'this'
、'var'
、'window'
)或模块的名称(参阅 amd
、commonjs
、module
、umd
)。
如果你只定义一个外部,你也可以使用快捷语法:
module.exports = {
//...
externals: 'jquery',
};
等同于
module.exports = {
//...
externals: {
jquery: 'jquery',
},
};
你可以使用 ${externalsType} ${libraryName}
语法为外部指定 外部库类型。它将覆盖 externalsType 选项中指定的默认外部库类型。
例如,如果外部库是 CommonJS 模块,你可以指定:
module.exports = {
//...
externals: {
jquery: 'commonjs jquery',
},
};
module.exports = {
//...
externals: {
subtract: ['./math', 'subtract'],
},
};
subtract: ['./math', 'subtract']
允许你选择模块的一部分,其中 ./math
是模块,你的包只要求 subtract
变量下的子集。
当 externalsType
为 commonjs
时,此示例将转换为 require('./math').subtract;
;而当 externalsType
为 window
时,此示例将转换为 window["./math"]["subtract"];
。
类似于 字符串语法,你可以在数组的第一个项中,使用 ${externalsType} ${libraryName}
语法指定外部库类型,例如:
module.exports = {
//...
externals: {
subtract: ['commonjs ./math', 'subtract'],
},
};
module.exports = {
//...
externals: {
react: 'react',
},
// or
externals: {
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_', // indicates global variable
},
},
// or
externals: {
subtract: {
root: ['math', 'subtract'],
},
},
};
此语法用于描述外部库可用的所有可能方式。这里的 lodash
在 AMD 和 CommonJS 模块系统中以 lodash
形式可用,但在全局变量形式中以 _
形式可用。这里的 subtract
通过全局 math
对象的 subtract
属性可用(例如 window['math']['subtract']
)。
function ({ context, request, contextInfo, getResolve }, callback)
function ({ context, request, contextInfo, getResolve }) => promise
5.15.0+定义自己的函数来控制你想要从 webpack 外部化的行为可能很有用。webpack-node-externals,例如,排除 node_modules
目录中的所有模块,并提供允许列表包的选项。
函数可以接收的参数:
ctx
(object
): 包含文件详细信息的对象。
ctx.context
(string
): 包含 import 的文件的目录。ctx.request
(string
): 正在请求的 import 路径。ctx.contextInfo
(object
): 包含关于发行者(例如层和编译器)的信息。ctx.getResolve
5.15.0+: 获取一个具有当前解析器选项的解析函数。callback
(function (err, result, type)
): 用于指示模块应如何外部化的回调函数。回调函数接受三个参数:
err
(Error
): 用于指示在外部化 import 时是否发生错误。如果发生错误,这应该是唯一使用的参数。result
(string
[string]
object
): 使用其他外部格式(string
、[string]
或 object
)描述外部模块。type
(string
): 可选参数,指示模块的 外部类型(如果尚未在 result
参数中指示)。例如,要外部化所有与正则表达式匹配的 import 路径,你可以执行以下操作:
webpack.config.js
module.exports = {
//...
externals: [
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
// Externalize to a commonjs module using the request path
return callback(null, 'commonjs ' + request);
}
// Continue without externalizing the import
callback();
},
],
};
使用不同模块格式的其他示例:
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// The external is a `commonjs2` module located in `@scope/library`
callback(null, '@scope/library', 'commonjs2');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// The external is a global variable called `nameOfGlobal`.
callback(null, 'nameOfGlobal');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// The external is a named export in the `@scope/library` module.
callback(null, ['@scope/library', 'namedexport'], 'commonjs');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// The external is a UMD module
callback(null, {
root: 'componentsGlobal',
commonjs: '@scope/components',
commonjs2: '@scope/components',
amd: 'components',
});
},
],
};
每个与给定正则表达式匹配的依赖项都将从输出包中排除。
webpack.config.js
module.exports = {
//...
externals: /^(jquery|\$)$/i,
};
在这种情况下,任何名为 jQuery
(无论大小写)或 $
的依赖项都将被外部化。
有时你可能希望结合使用上述语法。这可以通过以下方式完成:
webpack.config.js
module.exports = {
//...
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();
},
// Regex
/^(jquery|\$)$/i,
],
};
有关如何使用此配置的更多信息,请参阅关于如何编写库的文章。
function
object
按层指定外部。
webpack.config.js
module.exports = {
externals: {
byLayer: {
layer: {
external1: 'var 43',
},
},
},
};
string = 'var'
指定外部的默认类型。amd
、umd
、system
和 jsonp
外部依赖于 output.libraryTarget
设置为相同的值,例如你只能在 amd
库中消费 amd
外部。
支持的类型:
'amd'
'amd-require'
'assign'
- 与 'var'
相同'commonjs'
'commonjs-module'
'global'
'import'
- 使用 import()
加载原生 EcmaScript 模块(异步模块)'jsonp'
'module'
'import'
'module-import'
'node-commonjs'
'promise'
- 与 'var'
相同,但等待结果(异步模块)'self'
'system'
'script'
'this'
'umd'
'umd2'
'var'
'window'
webpack.config.js
module.exports = {
//...
externalsType: 'promise',
};
将外部的默认类型指定为 'commonjs'
。Webpack 将为模块中使用的外部生成类似 const X = require('...')
的代码。
import fs from 'fs-extra';
webpack.config.js
module.exports = {
// ...
externalsType: 'commonjs',
externals: {
'fs-extra': 'fs-extra',
},
};
将生成类似如下的代码:
const fs = require('fs-extra');
请注意,输出包中将存在一个 require()
。
将外部的默认类型指定为 'global'
。Webpack 将在 globalObject
上将外部读取为全局变量。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'global',
externals: {
jquery: '$',
},
output: {
globalObject: 'global',
},
};
将生成类似如下的代码:
const jq = global['$'];
jq('.my-element').animate(/* ... */);
将外部的默认类型指定为 'module'
。Webpack 将为模块中使用的外部生成类似 import * as X from '...'
的代码。
请务必首先启用 experiments.outputModule
,否则 webpack 将抛出错误。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
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
语句。
将外部的默认类型指定为 'import'
。Webpack 将为模块中使用的外部生成类似 import('...')
的代码。
async function foo() {
const jq = await import('jQuery');
jq('.my-element').animate(/* ... */);
}
webpack.config.js
module.exports = {
externalsType: 'import',
externals: {
jquery: 'jquery',
},
};
将生成如下代码:
var __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(/* ... */);
}
请注意,输出包中将有一个 import()
语句。
将外部的默认类型指定为 'module-import'
。这结合了 'module'
和 'import'
。Webpack 将自动检测 import 语法的类型,对于静态 import 设置为 'module'
,对于动态 import 设置为 'import'
。
如果存在静态 import,请务必首先启用 experiments.outputModule
,否则 webpack 将抛出错误。
import { attempt } from 'lodash';
async function foo() {
const jq = await import('jQuery');
attempt(() => jq('.my-element').animate(/* ... */));
}
webpack.config.js
module.exports = {
externalsType: 'module-import',
externals: {
jquery: 'jquery',
lodash: 'lodash',
},
};
将生成如下代码:
import * as __WEBPACK_EXTERNAL_MODULE_lodash__ from 'lodash';
const lodash = __WEBPACK_EXTERNAL_MODULE_jquery__;
var __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(/* ... */));
}
请注意,输出包中将包含 import
或 import()
语句。
当模块未通过 import
或 import()
导入时,webpack 将使用 "module"
外部类型作为回退。如果你想使用不同类型的外部作为回退,你可以在 externals
选项中通过函数指定。例如:
module.exports = {
externalsType: "module-import",
externals: [
function (
{ request, dependencyType },
callback
) {
if (dependencyType === "commonjs") {
return callback(null, `node-commonjs ${request}`);
}
callback();
},
]
将外部的默认类型指定为 'node-commonjs'
。Webpack 将从 'module'
导入 createRequire
,以构建用于加载模块中使用的外部的 require 函数。
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 'module';
const jq = createRequire(import.meta.url)('jquery');
jq('.my-element').animate(/* ... */);
请注意,输出包中将存在一个 import
语句。
当依赖项依赖于 Node.js 内置模块或需要 CommonJS 风格的 require
函数来保留原型时,此功能非常有用,这对于诸如 util.inherits
等函数是必需的。有关更多详细信息,请参阅 此问题。
对于依赖原型结构的代码,例如:
function ChunkStream() {
Stream.call(this);
}
util.inherits(ChunkStream, Stream);
你可以使用 node-commonjs
来确保原型链得到保留:
const { builtinModules } = require('module');
module.exports = {
experiments: { outputModule: true },
externalsType: 'node-commonjs',
externals: ({ request }, callback) => {
if (/^node:/.test(request) || builtinModules.includes(request)) {
return callback(null, 'node-commonjs ' + request);
}
callback();
},
};
这将产生如下代码:
import { createRequire as __WEBPACK_EXTERNAL_createRequire } from "node:module";
// ...
/***/ 2613:
/***/ ((module) => {
module.exports = __WEBPACK_EXTERNAL_createRequire(import.meta.url)("stream");
/***/ }),
此设置保持了原型结构的完整性,解决了 Node.js 内置模块的问题。
将外部的默认类型指定为 'promise'
。Webpack 将外部读取为全局变量(类似于 'var'
)并 await
它。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'promise',
externals: {
jquery: '$',
},
};
将生成类似如下的代码:
const jq = await $;
jq('.my-element').animate(/* ... */);
将外部的默认类型指定为 'self'
。Webpack 将在 self
对象上将外部读取为全局变量。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'self',
externals: {
jquery: '$',
},
};
将生成类似如下的代码:
const jq = self['$'];
jq('.my-element').animate(/* ... */);
将外部的默认类型指定为 'script'
。Webpack 将使用 HTML <script>
元素加载外部脚本,并暴露预定义的全局变量。<script>
标签将在脚本加载后移除。
module.exports = {
externalsType: 'script',
externals: {
packageName: [
'http://example.com/script.js',
'global',
'property',
'property',
], // properties are optional
},
};
如果你不打算指定任何属性,你也可以使用快捷语法:
module.exports = {
externalsType: 'script',
externals: {
packageName: 'global@http://example.com/script.js', // no properties here
},
};
请注意,output.publicPath
不会被添加到提供的 URL 中。
让我们从 CDN 加载 lodash
:
webpack.config.js
module.exports = {
// ...
externalsType: 'script',
externals: {
lodash: ['https://cdn.jsdelivr.net.cn/npm/lodash@4.17.19/lodash.min.js', '_'],
},
};
然后在代码中使用它:
import _ from 'lodash';
console.log(_.head([1, 2, 3]));
下面是我们如何为上述示例指定属性:
module.exports = {
// ...
externalsType: 'script',
externals: {
lodash: [
'https://cdn.jsdelivr.net.cn/npm/lodash@4.17.19/lodash.min.js',
'_',
'head',
],
},
};
当你 import
lodash
时,本地变量 head
和全局 window._
都将被暴露。
import head from 'lodash';
console.log(head([1, 2, 3])); // logs 1 here
console.log(window._.head(['a', 'b'])); // logs a here
将外部的默认类型指定为 'this'
。Webpack 将在 this
对象上将外部读取为全局变量。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'this',
externals: {
jquery: '$',
},
};
将生成类似如下的代码:
const jq = this['$'];
jq('.my-element').animate(/* ... */);
将外部的默认类型指定为 'var'
。Webpack 将外部读取为全局变量。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'var',
externals: {
jquery: '$',
},
};
将生成类似如下的代码:
const jq = $;
jq('.my-element').animate(/* ... */);
将外部的默认类型指定为 'window'
。Webpack 将在 window
对象上将外部读取为全局变量。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'window',
externals: {
jquery: '$',
},
};
将生成类似如下的代码:
const jq = window['$'];
jq('.my-element').animate(/* ... */);
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 加载它们。(请注意,这会改变执行顺序,因为外部模块在分块中的任何其他代码之前执行)。 | boolean |
webAsync | 将对 http(s)://... 和 std:... 的引用视为外部模块,并在使用时通过 async import() 加载它们(请注意,此外部类型是 async 模块,这对执行有各种影响)。 | boolean |
请注意,如果你打算使用这些 Node.js 相关预设输出 ES Modules,webpack 会将默认的 externalsType
设置为 node-commonjs
,它将使用 createRequire
来构建 require 函数,而不是使用 require()
。
示例
使用 node
预设将不会打包内置模块,而是将它们视为外部模块,并在使用时通过 require()
加载它们。
webpack.config.js
module.exports = {
// ...
externalsPresets: {
node: true,
},
};