library & libraryTarget & externals & globalObject
module.exports = {
output: {
library: ,
libraryTarget: "",
}
}
library是指定义一个全局使用的名称变量
libraryTarget是指设置library的暴露方式,是commonjs、commonjs2、umd还是this、var等。
这三个属性的特征都是在公共对象上export出你的方法函数。特点无非是减少了变量冲突的可能性,但是依旧没有解决问题,只有global模式支持在node环境中,还必须设置target为node不然也是不支持的。
这两个属性,是符合模块化规范的产物,commonjs是在export上定义library设置的变量,commonjs2是用module.export直接export的。amd的依赖前置方案在浏览器、node中都必须额外引入RequireJS来使用。
amd那就是在define的方法中设置了library,这样就能符合RequireJS的使用规范。
兼容的模块化定义
但是如果你想做到这一点,必须要额外设置,umdNamedDefine: true,globalObject: ‘this’,umdNamedDefine为设置amd前置名称使用library设置的变量,globalObject为改变全局指向。
这样就能保证你的库在node和浏览器中通用了。当然便捷的引入一定会带来一定的冗余,这就看你如何取舍了。
最后建议,如果目标明确,我只是兼容nodejs,那么选择commonjs/commonjs2,如果只兼容浏览器,那就选择暴露变量的方式,如果想通用,那就选择umd的方式,对于不同的情况做多种处理方式,是非常明智的选择。
library
暴露一个自定义库
我们需要通过 output.library 配置项暴露从入口导出的内容。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
+ library: "webpackNumbers",
},
};
<script src="https://example.org/webpack-numbers.js"></script>
<script>
window.webpackNumbers.wordToNum('Five');
</script>
然而它只能通过被 script 标签引用而发挥作用,它不能运行在 CommonJS、AMD、Node.js 等环境中。
作为一个库作者,我们希望它能够兼容不同的环境,也就是说,用户应该能够通过以下方式使用打包后的库:
const webpackNumbers = require('webpack-numbers');
// ...
webpackNumbers.wordToNum('Two');
require(['webpackNumbers'], function (webpackNumbers) {
// ...
webpackNumbers.wordToNum('Two');
});
<!DOCTYPE html>
<html>
...
<script src="https://example.org/webpack-numbers.js"></script>
<script>
// ...
// Global variable
webpackNumbers.wordToNum('Five');
// Property in the window object
window.webpackNumbers.wordToNum('Five');
// ...
</script>
</html>
我们更新 output.library 配置项,将其 type 设置为 'umd':
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
+ library: {
+ name: 'webpackNumbers',
+ type: 'umd',
+ },
},
};
现在 webpack 将打包一个库,其可以与 CommonJS、AMD 以及 script 标签使用。
外部化 lodash
现在,如果执行 webpack,你会发现创建了一个体积相当大的文件。如果你查看这个文件,会看到 lodash 也被打包到代码中。在这种场景中,我们更倾向于把 lodash 当作 peerDependency。也就是说,consumer(使用者) 应该已经安装过 lodash 。因此,你就可以放弃控制此外部 library ,而是将控制权让给使用 library 的 consumer。
这可以使用 externals 配置来完成:
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
library: {
name: "webpackNumbers",
type: "umd"
},
},
+ externals: {
+ lodash: {
+ commonjs: 'lodash',
+ commonjs2: 'lodash',
+ amd: 'lodash',
+ root: '_',
+ },
+ },
};
这意味着你的 library 需要一个名为 lodash 的依赖,这个依赖在 consumer 环境中必须存在且可用。
外部化的限制
对于想要实现从一个依赖中调用多个文件的那些 library:
import A from 'library/one';
import B from 'library/two';
// ...
无法通过在 externals 中指定整个 library 的方式,将它们从 bundle 中排除。而是需要逐个或者使用一个正则表达式,来排除它们。
module.exports = {
//...
externals: [
'library/one',
'library/two',
// 匹配以 "library/" 开始的所有依赖
/^library\/.+$/,
],
};
output.globalObject
当输出为 library 时,尤其是当 libraryTarget 为 'umd'时,此选项将决定使用哪个全局对象来挂载 library。为了使 UMD 构建在浏览器和 Node.js 上均可用,应将 output.globalObject 选项设置为 'this'。对于类似 web 的目标,默认为 self。
示例:
webpack.config.js
module.exports = {
// ...
output: {
library: 'myLib',
libraryTarget: 'umd',
filename: 'myLib.js',
globalObject: 'this',
},
};
externals
我们通常在做项目时可能会把第三方库打包到bundle中,
如果不想把第三方库打包到bundle中,这就有了externals。官方的使用externals比较简单,只需三步
1.在HTML中引入第三方库的cdn
2.在webpack中配置externals
externals: {
jquery: "jQuery",
}
3.在js中引用
const $ = require("jquery");
$("#content").html("<h1>hello world</h1>");
好,现在我们可以随心所欲的使用jquery插件并保证不会打包到bundle中。
详解:
防止将某些 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(/* ... */);
具有外部依赖(external dependency)的 bundle 可以在各种模块上下文(module context)中使用,例如 CommonJS, AMD, 全局变量和 ES2015 模块。外部 library 可能是以下任何一种形式:
可以接受以下语法……
字符串
请查看上面的例子。属性名称是 jquery,表示应该排除 import $ from 'jquery' 中的 jquery 模块。为了替换这个模块,jQuery 的值将被用来检索一个全局的 jQuery 变量。换句话说,当设置为一个字符串时,它将被视为全局的(定义在上面和下面)。
另一方面,如果你想将一个符合 CommonJS 模块化规则的类库外部化,你可以提供外联类库的类型以及类库的名称。
如果你想将 fs-extra 从输出的 bundle 中剔除并在运行时中引入它,你可以如下定义:
module.exports = {
// ...
externals: {
'fs-extra': 'commonjs2 fs-extra', // 转化成 commonJS 格式
},
};
这样的做法会让任何依赖的模块都不变,正如以下所示的代码:
import fs from 'fs-extra';
会将代码编译成:
const fs = require('fs-extra');
补充
补充:四个关键 output 选项对照:
output.library:暴露给外部使用的全局变量名(如MyLib)。output.libraryExport:指定要导出模块的哪个 export(如default)。output.libraryTarget:暴露方式:
var(默认):把返回值挂到var <library>上。this/window/global:挂到对应全局对象。commonjs/commonjs2:以module.exports形式暴露(Node 端)。umd:同时支持 AMD、CommonJS、全局变量(最通用,构建产物体积也最大)。module(webpack 5):输出 ES Module 风格的 export。output.globalObject:当libraryTarget是umd/this时使用的全局对象名,默认是window(在 Node 环境下需设为global)。externals:声明"不打包的依赖",由使用方运行时提供(如通过 CDN 引入的 React)。
来源整理自:我的有道云笔记



