为什么自己写的组件库被引用总是报错——详解webpack的library和libraryTarget

7次阅读

共计 2127 个字符,预计需要花费 6 分钟才能阅读完成。

如果我们仅仅是实现一个项目,我们大概率不会关注到 webpack output 中的这两个属性。但是如果我们是实现一个组件库,那么这两个属性就变得至关重要了。本文从自己之前遇到的一个问题说起,继而引申出 library 和 libraryTarget 属性。
1. 故事起源
当我自己开始写第一个组件库的时候,很快我就撸好了框架的代码,然后我兴致冲冲的把我的组件库引入到我的项目中,我记得那时候我是这么写的:
组件库:
import Feeds from ‘@/components/feeds/index’;
export {
Feeds,
};
主项目:
import Feeds from ‘@/tencent/newsH5Ad’;

// 一些其他代码

<Feeds data=’xxx’>

然后我就收获了一个报错,Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: null。啊?难道是我的最终输出代码有问题?我检查了一下最终输出的代码,没有问题,Feed 组件的代码也在里面。这个问题我查了很久,都没有答案,最后才发现是 webpack 打包的问题。这就涉及到了本文的主角,library 和 libraryTarget。
2.
2. library 和 libraryTarget
我们都知道,webpack 可以将不同的模块化方式(commonjs, AMD, CMD, ES6 Module)的代码打包。那我们打出来的代码包其实也可以按不同的模块化方式生成,所以:

libraryTarget 就是配置 webpack 打包内容的模块方式的参数而 library 就是 webpack 打包内容的名字

所以 library 规定了组件库返回值的名字,libraryTarget 规定了返回值的编码格式。
libraryTarget 的配置选项可以分为四大类:
2.1 按不同的模块方式生成
也就是我们这个问题的解决方法,由于我写的是一个 React 的 UI 组件库,所以我们需要 commonjs 的模块方式。因此只需要在 webpack.config.js 中配置这一项即可:
module.exports = {
entry: ‘./src/index.js’,
output: {
filename: ‘index.js’,
// library: ‘MyLibrary’, // 模块名称
libraryTarget: ‘commonjs2’, // 输出格式
},
// 其他代码
}
事实上,你可以选择的选项有:

commonjs/commonjs2: 将你的 library 暴露为 CommonJS 模块 amd: 将你的 library 暴露为 amd 模块 umd: 将你的 library 暴露为所有的模块定义下都可运行的方式
其中 AMD 和 UMD 需要指定 library,如果不声明组件库则不能正常运行。这是为了在浏览器上通过 script 标签加载时,用 AMD 模块方式输出的组件库可以有明确的模块名。如:
define(“MyLibrary”, [], function() {
return _entry_return_; // 此模块返回值,是入口 chunk 返回的值
});
注意:commonjs 和 commonjs2 几乎相同,只不过 commonjs 只包含 exports,而 commonjs2 还包含 module.exports,所以直接使用 commonjs2 即可。
2.2 生成为一个变量
libraryTarget 的默认值是 var,顾名思义,就是将组件库入口起点的返回值生成一个变量。如:
var MyLibrary = _entry_return_;
也可以选择‘assign’,那样的话将默认生成和一个全局的变量。不管是 var 还是 assign,都需要设置 library 的名称,否则就会报错。
2.3 生成一个为一个对象的属性
和第二种情况差不多,只不过会把这个变量赋值给某个对象,作为它的一个属性存在。可以选择的选项有:
this: 返回值成为 this 的一个属性 window: 返回值成为 window 的一个属性 global: 返回值成为 global 的一个属性
例如:
this[“MyLibrary”] = _entry_return_;
window[“MyLibrary”] = _entry_return_;
global[“MyLibrary”] = _entry_return_;
可以看到,这种情况下也必须指定 library 的名字。
2.4 异步生成方式
在这种情况下,libraryTarget 的值为‘jsonp’,组件库入口起点的返回值,会被包裹到一个 jsonp 包装容器中,并配合 webpack 的 externals 使用——组件库的依赖由 externals 指定。如:
MyLibrary(_entry_return_);
3. 总结
本文介绍了 webpack 中 libraray 和 libraryTarget 的相关内容,解释了为什么不设置它们时使用 webpack 打包出来的组件库会有问题。一般情况下,作为 vue 或者 react 组件库,libraryTarget 在 commonjs2,amd,umd 中三者择其一即可。
参考文献
《webpack 文档》

正文完
 0