最近把自己(未完待续)的轮子库 cui-demo
尝试发布到 npm 上,在测试项目中尝试引用时,报了一个无情的错。
「不看废话版」
排除了我的代码问题后,这个报错的原因应该是我的轮子库没有成功获取到测试项目(宿主环境)的依赖react
和react-dom
。解决方法如下:
- 在 webpack 配置中将
react
和react-dom
标记为externals
(这同时要求output.libraryTarget
为umd
),使轮子库可以在运行时获取到宿主环境的依赖。即
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 // webpack.config.js
module.exports = {
// ...
externals: {
react: {
commonjs: 'react',
commonjs2: 'react',
amd: 'react',
root: 'React',
},
'react-dom': {
commonjs: 'react-dom',
commonjs2: 'react-dom',
amd: 'react-dom',
root: 'ReactDOM',
},
}
};- 在
package.json
中为react
和react-dom
添加同伴依赖peerDependencies
的映射,这是为了检测宿主环境中这两项依赖的版本如果低于你规定的最低版本,那么在 npm@3 中会给出警告(npm@1 和 npm@2 中会自动安装)。配置如下:
1
2
3
4
5
6
7 {
// ...
"peerDependencies": {
"react": "^16.8.4",
"react-dom": "^16.8.4"
}
}
Debug 开始:
为什么说这个错误提示无情呢?让我们来慢慢走进这个报错世界:
它让我转到 https://reactjs.org/docs/error-decoder.html/?invariant=321 去看完整信息。好,我知道这个报错是非法 Hook 调用(Invalid Hook Call)的问题了。
然后我继续看 https://fb.me/react-invalid-hook-call 提供的 debug 方法。
Breaking the Rules of Hooks
违反 Hooks 规则的错误,我用我的狗头保证,不是的🐶。Mismatching Versions of React and React DOM
React DOM 版本与 React 不匹配(低于16.8.0),也排除了。(见下图)Duplicate React
意外地引入了两个 React ,还是排除了。(见下图)而且我的轮子库的
package.json
中对react
和react-dom
的版本设置也是符合要求的:1
2
3
4
5
6
7
8{
// ...
"devDependencies": {
// ...
"react": "^16.8.4",
"react-dom": "^16.8.4"
}
}在这两个证据之下,我不得不怀疑自己的狗头是不是保不住了… 难不成我真的违反了 Hooks 的规则??不应该呀… 如果真是这样,那我平时自己写轮子运行的时候就会报错不通过了呀…
带着疑问,我决定去参考 ant-design 和 element-ui 的
package.json
文件,看看它们是如何配置依赖的。后来发现它们还在peerDependencies
中指定了兼容的版本号。虽说我的轮子库对react
/react-dom
的依赖宽松到>=16.8.4 <17.0.0
,完全兼容测试项目的^16.12.0
,peerDependencies
在这应该不起作用,但为了防止其他用户使用我这个轮子库时宿主环境的依赖版本低于要求,我还是得给package.json
添加这个映射:1
2
3
4
5
6
7
8
9
10
11
12
13{
...
"devDependencies": {
...
"react": "^16.8.4",
"react-dom": "^16.8.4"
},
+ "peerDependencies": {
+ "react": "^16.8.4",
+ "react-dom": "^16.8.4"
+ },
"dependencies": {}
}抱着“瞎猫碰上死耗子”的心态,我重新把更改后的轮子库发布到 npm 中。但最后这个更改果然并没有让
#321
的报错消失。无情展露无余。
在几次顽强地挣扎和重试后,我真的摸不着头脑了。谷歌了很多篇文章,终于,老天不负有心人,我终于找到了问题所在——原来项目中真的存在着多个 react
实例, cui-demo
打包时 webpack 把 react
一起把它打包进 bundles 里了:
为了解决这个问题,我应该在 webpack 构建时将 react
和 react-dom
标记为 externals
(外部扩展),这样它们就不会被打包进 bundles 中,而是在运行时自动从宿主环境中获取这些扩展依赖。配置如下:
1 | // webpack.config.js |
好的,再重新发布看看。
YES!终于成功了!在 webpack 中排除依赖打包进外部 bundles 中即可解决我测试项目中 Minified React error #321
的报错~戳此体验一下新鲜出炉的轮子库 cui-demo
吧!
参考资料: