项目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"
  },

这些只是依赖包的其中一部分,每一个点拿出来均可以是一个深刻研究的问题,所以这里主要阐述一下各类包的主要逻辑与联系(其实就是各类坑)。css

vue、vue-loader、vue-template-compiler :

先看vue-template-compiler的官方说明:html

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

vue-router :

在这里把vue-router拿出来讲,是由于在这里踩了一个坑。在此次预研任务里,主要目标就是理解webpack打包构建的原理和过程。在网上看了诸多笔记和教程,没有一篇提到过与vue-router发生冲突或者报错的。可是项目在升级webpack4后页面数据<router-view></router-view>的部分渲染不出来,报错以下:
图片描述
图片描述
在网上搜索了不少,以及去github看了issue,没有定向到问题所在。总结出大概方向应该是解析器版本没对上,而后vue-loader什么的,一个个版本都试过了也没有用。
最后把vue-router从2.5.x升级到最新2.8.1,立马解决。node

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兼容性良好。由于项目用的是这个,因此继续沿用。webpack

总结在升级依赖时有三个点:

1.更新工具/依赖的时候,第一步必定是尽量把全部核心的依赖所有都升到最新,通常能够解决问题(其实已经作到)。
2.出现报错,首先考虑更新有直接关系的依赖,而不是回想本身以前的更新是否不对。(我就是一直在想是否vue-loader/html-webpack-plugin...等版本不吻合,卡了好久,其实就是vue-router没更新,固然这主要是本身的问题,被网上资料引导了,没看到任何相关问题,就一直没往这方面考虑)。
3.若是须要了解一个依赖包,第一选择是上github,筛选对本身有用的问题;其次再去搜索网上的资源。不建议在没有读懂原理的时候就直接套用网上的配置,即便一时生效,日后可能也是个大坑。git

webpack4.x:SplitChunkPLugin是如何分包的?官方文档

直接采用了官方文档的example 1,以下:es6

splitChunks: {
      cacheGroups: {
        commons: {
          name: 'commons',
          chunks: 'initial',
          minChunks: 2
        }
      }
    }

而后打包(run build),运行成功,耗时从240s缩减为110s,主要的vendor.js体积也从540k减少到了440k左右。github

run dev,能够正常运行,可是过不了多久,就会报内存溢出:web

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的配置有关,从此有机会继续研究一下,会在这里续写。

相关文章
相关标签/搜索