CC 4.0 协议声明
本节内容派生于以下链接指向的内容 ,并遵守 CC BY 4.0 许可证的规定。
以下内容如果没有特殊声明,可以认为都是基于原内容的修改和删减后的结果。
Externals
外部依赖:该选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer's environment)中的依赖。此功能通常对库开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。
externals
- 类型:
string | object | function | RegExp | Array<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>
rspack.config.js
module.exports = {
//...
externals: {
jquery: 'jquery',
},
};
这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:
import $ from 'jquery';
$('.my-element').animate(/* ... */);
上面 rspack.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
)。
如果你只定义一个 external,也可以使用快捷语法:
rspack.config.js
module.exports = {
//...
externals: 'jquery',
};
等价于
rspack.config.js
module.exports = {
//...
externals: {
jquery: 'jquery',
},
};
你可以使用 ${externalsType} ${libraryName}
语法来指定外部库类型。它将覆盖 externalsType 选项中指定的默认外部库类型。
例如,如果外部库是一个 CommonJS 模块,你可以指定
rspack.config.js
module.exports = {
//...
externals: {
jquery: 'commonjs jquery',
},
};
字符串数组
rspack.config.js
module.exports = {
//...
externals: {
subtract: ['./math', 'subtract'],
},
};
subtract: ['./math', 'subtract']
允许你选择一个模块的一部分,其中 ./math
是模块名,你的打包只需要包含 subtract
变量下的子集。
当 externalsType
为 commonjs
时,这个例子会编译为 require('./math').subtract
;当 externalsType
为 window
时,这个例子会编译为 window["./math"]["subtract"]
。
与字符串语法类似,你可以在数组的第一个元素中使用 ${externalsType} ${libraryName}
语法指定外部库类型,例如:
rspack.config.js
module.exports = {
//...
externals: {
subtract: ['commonjs ./math', 'subtract'],
},
};
对象
rspack.config.js
module.exports = {
externals: {
// 在 `libraryTarget: 'umd'` 和 `externalsType: 'umd'` 时,需严格遵循以下格式:
lodash: {
root: '_', // 指向全局变量
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
},
},
};
此语法用于描述外部 library 所有可用的访问方式。这里 lodash
这个外部库可以在 AMD 和 CommonJS 模块系统中通过 lodash
访问,但在全局变量形式下用 _
访问。subtract
可以通过全局 math
对象下的属性 subtract
访问(例如 window['math']['subtract']
)。
函数
-
类型:
function ({ context, request, contextInfo, getResolve }, callback)
function ({ context, request, contextInfo, getResolve }) => promise
如果你想要自定义外部化的行为,可以使用函数。例如使用 webpack-node-externals 排除所有来自 node_modules
目录的模块,并提供了选项来允许列出白名单中的包。
函数接收两个入参:
ctx
(object
): 包含文件的详细信息的对象。
ctx.context
(string
): 包含 import 的文件的目录。
ctx.request
(string
): 被请求的 import 路径。
ctx.contextInfo
(object
): 包含有关发起者的信息(例如 layer 和编译器)。
ctx.getResolve
: 获取一个带有当前解析器选项的解析函数。
callback
(function (err, result, type)
): 用来指示模块如何被外部化的回调函数。
回调函数接收三个参数:
err
(Error
): 用于标识外部化导入时是否出现错误。如果有错误,这应该是唯一使用的参数。
result
(string | string[] | object
): 使用其他外部格式描述外部模块(字符串,字符串数组或对象 )。
type
(string
): 指示 externalsType 的可选参数(如果还没有在 result
参数中指出的话)。
例如,要外部化所有导入路径与正则表达式匹配的导入,可以这样做:
rspack.config.js
module.exports = {
//...
externals: [
function ({ context, request }, callback) {
if (/^yourregex$/.test(request)) {
// 将请求路径外部化到 CommonJS 模块
return callback(null, 'commonjs ' + request);
}
// 跳过外部化导入
callback();
},
],
};
其他使用不同模块格式的例子:
rspack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 外部化为 `@scope/library` 的 `commonjs2` 模块
callback(null, '@scope/library', 'commonjs2');
},
],
};
rspack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 外部化名为 `nameOfGlobal` 的全局变量
callback(null, 'nameOfGlobal');
},
],
};
rspack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 外部化为 `@scope/library` 模块中的具名导出
callback(null, ['@scope/library', 'namedexport'], 'commonjs');
},
],
};
rspack.config.js
module.exports = {
externals: [
function (ctx, callback) {
// 外部化为 UMD 模块
callback(null, {
root: 'componentsGlobal',
commonjs: '@scope/components',
commonjs2: '@scope/components',
amd: 'components',
});
},
],
};
正则表达式
符合给定正则表达式的每个依赖项都将从打包产物中排除。
rspack.config.js
module.exports = {
//...
externals: /^(jquery|\$)$/i,
};
在这种情况下,任何名为 jQuery
的依赖项,无论是否大写,或者 $
,都将被外部化。
复合语法
有时你可能希望使用上述语法的组合。这可以通过以下方式完成:
rspack.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,
],
};
WARNING
如果没有指定类型,将使用默认类型,例如 externals: { react: 'react' }
而不是 externals: { react: 'commonjs-module react' }
。
externalsType
指定 externals 的默认类型。当 external 被设置为 amd
,umd
,system
以及 jsonp
时,output.libraryTarget
的值也应相同。例如,你只能在 amd
库中使用 amd
的 externals。
支持的类型如下:
rspack.config.js
module.exports = {
//...
externalsType: 'promise',
};
externalsType.commonjs
将 externals 的默认类型指定为 'commonjs'
。Rspack 将为模块中使用的外部生成类似 const X = require('...')
的代码。
示例
import fs from 'fs-extra';
rspack.config.js
module.exports = {
// ...
externalsType: 'commonjs',
externals: {
'fs-extra': 'fs-extra',
},
};
将会转换为类似下面的代码:
const fs = require('fs-extra');
请注意,输出产物中会有一个 require()
。
externalsType.global
将 externals 的默认类型指定为 'global'
。Rspack 会将 external 视为 globalObject
上的一个全局变量读取。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'global',
externals: {
jquery: '$',
},
output: {
globalObject: 'global',
},
};
将会转换为类似下面的代码:
const jq = global['$'];
jq('.my-element').animate(/* ... */);
externalsType.module
将 externals 的默认类型指定为 'module'
。Rspack 将为模块中使用的 externals 生成类似 import * as X from '...'
的代码。
确保开启了 experiments.outputModule
,否则 Rspack 会抛出错误。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.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
语句。
externalsType.import
将 externals 的默认类型指定为 'import'
。Rspack 将为模块中使用的 externals 生成类似 import('...')
的代码。
示例
async function foo() {
const jq = await import('jquery');
jq('.my-element').animate(/* ... */);
}
rspack.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()
语句。
externalsType['module-import']
将 externals 的默认类型指定为 'module-import'
。这将结合 'module'
和 'import'
。Rspack 将自动检测导入语法的类型,对于静态导入设置为 'module'
,对于动态导入设置为 'import'
。
示例
import { attempt } from 'lodash';
async function foo() {
const jq = await import('jquery');
attempt(() => jq('.my-element').animate(/* ... */));
}
rspack.config.js
module.exports = {
externalsType: 'module-import',
externals: {
jquery: 'jquery',
},
};
将会转换为类似下面的代码:
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()
导入时,Rspack 将使用 "module"
externals type 作为回退。如果你想使用不同类型的 externals 作为回退,你可以在 externals
选项中指定一个函数。例如:
rspack.config.js
module.exports = {
externalsType: "module-import",
externals: [
function (
{ request, dependencyType },
callback
) {
if (dependencyType === "commonjs") {
return callback(null, `node-commonjs ${request}`);
}
callback();
},
]
externalsType['commonjs-import']
将 externals 的默认类型指定为 'commonjs-import'
。这将结合 'commonjs'
和 'import'
。Rspack 将自动检测导入语法的类型,对于动态导入设置为 'import'
,其他的导入设置为 'commonjs'
。
这在构建一个 Node.js 应用程序时非常有用,当目标 Node.js 版本高于 13.2.0
,同时支持 import()
表达式 和 require()
。
NOTE
commonjs-import
类型仅在 Rspack 中可用,webpack 并不支持此类型。
示例
import { attempt } from 'lodash';
async function foo() {
const jq = await import('jquery');
attempt(() => jq('.my-element').animate(/* ... */));
}
rspack.config.js
module.exports = {
externalsType: 'commonjs-import',
externals: {
lodash: 'lodash',
jquery: 'jquery',
},
};
将会转换为类似下面的代码:
var __webpack_modules__ = {
lodash: function (module) {
module.exports = require('lodash');
},
jquery: function (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__WEBPACK_IMPORTED_MODULE_0__.attempt)(() =>
jq('.my-element').animate(/* ... */),
);
}
请注意,在输出产物中将有 import()
语句。
externalsType['node-commonjs']
将 externals 类型设置为 'node-commonjs'
,Rspack 将从 module
中导入 createRequire
来构造一个 require 函数,用于加载模块中使用的外部对象。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.export = {
externalsType: 'node-commonjs',
externals: {
jquery: 'jquery',
},
};
将会转换为类似下面的代码:
import { createRequire } from 'module';
const jq = createRequire(import.meta.url)('jquery');
jq('.my-element').animate(/* ... */);
请注意,在输出产物中会有 import
语句。
externalsType.promise
将 externals 的默认类型指定为 'promise'
,Rspack 会将 external 视为全局变量(类似于 'var'
)并 await 它。
例子
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'promise',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = await $;
jq('.my-element').animate(/* ... */);
externalsType.self
将外部的默认类型指定为 'self'
。 Rspack 会将 external 作为 self
对象上的全局变量读取。
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'self',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = self['$'];
jq('.my-element').animate(/* ... */);
externalsType.script
将 external 的默认类型指定为 'script'
。Rspack 会使用 HTML <script>
标签加载外部资源,暴露预定义的全局变量。脚本加载完成后,<script>
标签将被移除。
语法
rspack.config.js
module.exports = {
externalsType: 'script',
externals: {
packageName: [
'http://example.com/script.js',
'global',
'property',
'property',
], // 属性是可选的
},
};
如果不打算指定任何属性也可以使用快捷语法:
rspack.config.js
module.exports = {
externalsType: 'script',
externals: {
packageName: 'global@http://example.com/script.js', // 这里没有属性
},
};
请注意,output.publicPath 不会被添加到提供的 URL 中。
示例
让我们从 CDN 加载一个 lodash
:
rspack.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]));
下面是我们如何为上述示例指定属性的方法:
rspack.config.js
module.exports = {
// ...
externalsType: 'script',
externals: {
lodash: [
'https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js',
'_',
'head',
],
},
};
局部变量 head
和全局 window._
在导入 lodash
时都将被暴露出来。
import head from 'lodash';
console.log(head([1, 2, 3])); // logs 1 here
console.log(window._.head(['a', 'b'])); // logs a here
TIP
当使用 HTML <script>
标签加载代码时,Rspack 运行时会尝试查找与 src
属性匹配或具有特定 data-webpack
属性的现有 <script>
标签。对于 chunk 加载,data-webpack
属性的值将是 '[output.uniqueName]:chunk-[chunkId]'
,而外部脚本的值将是 '[output.uniqueName]:[global]'
。
externalsType.this
将 external 的默认类型指定为 'this'
。Rspack 会将 external 作为 this
对象上的全局变量读取。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'this',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = this['$'];
jq('.my-element').animate(/* ... */);
externalsType.var
将 external 的默认类型指定为 'var'
。Rspack 会将 external 作为全局变量读取。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'var',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = $;
jq('.my-element').animate(/* ... */);
externalsType.window
将 external 的默认类型指定为 'window'
。Rspack 会将 external 作为 window
对象上的全局变量读取。
示例
import jq from 'jquery';
jq('.my-element').animate(/* ... */);
rspack.config.js
module.exports = {
// ...
externalsType: 'window',
externals: {
jquery: '$',
},
};
将会转换为类似下面的代码:
const jq = window['$'];
jq('.my-element').animate(/* ... */);
externalsPresets
为特定的目标环境启用外部模块的预设值。
externalsPresets.electron
类型:boolean
将 Electron 主进程和预加载脚本中常见的 Electron 内置模块如 electron
、ipc
或 shell
视为外部模块,并在使用时通过 require()
加载它们。
externalsPresets.electronMain
类型:boolean
将 Electron 主进程中常见的 Electron 内置模块如 app
、ipc-main
或 shell
视为外部模块,并在使用时通过 require()
加载它们。
externalsPresets.electronPreload
类型:boolean
将 Electron 预加载脚本中常见的 Electron 内置模块如 web-frame
、ipc-renderer
或 shell
视为外部模块,并在使用时通过 require()
加载它们。
externalsPresets.electronRenderer
类型:boolean
将 Electron 渲染进程中常见的 Electron 内置模块如 web-frame
、ipc-renderer
或 shell
视为外部模块,并在使用时通过 require()
加载它们。
externalsPresets.node
类型:boolean
将 node.js 的内置模块(如 fs
、path
或 vm
)视为外部模块,并在使用时通过 require()
加载它们。
externalsPresets.nwjs
类型:boolean
将 NW.js 旧版 nw.gui
模块视为外部模块,并在使用时通过 require()
加载它。
externalsPresets.web
类型:boolean
将对 http(s)://...
和 std:...
引入的模块视为外部模块,并在使用时通过 import
(externalType: "module"
) 来加载它们 (请注意,这会改变执行顺序,因为外部模块的代码会在 chunk 中的任何其他模块的代码之前执行)。
externalsPresets.webAsync
类型:boolean
将对 http(s)://...
和 std:...
引入的模块视为外部模块,并在使用时通过 async import()
来加载它们 (注意,外部模块的类型是 async
模块,对执行有各种影响)。
请注意,如果你打算输出 ES 模块并使用这些 node.js 相关的预设值,Rspack 将会将默认的 externalsType
设置为 node-commonjs
,这将使用 createRequire
来构造一个 require 函数,而不是使用 require()
。
示例
使用 node
预设将不会打包内置模块,并将它们视为外部模块,当使用时通过 require()
加载它们。
rspack.config.js
module.exports = {
// ...
externalsPresets: {
node: true,
},
};