webpack4升级指南

鉴于图书项目编译速度极慢的情况(项目里面module太多了,编译慢很正常)且最近需求不多(很少出现的空挡期)。所以我觉得搞一波webpack升级,看看有没有帮助。webpack于2018年2月25正式发布v4.0.0版本,代号legato。名字是不是很大器,不明觉厉的样子。废话少说下面正式进入主题。(本文的升级配置主要针对vue项目)

一、webpack4更新变化

先说一下webpack4有几个比较重要的更新:webpack4更新日志

1.环境支持: 官方不再支持Node 4,Node 6,最好使用v8.5.0以上稳定版本。支持93%的ES6语法。因为webpack4使用了很多JS新的语法,它们在新版本的 v8 里经过了优化。

2.0配置: 受Parcel打包工具启发,尽可能的让开发者运行项目的成本变低。webpack4不再强制需要 webpack.config.js 作为打包的入口配置文件了,它默认的入口为'./src/'和默认出口'./dist',这对于小项目来说确实是一件不错的事情。

3.mode选项: 告知 webpack 使用相应模式的内置优化。可选 development 或 production,举个栗子。

  1. module.exports = {
  2. mode: 'production'
  3. };

或者从 CLI 参数中传递:

webpack --mode = production

选项 描述
development 会将 process.env.NODE_ENV 的值设为 development。启用 NamedChunksPlugin 和 NamedModulesPlugin。
production 会将 process.env.NODE_ENV 的值设为 production。启用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin.

注意:只设置 NODE_ENV,则不会自动设置 mode

mode: development

  1. // webpack.dev.config.js
  2. module.exports = {
  3. + mode: 'development'
  4. - plugins: [
  5. - new webpack.NamedModulesPlugin(),
  6. - new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }),
  7. - ]
  8. }

mode: production

  1. // webpack.prod.config.js
  2. module.exports = {
  3. + mode: 'production',
  4. - plugins: [
  5. - new UglifyJsPlugin(/* ... */),
  6. - new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }),
  7. - new webpack.optimize.ModuleConcatenationPlugin(),
  8. - new webpack.NoEmitOnErrorsPlugin()
  9. - ]
  10. }

4.插件变化: webpack4删除了CommonsChunkPlugin插件,它使用内置API optimization.splitChunks 和 optimization.runtimeChunk,即webpack会默认为你生成共享的代码块。

5.Rule.loaders: 此选项已废弃(Rule.loaders 是 Rule.use 的别名。可以使用Rule.use)

6.WebAssembly: 开箱即用WebAssembly(这个没用到,不知道是啥)

二、升级webpack4 loader及插件的配置修改

升级webpack4首先需要更新webpack到v4.0.0以上版,然后安装webpack-cli,建议使用cnpm安装,有时候npm安装下载不下来。

  1. npm install --save-dev webpack-cli

项目相关的loader和插件也是需要更新的,不然会报错。接下来介绍一些需要额外配置的loader和插件。

1.vue-loader(更多细节)

Vue Loader v15 现在需要配合一个 webpack 插件才能正确使用:

  1. // webpack.config.js
  2. const VueLoaderPlugin = require('vue-loader/lib/plugin')
  3. module.exports = {
  4. // ...
  5. plugins: [
  6. new VueLoaderPlugin()
  7. ]
  8. }

现在 Vue Loader v15 使用了一个不一样的策略来推导语言块使用的 loader。

拿 <style lang="less"> 举例:在 v14 或更低版本中,它会尝试使用 less-loader 加载这个块,并在其后面隐式地链上 css-loader 和 vue-style-loader,这一切都使用内联的 loader 字符串。

在 v15 中,<style lang="less"> 会完成把它当作一个真实的 *.less 文件来加载。因此,为了这样处理它,你需要在你的主 webpack 配置中显式地提供一条规则:

  1. {
  2. module: {
  3. rules: [
  4. // ... 其它规则
  5. {
  6. test: /\.less$/,
  7. use: [
  8. 'vue-style-loader',
  9. 'css-loader',
  10. 'less-loader'
  11. ]
  12. }
  13. ]
  14. }
  15. }

这样做的好处是这条规则同样应用在 JavaScript 里普通的 *.less 导入中,并且你可以为这些 loader 配置任何你想要的选项。在 v14 或更低版本中,如果你想为一个推导出来的 loader 定制选项,你不得不在 Vue Loader 自己的 loaders 选项中将它重复一遍。在 v15 中你再也没有必要这么做了。如果是用cli搭建的项目,升级webpack4时,别忘记把配置中的样式规则删掉,如下:

  1. //webpack.dev.conf.js
  2. const devWebpackConfig = merge(baseWebpackConfig, {
  3. mode: 'development',
  4. - module: {
  5. - rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap, usePostCSS: true })
  6. - },
  7. //其他配置...
  8. })

webpack.prod.conf.js文件同上修改

鉴于 v15 中的推导变化,如果你导入一个 node_modules 内的 Vue 单文件组件,它的 <script> 部分在转译时将会被排除在外。为了确保 JS 的转译应用到 node_modules 的 Vue 单文件组件,你需要通过使用一个排除函数将它们加入白名单:

  1. {
  2. test: /\.js$/,
  3. loader: 'babel-loader',
  4. exclude: file => (
  5. /node_modules/.test(file) &&
  6. !/\.vue\.js/.test(file)
  7. )
  8. }

Vue Loader v15 还废弃了很多选项,它们应该使用普通的 webpack 模块的规则来配置:

  • loader
  • preLoaders
  • postLoaders
  • postcss
  • cssSourceMap
  • buble
  • extractCSS
  • template

下列选项已经被废弃了,它们应该使用新的 compilerOptions 选项来配置:

  • preserveWhitespace (使用 compilerOptions.preserveWhitespace)
  • compilerModules (使用 compilerOptions.modules)
  • compilerDirectives (使用 compilerOptions.directives)

下列选项已经被改名了:

  • transformToRequire (现在改名为 transformAssetUrls)

2.CommonsChunkPlugin

前面提及到webpack4删除了CommonsChunkPlugin插件,需要使用内置API optimization.splitChunks 和 optimization.runtimeChunk替代,具体替代配置如下:

  1. //webpack.prod.conf.js
  2. optimization: {
  3. //其他配置
  4. runtimeChunk: {
  5. name: 'manifest'
  6. },
  7. splitChunks:{
  8. chunks: 'async',
  9. minSize: 30000,
  10. minChunks: 1,
  11. maxAsyncRequests: 5,
  12. maxInitialRequests: 3,
  13. name: false,
  14. cacheGroups: {
  15. vendor: {
  16. name: 'vendor',
  17. chunks: 'initial',
  18. priority: -10,
  19. reuseExistingChunk: false,
  20. test: /node_modules\/(.*)\.js/
  21. },
  22. styles: {
  23. name: 'styles',
  24. test: /\.(scss|css)$/,
  25. chunks: 'all',
  26. minChunks: 1,
  27. reuseExistingChunk: true,
  28. enforce: true
  29. }
  30. }
  31. }
  32. },

由于CommonsChunkPlugin已经废弃,所以HtmlWebpackPlugin插件配置中的chunksSortMode也不再需要。

  1. plugins: [
  2. //...
  3. new HtmlWebpackPlugin({
  4. filename: process.env.NODE_ENV === 'testing'? 'index.html': config.build.index,
  5. template: 'index.html',
  6. inject: true,
  7. inlineSource:/(app\.(.+)?\.css|manifest\.(.+)?\.js)$/,
  8. minify: {
  9. removeComments: true,
  10. collapseWhitespace: true,
  11. removeAttributeQuotes: true
  12. // more options: https://github.com/kangax/html-minifier#options-quick-reference
  13. },
  14. - chunksSortMode: 'dependency'
  15. }),
  16. ]

3.mini-css-extract-plugin(更多细节)(webpack4新插件)

介绍新插件之前先说一下extract-text-webpack-plugin,相信大家多少会听说过,它的作用是会将所有的入口 chunk(entry chunks)中引用的 *.css,移动到独立分离的 CSS 文件。因此,你的样式将不再内嵌到 JS bundle 中,而是会放到一个单独的 CSS 文件(即 styles.css)当中。 如果你的样式文件大小较大,这会做更快提前加载,因为 CSS bundle 会跟 JS bundle 并行加载。不过在webpack4中推荐使用mini-css-extract-plugin这个插件。具体配置如下:

  1. //webpack.prod.conf.js
  2. const MiniCssExtractPlugin = require("mini-css-extract-plugin")
  3. plugins:[
  4. //其他配置
  5. new MiniCssExtractPlugin({
  6. filename: utils.assetsPath('css/[name].[contenthash].css'),//"[name].css"
  7. chunkFilename: utils.assetsPath('css/[id].css'),//"[id].css"
  8. }),
  9. ]
  1. //webpack.base.conf.js
  2. const MiniCssExtractPlugin = require("mini-css-extract-plugin")
  3. const devMode = process.env.NODE_ENV === 'production'
  4. module: {
  5. rules: [
  6. //...
  7. {
  8. test: /\.css$/,
  9. use: [
  10. devMode ? MiniCssExtractPlugin.loader : 'vue-style-loader',
  11. {
  12. loader: 'css-loader',
  13. options: { importLoaders: 1 }
  14. },
  15. 'postcss-loader'
  16. ]
  17. },
  18. ]
  19. }

再来压缩一下css和js

  1. //webpack.prod.conf.js
  2. const UglifyJsPlugin = require("uglifyjs-webpack-plugin")
  3. const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
  4. optimization: {
  5. minimizer: [
  6. new UglifyJsPlugin({
  7. cache: true,
  8. parallel: true,
  9. sourceMap: true // set to true if you want JS source maps
  10. }),
  11. new OptimizeCSSAssetsPlugin({})
  12. ],
  13. }

我在升级过程中大概升级了这些东西:

  1. "devDependencies" {
  2. //...
  3. "webpack": "^4.27.1",
  4. "webpack-cli": "^3.1.2",
  5. "webpack-dev-server": "^3.1.10",
  6. "vue-loader": "^15.4.2",
  7. "vue-style-loader": "^4.1.2",
  8. "html-webpack-plugin": "^3.2.0",
  9. "html-webpack-inline-source-plugin": "0.0.10",
  10. "babel-loader": "^7.1.3",
  11. "file-loader": "^2.0.0",
  12. "mini-css-extract-plugin": "^0.5.0",
  13. "ts-loader": "^5.3.1",
  14. "url-loader": "^1.1.2",
  15. "vue-html-loader": "^1.2.4",
  16. }

因为不同的项目相关配置不同,所以接下来就可以npm run dev,看看有啥报错,哪个插件、loader有问题,升个级就好了。

三、项目运行起来了

咋回事样式乱了,看一眼控制台,发现:

组件的模板没有识别,这是什么毛病?在翻阅了大量资料后,得知:

在引入组件的时候,除了ES6的 import 之外,还可以用 webpack 的 require,比如,在vue文件里,就写了大量的如下代码:


  1. const KingKong = require('../BookHomeCommon/KingKong.vue');
  2. const BookList = require('../BookHomeCommon/BookList.vue');
  3. const HomeAlert = require('../BookHomeCommon/HomeAlert.vue');
  4. const DoubleElevenToast = require('../Activitys/DoudleEleven/DoubleElevenToast.vue');
  5. const BrandVideo = require('./BrandVideo.vue');

在vue-loader v13.0.0的更新文档中提到:

New

  • Now uses ES modules internally to take advantage of webpack 3 scope hoisting. This should result in smaller bundle sizes.
  • Now uses PostCSS@6.

Breaking Changes

  • The esModule option is now true by default, because this is necessary for ES-module-based scope hoisting to work. This means the export from a *.vue file is now an ES module by default, so async components via dynamic import like this will break:
  1. const Foo = () => import('./Foo.vue')

Note: the above can continue to work with Vue 2.4 + vue-router 2.7, which will automatically resolve ES modules' default exports when dealing with async components. In earlier versions of Vue and vue-router you will have to do this:

  1. const Foo = () => import('./Foo.vue').then(m => m.default)

Alternatively, you can turn off the new behavior by explicitly using esModule: false in vue-loader options.


Similarly, old CommonJS-style requires will also need to be updated:

  1. // before
  2. const Foo = require('./Foo.vue')
  3. // after
  4. const Foo = require('./Foo.vue').default
  • PostCSS 6 might break old PostCSS plugins that haven't been updated to work with it yet.

官方文档说的很清楚:

  • 可以在 vue-loader 的 options 里通过 esModule: false 配置来关闭 ES 模块
  • 同步引入组件,正常用 import,而原来使用 require 引入 ES6 语法的文件(例如:export default {...}),现在需要多加一个 default 属性来引用。异步引入组件,需要用动态 import 语法
  1. 如果有通过 require 引入组件的话,全部改为 require(xxx).default
  2. 如果有异步引入组件的话,全部更新为动态 import 方式,() => import(xxx)

但是在vue-loader v14.0.0中已经移除options里的esModule配置。无法关闭ES模块。那咋整?项目中已经有大量的const Foo = require('./Foo.vue')的用法。一个一个修改,太费时间,这时自定义loader就是一个很好的解决方案。代码如下:

  1. //compatible-es-module.js
  2. module.exports = function(content) {
  3. return content.replace(new RegExp(/require\('\.[/\w\.]+[^(\.png|\.gif|\.jpg)]'\)(\.default)?/,'g'),function(res) {
  4. return /(\.default)$/.test(res) ? res :res + '.default';
  5. });
  6. };
  7. //
  8. module: {
  9. rules: [
  10. {
  11. test: /\.(vue)$/,
  12. loader: './compatible-es-module'
  13. }
  14. ]
  15. }

四、总结

费这么大劲升级,不能没有效果吧,下面看看编译时间对比,这是webpack3编译时长截图:

这是webpack4的:

51万ms和21万ms编译速度足足提高了50%多。(不同项目情况不同,请以实际情况为准)

webpack4还有很多新的特性,有待继续学习。

人们总是对未知的东西,感到恐惧。直面自己的恐惧,学习理解它,你就会进步。(手动耶)

webpack4升级指南的更多相关文章

  1. 企业IT管理员IE11升级指南【17】—— F12 开发者工具

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  2. 企业IT管理员IE11升级指南【16】—— 使用Compat Inspector快速定位IE兼容性问题

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  3. 企业IT管理员IE11升级指南【15】—— 代理自动配置脚本

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  4. 企业IT管理员IE11升级指南【1】—— Internet Explorer 11增强保护模式 (EPM) 介绍

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  5. 企业IT管理员IE11升级指南【2】—— Internet Explorer 11 对Adobe Flash的支持

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  6. 企业IT管理员IE11升级指南【3】—— IE11 新的GPO设置

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  7. 企业IT管理员IE11升级指南【4】—— IE企业模式介绍

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  8. 企业IT管理员IE11升级指南【5】—— 不跟踪(DNT)例外

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

  9. 企业IT管理员IE11升级指南【6】—— Internet Explorer 11面向IT专业人员的常见问题

    企业IT管理员IE11升级指南 系列: [1]—— Internet Explorer 11增强保护模式 (EPM) 介绍 [2]—— Internet Explorer 11 对Adobe Flas ...

随机推荐

  1. 【状压dp】Bzoj2064 分裂

    Description 背景: 和久必分,分久必和... 题目描述: 中国历史上上分分和和次数非常多..通读中国历史的WJMZBMR表示毫无压力. 同时经常搞OI的他把这个变成了一个数学模型. 假设中 ...

  2. otter代码在IDEA远程DEBUG方法

    众所周知,Otter的代码打包后,是通过Jetty启动的,Otter代码的启动脚本中自带了开启Jetty远程DEBUG的脚本,所以我们只需要在启动Otter Manager和Otter Node的时候 ...

  3. BZOJ_3038_上帝造题的七分钟2_线段树

    BZOJ_3038_上帝造题的七分钟2_线段树 题意: XLk觉得<上帝造题的七分钟>不太过瘾,于是有了第二部. "第一分钟,X说,要有数列,于是便给定了一个正整数数列. 第二分 ...

  4. 数字证书中读取PublicKey

    1. 读取https签发证书中的key 1) 在下面的代码中,是实现读取证书字符串来读取key的,CERTIFICATE 就是一个证书的字符串, 而方法cf.generateCertificate() ...

  5. 第十四章——循环神经网络(Recurrent Neural Networks)(第一部分)

    由于本章过长,分为两个部分,这是第一部分. 这几年提到RNN,一般指Recurrent Neural Networks,至于翻译成循环神经网络还是递归神经网络都可以.wiki上面把Recurrent ...

  6. (4)STM32使用HAL库实现串口通讯——理论讲解

    一.查询模式 1. 二.中断模式 1.中断接收. 1.1先看中断接收的流程(以 USART2 为例) 在启动文件中找到中断向量 USART2_IRQHandler 找到USART2_IRQHandle ...

  7. ACM——八大输出方式总结

    个人做题总结,希望能够帮助到未来的学弟学妹们的学习! 永远爱你们的 ----新宝宝 1: 题目描述 Your task is to Calculate a + b. Too easy?! Of cou ...

  8. apigateway-kong(二)admin-api(结合实例比官网还详细)

    部署好kong之后,则需要将我们自己的接口加入到kong中管理,kong提供了比较全面的restful api,每个版本会有所不同,下面的记录基于kong v0.13.x kong的8001端口是re ...

  9. MIP 移动网页加速器视频教程全新发布

    MIP (Mobile Instant Pages - 移动网页加速器) 是百度推出的开源项目,用于移动端页面加速.MIP 技术通过优化浏览器资源加载,前端代码执行及 CDN 缓存加速来加速页面,打造 ...

  10. window.history.back(-1);与window.go(-1);的区别

    history.back(-1):直接返回当前页的上一页,数据全部消息,是个新页面 history.go(-1):也是返回当前页的上一页,不过表单里的数据全部还在 history.back(1) 前进 ...