WebpackDllPlugin中添加例外
TL; DR
要使得一个在Dll中的包在webpack构建时不被跳过,可以使用别名。
背景
在提升webpack构建性能时,很多人都会选择使用webpackDllPlugin,将不常更新的第三方依赖(如react、lodash等)打包到一个固定的vendor之中,并在之后的构建中直接跳过它们。
一般来说,在需要更新其中的依赖版本时,重新构建一次dll,生成一个新的vendor和manifest即可。然而,最近我遇到一个场景,一个vendor同时被多个项目共同引用,要更新就必须同时更新,所以很难更新它的内容。
在这种情况下,如果个别项目需要升级其中一个依赖的版本,就有点麻烦了。
下面我介绍下我的解决思路:
别名
最开始接到这个问题时(不动dll的情况下,更新个别项目的echarts版本),第一反应就是利用别名处理。
别名分为几个不同的层次,比如有webpack的alias,有require的cache等,甚至还有最暴力的手段,直接把echarts包重新发一个,改名叫myecharts。
npm别名
直接clone echarts,然后重新发个myecharts,应当算是下下之选,一方面多了一个维护的成本,另外一方面即使echarts被改名为myecharts,它的依赖项并不会跟着改名。这样就有可能出现虽然本地安装了更新版本的依赖,但是打包之后还是旧版本的情况。还是会有可能出bug。
因此,还是应该首先考虑下工具层别名的处理。
webpack 别名
webpack的resolve里面,可以设置包的别名。要确定这个别名能否发挥作用,就需要先确定下 webpack 别名与 dllPlugin 的先后关系。
如果是先DllPlugin处理,再解析webpack alias,那么这种方法可行,反之则不行。
为了确定这个顺序,需要看下dllPlugin输出文件中的 manifest.json
:
1{ 2 "name": "vendorLibrary", 3 "content": { 4 "./node_modules/prop-types/index.js": { 5 "id": 0, 6 "buildMeta": { "providedExports": true } 7 }, 8 "./node_modules/react/index.js": { 9 "id": 1, 10 "buildMeta": { "providedExports": true } 11 }, 12 "./node_modules/ramda/es/internal/_curry2.js": { 13 "id": 2, 14 "buildMeta": { 15 "exportsType": "namespace", 16 "providedExports": ["default"] 17 } 18 }, 19 "__others__": "省略其它内容" 20 } 21}
上面是截取的manifest.json中的部分内容,从它的结构中可以看出,key是node_modules
下的具体文件名。
这样也就能判断出,修改webpack alias是没有用的了,因为无论再怎么改,最终映射到node_modules中的具体文件名是不一样的。
因此这种方案不可行。
node别名
另一种方式,是修改node中的require。
比较常见的使用方式,是引用一个npm包 module-alias。
它通过修改require.cache
等操作,影响了nodejs中的路径解析过程。所以一般会被用来简化引用路径。
但是考虑到无论怎样简化,最终对应到node_modules
中的文件名是不变的,所以理论上来说这种方式也起不到相应的效果。
npm别名 - 2
npm从v6.9.0版开始,支持将一个包安装到不同的两个位置。
比如说通过如下的命令:
1npm i echarts-410@npm:echarts@4.1.0
就可以在node_modules中生成一个 `echarts-410 的目录,与之前安装的旧版本所处目录不同。
然后设置webpack别名,将echarts解析到echarts-410
1const config = { 2 resolve: { 3 alias: { 4 'echarts': 'echarts-410' 5 } 6 } 7}
真正解析到的位置就会是 node_modules/echarts-410/xxx
这样的文件,也就匹配不到manifest.json
中的key了。
只要匹配不到manifest.json
中的key,自然在webpack打包过程中就不会被略过。
如此一来,就可以实现在不动dll的情况下,使用echarts的另一个版本。
注意如果有内部依赖,如依赖了 echarts/map/json/china.json
,那么就需要保证新版和旧版的路径一致,不然的话就需要修改引用语句,适配新版本。
总结
在解决webpackDllPlugin中添加例外这个问题时,尝试了几种方法。
其中 webpack 别名和node别名不能正常工作,重发npm包的方式代价比较大,相对最轻量的方案,是通过npm的别名机制,将同一个包安装到两个不同的位置上。从而绕过dllPlugin的处理。