Webpack 外部擴(kuò)展(Externals)

2023-05-16 16:04 更新

externals 配置選項(xiàng)提供了「從輸出的 bundle 中排除依賴」的方法。相反,所創(chuàng)建的 bundle 依賴于那些存在于用戶環(huán)境(consumer's environment)中的依賴。此功能通常對(duì) library 開發(fā)人員來(lái)說(shuō)是最有用的,然而也會(huì)有各種各樣的應(yīng)用程序用到它。

externals

string object function RegExp [string, object, function, RegExp]

防止將某些 import 的包(package)打包到 bundle 中,而是在運(yùn)行時(shí)(runtime)再去從外部獲取這些擴(kuò)展依賴(external dependencies)。

例如,從 CDN 引入 jQuery,而不是把它打包:

index.html

<script
  src="https://code.jquery.com/jquery-3.1.0.js" rel="external nofollow" 
  integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
  crossorigin="anonymous"
></script>

webpack.config.js

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

這樣就剝離了那些不需要改動(dòng)的依賴模塊,換句話,下面展示的代碼還可以正常運(yùn)行:

import $ from 'jquery';

$('.my-element').animate(/* ... */);

上面 webpack.config.js 中 externals 下指定的屬性名稱 jquery 表示 import $ from 'jquery' 中的模塊 jquery 應(yīng)該從打包產(chǎn)物中排除。 為了替換這個(gè)模塊,jQuery 值將用于檢索全局 jQuery 變量,因?yàn)槟J(rèn)的外部庫(kù)類型是 var,請(qǐng)參閱 externalsType。

雖然我們?cè)谏厦嬲故玖艘粋€(gè)使用外部全局變量的示例,但實(shí)際上可以以以下任何形式使用外部變量:全局變量、CommonJS、AMD、ES2015 模塊,在 externalsType 中查看更多信息。

字符串

根據(jù) externalsType,這可能是全局變量的名稱(參見 'global'、'this'、 'var ', 'window') 或模塊的名稱(參見 amd, commonjs,  module, umd)。

如果你只定義 1 個(gè) external,您也可以使用快捷語(yǔ)法:

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

equals to

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

您可以使用 ${externalsType} ${libraryName} 語(yǔ)法為外部指定 外部庫(kù)類型。 它將覆蓋 externalsType 選項(xiàng)中指定的默認(rèn)外部庫(kù)類型。

例如,如果外部庫(kù)是一個(gè) CommonJS 模塊,你可以指定

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

[string]

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

?subtract: ['./math', 'subtract']? 允許你選擇模塊的一部分,其中 ?./math? 是模塊,并且你的包只需要 subtract 變量下的子集。

當(dāng) externalsType 為 commonjs 時(shí),此示例將轉(zhuǎn)換為 ?require('./math').subtract;?,而當(dāng) externalsType 為 window 時(shí),此示例將轉(zhuǎn)換為 ?window["./math"]["subtract"];?

與 string 語(yǔ)法 類似,你可以使用 ${externalsType} ${libraryName} 語(yǔ)法在數(shù)組的第一項(xiàng)中指定外部庫(kù)類型,例如:

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

對(duì)象

module.exports = {
  //...
  externals: {
    react: 'react',
  },

  // 或者

  externals: {
    lodash: {
      commonjs: 'lodash',
      amd: 'lodash',
      root: '_', // 指向全局變量
    },
  },

  // 或者

  externals: {
    subtract: {
      root: ['math', 'subtract'],
    },
  },
};

此語(yǔ)法用于描述外部 library 所有可用的訪問(wèn)方式。這里 lodash 這個(gè)外部 library 可以在 AMD 和 CommonJS 模塊系統(tǒng)中通過(guò) lodash 訪問(wèn),但在全局變量形式下用 _ 訪問(wèn)。subtract 可以通過(guò)全局 math 對(duì)象下的屬性 subtract 訪問(wèn)(例如 window['math']['subtract'])。

函數(shù)

  • ?function ({ context, request, contextInfo, getResolve }, callback)?
  • ?function ({ context, request, contextInfo, getResolve }) => promise5.15.0+

對(duì)于 webpack 外部化,通過(guò)定義函數(shù)來(lái)控制行為,可能會(huì)很有幫助。例如,webpack-node-externals 能夠排除 node_modules 目錄中所有模塊,還提供一些選項(xiàng),比如白名單 package(whitelist package)。

函數(shù)接收兩個(gè)入?yún)ⅲ?/p>

  • ctx (object):包含文件詳情的對(duì)象。ctx.context (string): 包含引用的文件目錄。ctc.request (string): 被請(qǐng)求引入的路徑。ctx.contextInfo (object): 包含 issuer 的信息(如,layer 和 compiler)ctx.getResolve 5.15.0+: 獲取當(dāng)前解析器選項(xiàng)的解析函數(shù)。
  • callback (function (err, result, type)): 用于指明模塊如何被外部化的回調(diào)函數(shù)

回調(diào)函數(shù)接收三個(gè)入?yún)ⅲ?/p>

  • err (Error): 被用于表明在外部外引用的時(shí)候是否會(huì)產(chǎn)生錯(cuò)誤。如果有錯(cuò)誤,這將會(huì)是唯一被用到的參數(shù)。
  • result (string [string] object): 描述外部化的模塊??梢越邮芷渌鼧?biāo)準(zhǔn)化外部化模塊格式,(string, [string],或  object)。
  • type (string): 可選的參數(shù),用于指明模塊的 external type(如果它沒(méi)在 result 參數(shù)中被指明)。

作為例子,要外部化所有匹配一個(gè)正則表達(dá)式的引入,你可以像下面那樣處理:

webpack.config.js

module.exports = {
  //...
  externals: [
    function ({ context, request }, callback) {
      if (/^yourregex$/.test(request)) {
        // 使用 request 路徑,將一個(gè) commonjs 模塊外部化
        return callback(null, 'commonjs ' + request);
      }

      // 繼續(xù)下一步且不外部化引用
      callback();
    },
  ],
};

其它例子使用不同的模塊格式:

webpack.config.js

module.exports = {
  externals: [
    function (ctx, callback) {
      // 該外部化的模塊,是一個(gè) `commonjs2` 的模塊,且放在 `@scope/library` 目錄中
      callback(null, '@scope/library', 'commonjs2');
    },
  ],
};

webpack.config.js

module.exports = {
  externals: [
    function (ctx, callback) {
      // 該外部化模塊是一個(gè)全局變量叫作 `nameOfGlobal`.
      callback(null, 'nameOfGlobal');
    },
  ],
};

webpack.config.js

module.exports = {
  externals: [
    function (ctx, callback) {
      // 該外部化模塊是一個(gè)在`@scope/library`模塊里的命名導(dǎo)出(named export)。
      callback(null, ['@scope/library', 'namedexport'], 'commonjs');
    },
  ],
};

webpack.config.js

module.exports = {
  externals: [
    function (ctx, callback) {
      // 外部化模塊是一個(gè) UMD 模塊
      callback(null, {
        root: 'componentsGlobal',
        commonjs: '@scope/components',
        commonjs2: '@scope/components',
        amd: 'components',
      });
    },
  ],
};

RegExp

匹配給定正則表達(dá)式的每個(gè)依賴,都將從輸出 bundle 中排除。

webpack.config.js

module.exports = {
  //...
  externals: /^(jquery|\$)$/i,
};

這個(gè)示例中,所有名為 jQuery 的依賴(忽略大小寫),或者 $,都會(huì)被外部化。

混用語(yǔ)法

有時(shí)你需要混用上面介紹的語(yǔ)法。這可以像以下這樣操作:

webpack.config.js

module.exports = {
  //...
  externals: [
    {
      // 字符串
      react: 'react',
      // 對(duì)象
      lodash: {
        commonjs: 'lodash',
        amd: 'lodash',
        root: '_', // indicates global variable
      },
      // 字符串?dāng)?shù)組
      subtract: ['./math', 'subtract'],
    },
    // 函數(shù)
    function ({ context, request }, callback) {
      if (/^yourregex$/.test(request)) {
        return callback(null, 'commonjs ' + request);
      }
      callback();
    },
    // 正則表達(dá)式
    /^(jquery|\$)$/i,
  ],
};

byLayer

?function object?

按層指定 externals:

webpack.config.js

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

externalsType

?string = 'var'?

指定 externals 的默認(rèn)類型。當(dāng) external 被設(shè)置為 amd,umd,system 以及 jsonp 時(shí),output.libraryTarget 的值也應(yīng)相同。例如,你只能在 amd 庫(kù)中使用 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' 相同,但是會(huì) await 結(jié)果(適用于 async 模塊)
  • ?'self'?
  • ?'system'?
  • ?'script'?
  • ?'this'?
  • ?'umd'?
  • ?'umd2'?
  • ?'var'?
  • ?'window'?

webpack.config.js

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

externalsType.commonjs

將外部的默認(rèn)類型指定為“commonjs”。Webpack 將為模塊中使用的外部生成類似 const X = require('...') 的代碼。

示例

import fs from 'fs-extra';

webpack.config.js

module.exports = {
  // ...
  externalsType: 'commonjs',
  externals: {
    'fs-extra': 'fs-extra',
  },
};

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const fs = require('fs-extra');

請(qǐng)注意,輸出產(chǎn)物中會(huì)有一個(gè) require()。

externalsType.global

將外部的默認(rèn)類型指定為 'global'。Webpack 會(huì)將 external 作為全局變量讀取到 globalObject。

示例

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

module.exports = {
  // ...
  externalsType: 'global',
  externals: {
    jquery: '$',
  },
  output: {
    globalObject: 'global',
  },
};

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = global['$'];
jq('.my-element').animate(/* ... */);

externalsType.module

將 externals 類型設(shè)置為 'module',webpack 將會(huì)在 module 中為外部引用生成形如 import * as X from '...' 的代碼。

確保首先把 experiments.outputModule 設(shè)置為 true, 否則 webpack 將會(huì)報(bào)錯(cuò)。

Example

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

module.exports = {
  experiments: {
    outputModule: true,
  },
  externalsType: 'module',
  externals: {
    jquery: 'jquery',
  },
};

將會(huì)轉(zhuǎn)換為類似下面的代碼:

import * as __WEBPACK_EXTERNAL_MODULE_jquery__ from 'jquery';

const jq = __WEBPACK_EXTERNAL_MODULE_jquery__['default'];
jq('.my-element').animate(/* ... */);

請(qǐng)注意,輸出產(chǎn)物中會(huì)有一個(gè) import 語(yǔ)句。

externalsType.node-commonjs

將 externals 類型設(shè)置為 'node-commonjs',webpack 將從 module 中導(dǎo)入 createRequire 來(lái)構(gòu)造一個(gè) require 函數(shù),用于加載模塊中使用的外部對(duì)象。

Example

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

module.export = {
  experiments: {
    outputModule: true,
  },
  externalsType: 'node-commonjs',
  externals: {
    jquery: 'jquery',
  },
};

將會(huì)轉(zhuǎn)換為類似下面的代碼:

import { createRequire } from 'module';

const jq = createRequire(import.meta.url)('jquery');
jq('.my-element').animate(/* ... */);

請(qǐng)注意,輸出包中會(huì)有一個(gè) import 語(yǔ)句。

externalsType.promise

將外部的默認(rèn)類型指定為 'promise'。Webpack 會(huì)將 external 讀取為全局變量(類似于 'var')并為它執(zhí)行 await。

Example

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

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

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = await $;
jq('.my-element').animate(/* ... */);

externalsType.self

將外部的默認(rèn)類型指定為 'self'。 Webpack 會(huì)將 external 作為 self 對(duì)象上的全局變量讀取。

示例

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

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

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = self['$'];
jq('.my-element').animate(/* ... */);

externalsType.script

將 external 的默認(rèn)類型指定為 'script'。Webpack 會(huì)將 external 作為腳本加載,并使用 HTML <script> 元素暴露預(yù)定義的全局變量。<script> 標(biāo)簽將在腳本加載后被移除。

Syntax

module.exports = {
  externalsType: 'script',
  externals: {
    packageName: [
      'http://example.com/script.js',
      'global',
      'property',
      'property',
    ], // properties are optional
  },
};

如果你不打算定義任何屬性,你可以使用簡(jiǎn)寫形式:

module.exports = {
  externalsType: 'script',
  externals: {
    packageName: 'global@http://example.com/script.js', // no properties here
  },
};

請(qǐng)注意,output.publicPath 不會(huì)被添加到提供的 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]));

下面示例是針對(duì)上面示例新增了屬性配置:

module.exports = {
  // ...
  externalsType: 'script',
  externals: {
    lodash: [
      'https://cdn.jsdelivr.net/npm/lodash@4.17.19/lodash.min.js',
      '_',
      'head',
    ],
  },
};

當(dāng)你 import 'loadsh' 時(shí),局部變量 head 和全局變量 window._ 都會(huì)被暴露:

import head from 'lodash';
console.log(head([1, 2, 3])); // logs 1 here
console.log(window._.head(['a', 'b'])); // logs a here

externalsType.this

將 external 的默認(rèn)類型指定為 'this'。Webpack 會(huì)將 external 作為 this 對(duì)象上的全局變量讀取。

示例:

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

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

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = this['$'];
jq('.my-element').animate(/* ... */);

externalsType.var

將 external 的默認(rèn)類型指定為 'var'。Webpack 會(huì)將 external 作為全局變量讀取。

示例:

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

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

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = $;
jq('.my-element').animate(/* ... */);

externalsType.window

將 external 的默認(rèn)類型指定為 'window'。Webpack 會(huì)將 external 作為 window 對(duì)象上的全局變量讀取。

示例:

import jq from 'jquery';
jq('.my-element').animate(/* ... */);

webpack.config.js

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

將會(huì)轉(zhuǎn)換為類似下面的代碼:

const jq = window['$'];
jq('.my-element').animate(/* ... */);

externalsPresets

?object?

為特定的 target 啟用 externals 的 preset。

選項(xiàng) 描述 輸入類型
electron 將 main 和預(yù)加載上下文中常見的 electron 內(nèi)置模塊視為 external 模塊(如 electron,ipc 或 shell),使用時(shí)通過(guò) require() 加載。 boolean
electronMain 將 main 上下文中的 electron 內(nèi)置模塊視為 external 模塊(如 appipc-main 或 shell),使用時(shí)通過(guò) require() 加載。 boolean
electronPreload 將預(yù)加載上下文的 electron 內(nèi)置模塊視為 external 模塊(如 web-frame,ipc-renderer 或 shell),使用時(shí)通過(guò) require() 加載。 boolean
electronRenderer 將 renderer 上下文的 electron 內(nèi)置模塊視為 external 模塊(如 web-frame、ipc-renderer 或 shell),使用時(shí)通過(guò) require() 加載。 boolean
node 將 node.js 的內(nèi)置模塊視為 external 模塊(如 fspath 或 vm),使用時(shí)通過(guò) require() 加載。 boolean
nwjs 將 NW.js 遺留的 nw.gui 模塊視為 external 模塊,使用時(shí)通過(guò) require() 加載。 boolean
web 將 http(s)://... 以及 std:... 視為 external 模塊,使用時(shí)通過(guò) import 加載。(注意,這將改變執(zhí)行順序,因?yàn)?external 代碼會(huì)在該塊中的其他代碼執(zhí)行前被執(zhí)行)。 boolean
webAsync 將 'http(s)://...' 以及 'std:...' 的引用視為 external 模塊,使用時(shí)通過(guò) async import() 加載。(注意,此 external 類型為 async 模塊,它對(duì)執(zhí)行會(huì)產(chǎn)生各種副作用) boolean

請(qǐng)注意,如果打算使用與Node.js相關(guān)的預(yù)設(shè)輸出ES模塊,Webpack將會(huì)將默認(rèn)的externalsType設(shè)置為node-commonjs,這將使用createRequire來(lái)構(gòu)建一個(gè)require函數(shù),而不是使用require()函數(shù)。

示例:

使用 node 的 preset 不會(huì)構(gòu)建內(nèi)置模塊,而會(huì)將其視為 external 模塊,使用時(shí)通過(guò) require() 加載。

webpack.config.js

module.exports = {
  // ...
  externalsPresets: {
    node: true,
  },
};


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)