项目webpack2.x迁移到4.x预研笔记
公司项目使用webpack2.x,搭建得比较早,没有用vue-cli(没啥影响),这是大背景。
本项目构建时主要的依赖包:
"dependencies": { "babel-core": "^6.26.0", "es6-promise": "^4.2.4", "eslint-config-vue": "^2.0.2", "vue": "^2.5.16", "vue-router": "^2.8.1", "webpack-cli": "^3.1.0", "webpack-dev-middleware": "^3.1.3", "webpack-hot-middleware": "^2.22.2" }, "devDependencies": { "babel-eslint": "^7.2.3", "babel-loader": "^7.1.4", "babel-polyfill": "^6.23.0", "babel-preset-es2015": "^6.22.0", "babel-preset-es2016": "^6.24.1", "babel-preset-stage-3": "^6.22.0", "copy-webpack-plugin": "^4.5.2", "css-loader": "^0.28.11", "ejs-loader": "^0.3.1", "eslint": "^3.18.0", "eslint-loader": "^2.0.0", "eslint-plugin-html": "^4.0.5", "eslint-plugin-vue": "^2.1.0", "extract-text-webpack-plugin": "^4.0.0-beta.0", "file-loader": "^1.1.11", "html-loader": "^1.0.0-alpha.0", "html-webpack-plugin": "^4.0.0-alpha", "less": "^3.0.4", "less-loader": "^4.1.0", "lodash": "^4.17.4", "node-sass": "^4.9.0", "sass-loader": "^6.0.7", "style-loader": "^0.21.0", "stylus": "^0.54.5", "stylus-loader": "^3.0.2", "url-loader": "^1.0.1", "vue-loader": "^15.2.6", "vue-template-compiler": "^2.5.16", "webpack": "^4.16.2", "webpack-dev-server": "^3.1.1" },
这些只是依赖包的其中一部分,每个点拿出来都可以是一个深入研究的问题,因此这里主要阐述一下各种包的主要逻辑与联系(其实就是各种坑)。
vue、vue-loader、vue-template-compiler :
先看vue-template-compiler的官方说明:
This package can be used to pre-compile Vue 2.0 templates into render functions to avoid runtime-compilation overhead and CSP restrictions.
You will only need it if you are writing build tools with very specific needs. In most cases you should be using vue-loader or vueify instead, both of which use this package internally.
一般情况下,vue-loader与vueify自身会在内部使用此包,只有在比较特殊的情况下才需要用到。单文件组件(.vue为扩展名的文件)就是这种情况的其中一种。
*在使用vue-template-compiler的时候,版本号要和vue版本号一致。
vue-router :
在这里把vue-router拿出来说,是因为在这里踩了一个坑。在这次预研任务里,主要目标就是理解webpack打包构建的原理和过程。在网上看了诸多笔记和教程,没有一篇提到过与vue-router发生冲突或者报错的。但是项目在升级webpack4后页面数据<router-view></router-view>的部分渲染不出来,报错如下:
在网上搜索了很多,以及去github看了issue,没有定向到问题所在。总结出大概方向应该是解析器版本没对上,然后vue-loader什么的,一个个版本都试过了也没有用。
最后把vue-router从2.5.x升级到最新2.8.1,立马解决。
extract-text-webpack-plugin与mini-css-extract-plugin :
extract-text-webpack-plugin主要是为了抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象。
webpack升4之后,extract-text-webpack-plugin的作者一度没有时间更新插件,这时比较多人推荐的是mini-css-extract-plugin,两者作用接近。
现在,extract-text-webpack-plugin的4.0beta版本已经出来了,与webpack4兼容性良好。因为项目用的是这个,所以继续沿用。
总结在升级依赖时有三个点:
1.更新工具/依赖的时候,第一步一定是尽可能把所有核心的依赖全部都升到最新,一般可以解决问题(其实已经做到)。
2.出现报错,首先考虑更新有直接关系的依赖,而不是回想自己之前的更新是否不对。(我就是一直在想是否vue-loader/html-webpack-plugin...等版本不吻合,卡了很久,其实就是vue-router没更新,当然这主要是自己的问题,被网上资料引导了,没看到任何相关问题,就一直没往这方面考虑)。
3.如果需要了解一个依赖包,第一选择是上github,筛选对自己有用的问题;其次再去搜索网上的资源。不建议在没有读懂原理的时候就直接套用网上的配置,即使一时生效,往后可能也是个大坑。
webpack4.x:SplitChunkPLugin是如何分包的?官方文档
直接采用了官方文档的example 1,如下:
splitChunks: { cacheGroups: { commons: { name: 'commons', chunks: 'initial', minChunks: 2 } } }
然后打包(run build),运行成功,耗时从240s缩减为110s,主要的vendor.js体积也从540k减小到了440k左右。
run dev,可以正常运行,但是过不了多久,就会报内存溢出:
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
JavaScript堆内存不足,这里说的 JavaScript 其实就是 Node,Node 是基于V8引擎的,在一般的后端开发语言中,在基本的内存使用上没有什么限制,但是实际上,在 Node 中通过 JavaScript 使用内存时只能使用部分内存(64位系统下约为1.4 GB,32位系统下约为0.7 GB)所以当前端项目庞大的话,webpack 编译时就会占用很多的系统资源,如果超出了V8对 Node 默认的内存限制大小就会出现这个错误,那怎么解决呢?V8依然提供了选项让我们使用更多的内存。Node 在启动时可以传递 --max-old-space-size 或 --max-new-space-size 来调整内存大小的使用限制。
如果遇到 Node 无法分配足够内存给 JavaScript 的情况,可以用这个办法来放宽V8默认的内存限制,避免在执行过程中稍微多用了一些内存就轻易崩溃,既然知道了解决办法那就好办了,在 package.json 里,我们直接把上面v8提供的选项参数直接写入scripts 字段的 node 命令后就好了,示例如下:
"scripts": { "dev": "node --max_old_space_size=4096 build/dev-server.js", "build": "node --max_old_space_size=4096 build/build.js" }
直接在 node 后面写上 --max_old_space_size=4096 就好了,我这里设置的内存大小是4G,这个具体的大小可以根据自己的项目情况来设置就好了。然后再重新运行 npm run dev/build 就可以正常运行和打包了。
最后:打开F12,会发现一些页面子组件还没有被渲染的时候,js方法会被预先加载出来。这里初步推测与splitChunk的配置有关,今后有机会继续研究一下,会在这里续写。