externals
配置选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer's environment)中的依赖。此功能通常对 library 开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。
string
object
function
RegExp
[string, object, function, RegExp]
防止将某些 import
的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies)。
例如,从 CDN 引入 jQuery,而不是把它打包:
index.html
<script
src="https://code.jquery.com/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
)。
如果你只定义 1 个 external,您也可以使用快捷语法:
module.exports = {
//...
externals: 'jquery',
};
equals to
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"];
与 string 语法 类似,你可以使用 ${externalsType} ${libraryName}
语法在数组的第一项中指定外部库类型,例如:
module.exports = {
//...
externals: {
subtract: ['commonjs ./math', 'subtract'],
},
};
module.exports = {
//...
externals: {
react: 'react',
},
// 或者
externals: {
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_', // 指向全局变量
},
},
// 或者
externals: {
subtract: {
root: ['math', 'subtract'],
},
},
};
此语法用于描述外部 library 所有可用的访问方式。这里 lodash
这个外部 library 可以在 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
目录中所有模块,还提供一些选项,比如白名单 package(whitelist package)。
函数接收两个入参:
ctx
(object
):包含文件详情的对象。ctx.context
(string
): 包含引用的文件目录。ctc.request
(string
): 被请求引入的路径。ctx.contextInfo
(object
): 包含 issuer 的信息(如,layer 和 compiler)ctx.getResolve
5.15.0+: 获取当前解析器选项的解析函数。callback
(function (err, result, type)
): 用于指明模块如何被外部化的回调函数回调函数接收三个入参:
err
(Error
): 被用于表明在外部外引用的时候是否会产生错误。如果有错误,这将会是唯一被用到的参数。result
(string
[string]
object
): 描述外部化的模块。可以接受其它标准化外部化模块格式,(string
, [string]
,或 object
)。type
(string
): 可选的参数,用于指明模块的 external type(如果它没在 result
参数中被指明)。作为例子,要外部化所有匹配一个正则表达式的引入,你可以像下面那样处理:
webpack.config.js
module.exports = {
//...
externals: [
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
// 使用 request 路径,将一个 commonjs 模块外部化
return callback(null, 'commonjs ' + request);
}
// 继续下一步且不外部化引用
callback();
},
],
};
其它例子使用不同的模块格式:
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 该外部化的模块,是一个 `commonjs2` 的模块,且放在 `@scope/library` 目录中
callback(null, '@scope/library', 'commonjs2');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 该外部化模块是一个全局变量叫作 `nameOfGlobal`.
callback(null, 'nameOfGlobal');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 该外部化模块是一个在`@scope/library`模块里的命名导出(named export)。
callback(null, ['@scope/library', 'namedexport'], 'commonjs');
},
],
};
webpack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 外部化模块是一个 UMD 模块
callback(null, {
root: 'componentsGlobal',
commonjs: '@scope/components',
commonjs2: '@scope/components',
amd: 'components',
});
},
],
};
匹配给定正则表达式的每个依赖,都将从输出 bundle 中排除。
webpack.config.js
module.exports = {
//...
externals: /^(jquery|\$)$/i,
};
这个示例中,所有名为 jQuery
的依赖(忽略大小写),或者 $
,都会被外部化。
有时你需要混用上面介绍的语法。这可以像以下这样操作:
webpack.config.js
module.exports = {
//...
externals: [
{
// 字符串
react: 'react',
// 对象
lodash: {
commonjs: 'lodash',
amd: 'lodash',
root: '_', // indicates global variable
},
// 字符串数组
subtract: ['./math', 'subtract'],
},
// 函数
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
return callback(null, 'commonjs ' + request);
}
callback();
},
// 正则表达式
/^(jquery|\$)$/i,
],
};
关于如何使用此 externals 配置的更多信息,请参考 如何编写 library。
function
object
按层指定 externals:
webpack.config.js
module.exports = {
externals: {
byLayer: {
layer: {
external1: 'var 43',
},
},
},
};
string = 'var'
指定 externals 的默认类型。当 external 被设置为 amd
,umd
,system
以及 jsonp
时,output.libraryTarget
的值也应相同。例如,你只能在 amd
库中使用 amd
的 externals。
支持的类型如下:
'amd'
'amd-require'
'assign'
- same as 'var'
'commonjs'
'commonjs-module'
'global'
'import'
- uses import()
to load a native EcmaScript module (async module)'jsonp'
'module'
'node-commonjs'
'promise'
- 与 'var'
相同,但是会 await 结果(适用于 async 模块)'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 会将 external 作为全局变量读取到 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(/* ... */);
将 externals 类型设置为 'module'
,webpack 将会在 module 中为外部引用生成形如 import * as X from '...'
的代码。
确保首先把 experiments.outputModule
设置为 true
, 否则 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
语句。
将 externals 类型设置为 '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
语句。
将外部的默认类型指定为 'promise'
。Webpack 会将 external 读取为全局变量(类似于 '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 会将 external 作为 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(/* ... */);
将 external 的默认类型指定为 'script'
。Webpack 会将 external 作为脚本加载,并使用 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/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/npm/lodash@4.17.19/lodash.min.js',
'_',
'head',
],
},
};
当你 import 'loadsh'
时,局部变量 head
和全局变量 window._
都会被暴露:
import head from 'lodash';
console.log(head([1, 2, 3])); // logs 1 here
console.log(window._.head(['a', 'b'])); // logs a here
将 external 的默认类型指定为 'this'
。Webpack 会将 external 作为 this
对象上的全局变量读取。
示例 $#example$
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'this',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = this['$'];
jq('.my-element').animate(/* ... */);
将 external 的默认类型指定为 'var'
。Webpack 会将 external 作为全局变量读取。
示例 $#example$
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
webpack.config.js
module.exports = {
// ...
externalsType: 'var',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = $;
jq('.my-element').animate(/* ... */);
将 external 的默认类型指定为 'window'
。Webpack 会将 external 作为 window
对象上的全局变量读取。
示例 $#example$
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
为特定的 target 启用 externals 的 preset。
选项 | 描述 | 输入类型 |
---|---|---|
electron | 将 main 和预加载上下文中常见的 electron 内置模块视为 external 模块(如 electron ,ipc 或 shell ),使用时通过 require() 加载。 | boolean |
electronMain | 将 main 上下文中的 electron 内置模块视为 external 模块(如 app ,ipc-main 或 shell ),使用时通过 require() 加载。 | boolean |
electronPreload | 将预加载上下文的 electron 内置模块视为 external 模块(如 web-frame ,ipc-renderer 或 shell ),使用时通过 require() 加载。 | boolean |
electronRenderer | 将 renderer 上下文的 electron 内置模块视为 external 模块(如 web-frame 、ipc-renderer 或 shell ),使用时通过 require() 加载。 | boolean |
node | 将 node.js 的内置模块视为 external 模块(如 fs ,path 或 vm ),使用时通过 require() 加载。 | boolean |
nwjs | 将 NW.js 遗留的 nw.gui 模块视为 external 模块,使用时通过 require() 加载。 | boolean |
web | 将 http(s)://... 以及 std:... 视为 external 模块,使用时通过 import 加载。(注意,这将改变执行顺序,因为 external 代码会在该块中的其他代码执行前被执行)。 | boolean |
webAsync | 将 'http(s)://...' 以及 'std:...' 的引用视为 external 模块,使用时通过 async import() 加载。(注意,此 external 类型为 async 模块,它对执行会产生各种副作用)。 | boolean |
Note that if you're going to output ES Modules with those node.js-related presets, webpack will set the default externalsType
to node-commonjs
which would use createRequire
to construct a require function instead of using require()
.
Example
使用 node
的 preset 不会构建内置模块,而会将其视为 external 模块,使用时通过 require()
加载。
webpack.config.js
module.exports = {
// ...
externalsPresets: {
node: true,
},
};
Webpack 5 现已正式发布。请阅读我们的 发布公告。如还未准备升级,请阅读 webpack 4 文档。