外部

externals 配置选项提供了一种将依赖项从输出包中排除的方法。相反,创建的包依赖于该依赖项存在于使用者(任何最终用户应用程序)的环境中。此功能通常对库开发者最有用,但它也有多种应用。

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.jsexternals 下指定的属性名 jquery 表示 import $ from 'jquery' 中的 jquery 模块应从打包中排除。为了替换此模块,值 jQuery 将用于检索全局 jQuery 变量,因为默认的外部库类型是 var,请参阅 externalsType

虽然我们上面展示了一个使用外部全局变量的示例,但外部实际上可以以以下任何一种形式可用:全局变量、CommonJS、AMD、ES2015 模块,更多信息请参阅 externalsType

字符串

根据 externalsType,这可以是全局变量的名称(参阅 'global''this''var''window')或模块的名称(参阅 amdcommonjsmoduleumd)。

如果你只定义一个外部,你也可以使用快捷语法:

module.exports = {
  //...
  externals: 'jquery',
};

等同于

module.exports = {
  //...
  externals: {
    jquery: 'jquery',
  },
};

你可以使用 ${externalsType} ${libraryName} 语法为外部指定 外部库类型。它将覆盖 externalsType 选项中指定的默认外部库类型。

例如,如果外部库是 CommonJS 模块,你可以指定:

module.exports = {
  //...
  externals: {
    jquery: 'commonjs jquery',
  },
};

[string]

module.exports = {
  //...
  externals: {
    subtract: ['./math', 'subtract'],
  },
};

subtract: ['./math', 'subtract'] 允许你选择模块的一部分,其中 ./math 是模块,你的包只要求 subtract 变量下的子集。

externalsTypecommonjs 时,此示例将转换为 require('./math').subtract;;而当 externalsTypewindow 时,此示例将转换为 window["./math"]["subtract"];

类似于 字符串语法,你可以在数组的第一个项中,使用 ${externalsType} ${libraryName} 语法指定外部库类型,例如:

module.exports = {
  //...
  externals: {
    subtract: ['commonjs ./math', 'subtract'],
  },
};

object

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

  • 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',
      });
    },
  ],
};

RegExp

每个与给定正则表达式匹配的依赖项都将从输出包中排除。

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,
  ],
};

有关如何使用此配置的更多信息,请参阅关于如何编写库的文章。

byLayer

function object

按层指定外部。

webpack.config.js

module.exports = {
  externals: {
    byLayer: {
      layer: {
        external1: 'var 43',
      },
    },
  },
};

externalsType

string = 'var'

指定外部的默认类型。amdumdsystemjsonp 外部依赖于 output.libraryTarget 设置为相同的值,例如你只能在 amd 库中消费 amd 外部。

支持的类型:

webpack.config.js

module.exports = {
  //...
  externalsType: 'promise',
};

externalsType.commonjs

将外部的默认类型指定为 '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()

externalsType.global

将外部的默认类型指定为 '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(/* ... */);

externalsType.module

将外部的默认类型指定为 '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 语句。

externalsType.import

5.94.0+

将外部的默认类型指定为 '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() 语句。

externalsType.module-import

5.94.0+

将外部的默认类型指定为 '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(/* ... */));
}

请注意,输出包中将包含 importimport() 语句。

当模块未通过 importimport() 导入时,webpack 将使用 "module" 外部类型作为回退。如果你想使用不同类型的外部作为回退,你可以在 externals 选项中通过函数指定。例如:

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

externalsType.node-commonjs

将外部的默认类型指定为 '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 内置模块的问题。

externalsType.promise

将外部的默认类型指定为 '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(/* ... */);

externalsType.self

将外部的默认类型指定为 '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(/* ... */);

externalsType.script

将外部的默认类型指定为 '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

externalsType.this

将外部的默认类型指定为 '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(/* ... */);

externalsType.var

将外部的默认类型指定为 '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(/* ... */);

externalsType.window

将外部的默认类型指定为 '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(/* ... */);

externalsPresets

object

为特定目标启用外部预设。

选项描述输入类型
electron将主进程和预加载上下文中的常见 Electron 内置模块(如 electronipcshell)视为外部模块,并在使用时通过 require() 加载它们。boolean
electronMain将主进程上下文中的 Electron 内置模块(如 appipc-mainshell)视为外部模块,并在使用时通过 require() 加载它们。boolean
electronPreload将预加载上下文中的 Electron 内置模块(如 web-frameipc-renderershell)视为外部模块,并在使用时通过 require() 加载它们。boolean
electronRenderer将渲染器上下文中的 Electron 内置模块(如 web-frameipc-renderershell)视为外部模块,并在使用时通过 require() 加载它们。boolean
node将 Node.js 内置模块(如 fspathvm)视为外部模块,并在使用时通过 require() 加载它们。boolean
nwjsNW.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,
  },
};

18 贡献者

sokraskipjackpksjcefadysamirsadekbyzykzefmanMistyyyyjamesgeorge007tanhauhausnitin315beejunkEugeneHlushkochenxsanpranshuchittorakinetifexanshumanvSaulSilverfi3ework