blog
blog copied to clipboard
`npm link` 的使用踩坑记录
我有两个项目 A 和 B。其中:
- A 是一个 npm 包
- B 是一个 Webpack 项目,它通过
npm install A的方式安装 A
现在,我想要在开发阶段直接让 B 安装本地的 A,这样当我频繁修改 A 时,无需 publish 到 npm 里。
踩坑开始。
Webpack 报错“找不到 core-js“
经过排查,问题原因如下。
前提:
- A 是使用最新的 js 语法写的,且在打包时没有注入任何 polyfill
- 为此,B 的 Webpack 启用了
@babel/preset-env,这个插件会根据代码里的使用情况自动注入来自 core-js 的 polyfill
报错的原因是,当将 A link 进 B 之后,Webpack 自动给 A 的代码注入了 import 'core-js/xxx 的代码,然后由于 A 在 B 中是一个软链接,B 中的 Webpack 会从 A/node_modules/core-js 读取 corejs,而 A 并没有安装 core-js,所以报错了。
一开始,我是通过给 webpack 设置 resolve.symlinks: false 的方式来解决这个问题的。设置后,webpack 对于软链接的项目,会改为从自身项目里寻找 deps。但是,这样会带来两个问题。
resolve.symlinks: false 的第一个问题:webpack --watch 对项目 A 失效了
在没设置前,webapck --watch 对软链接项目内的代码修改也会触发,而设置后,虽然控制台有动静,但实际上并没有用最新代码。
resolve.symlinks: false 的第二个问题:需要临时安装项目 A 的依赖
在将 A link 进 B 后,npm 会从 B/node_modules 中删掉 A 的所有 deps(类似于 npm uninstall A),而如果 B 没有这些 deps,那么 webpack 还是会报错“找不到模块 xxx“,此时就需要临时把 A 的 deps 安装进 B 中,等开发完了再卸载,很麻烦。
改为在项目 A 中安装 core-js 也有问题
为此,我决定在项目 A 中 npm i -D core-js,并且不设置 resolve.symlinks: false。这样一来,webpack 能从项目 A 中找到 core-js,也不会有上面的两个问题。
一开始挺好的,但是直到有一天,我给 A 和 B 同时安装了 react 和 react-dom。在 B 运行时,浏览器的控制台会报错:使用 hooks 失败,可能原因列了很多,其中一条是“使用了不同版本的 react”。有了前面的经验,我立马明白问题的原因了:A 使用了 A/node_modules/react 而 B 使用了 B/node_modules/react,导致出现了这个问题。
所以,对于 react 这类特殊的 npm 包,必须得让 webpack 只从 B/node_modules 里读取。
最终解决方案:resolve.alias
resolve: {
alias: {
react: path.dirname(require.resolve('react/package.json')),
'react-dom': path.dirname(require.resolve('react-dom/package.json')),
'core-js': path.dirname(require.resolve('core-js/package.json')),
}
}
有了上面的配置,就能确保 webpack 在读取 core-js、react 和 react-dom 时,都从 B/node_modules 里读取,这样也不用给 A 安装 core-js 了,算是完美解决了问题。