基于vue多入口项目升级webpack4实践

项目背景简介

  • 多页面应用,每个页面独立entry,单个页面内使用vue-router
  • 基于vue,使用vue-loader加载.vue文件
  • 单页内使用懒加载异步chunk

项目二期上线后,相对不辣么忙,眼看着webpack4也出来快半年了并且日趋稳定,之前虽然写过demo测试使用,但还未在项目中用过,于是择日不如撞日一鼓作气开启了升级【踩坑】之旅

升级之旅

首先保证 node>= 6.11.5,建议使用8以上LTS版本

相关依赖包安装或更新

以下是我的项目中使用到的依赖安装或更新情况,不同项目使用loader、插件不同,这部分得根据自身情况调整
主要依赖:
- webpack安装最新
- webpack-cli安装(启动webpack)
- webpack-dev-server更新至3以上
- vue-loader更新至15以上
- 安装mini-css-extract-plugin
其他:
babel相关依赖、html-webpack-plugin、file-loader、url-loader、sass-loader等我都升级了版本,或者也可以修改完配置后,运行起来看看控制台是否有相关报警再更新
辅助:
推荐安装webpack-bundle-analyzer插件,可以分析构建结果依赖关系

配置变更

接下来来到这次愉快踩坑之旅的重头戏了!

mode

mode是webpack4新增的配置项,也是本次更新的亮点之一,简单理解就是告诉webpack本次构建模式,使其可以对构建使用对应的优化策略。回想之前写工程化配置,也会区分开发模式和生产模式的配置入口,webpack4提供了mode降低了不少配置成本。

mode可被设置为development(默认)或production

module.exports = {
  mode: 'production'
};

development侧重于优化开发体验,production侧重于优化模块体积和线上部署,具体优化内容这里就不搬运官方文档了,对于我的项目而言比较在意的有以下几点:

  • 将自动设置process.env.NODE_ENV为对应值(developmentproduction),原手工配置process.env.NODE_ENV = 'development' ;的代码可以删除
  • production模式将自动加入代码压缩功能,可删除原new UglifyJsPlugin()相关代码

更多说明参考 https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a

optimization

webpack4根据mode配置对构建进行优化,也可以通过覆盖optimization配置进一步定制两种构建模式下的优化策略,并且官方移除了CommonsChunkPlugin插件。

其中项目升级最大的变更就在CommonsChunkPlugin插件的移除和optimizationsplitChunksruntimeChunk的配置
另外由于代码压缩功能将在production模式下自动开启,如果需要对js压缩或css压缩策略定制,则需要覆盖默认optimization.minimizer配置

splitChunks

关于splitChunks可以单独用一篇文章进行详细说明,这里我只是按原项目的缓存策略修改(CommonsChunkPlugin配置): 抽取/node_modules/下第三方依赖作为公共vendor(基于第三方依赖更新频率低)

默认配置下,splitChunks只对懒加载的模块产生影响
注释部分是splitChunks的默认配置,这里仅修改cacheGroups内vendor相关配置,将chunks改成'initial'避免将部分异步加载的较大的第三方依赖也合并到vendor中

splitChunks: {
      //chunks: 'async',
      //minSize: 30000,
      //minChunks: 1,
      //maxAsyncRequests: 5,
      //maxInitialRequests: 3,
      //automaticNameDelimiter: '~',
      //name: true, 
      cacheGroups: {
        vendor: {
        name: 'vendor',
        //@NOTE 配置成all 会把async的也打进来
        chunks: 'initial', 
        priority: -10,
        test: /[\\/]node_modules[\\/]/
        }
    }
}
runtimeChunk

之前的production模式构建会使用CommonChunkPlugin抽取runtime code(这部分概念不了解的可以参考https://webpack.js.org/concepts/manifest/#src/components/Sidebar/Sidebar.jsx)作为单独的chunk,升级后这部分配置需要写到optimization.runtimeChunk中:

  • 默认设置为false,runtime code包含在基于各个entry抽取的第一个chunk中(注意:由于本项目抽取了公用vendor,针对本项目会将所有entry的runtime代码抽取到公用vendor中,vendor将失去浏览器缓存意义)
  • 配置为single string,所有entry的runtime代码将会抽取为一个chunk
  • 配置为一个生成函数,可以基于每个entry独立抽取runtime代码(本项目使用,多个独立页面多入口)

配置成生成函数的代码:

runtimeChunk: {
    name: entrypoint => `manifest~${entrypoint.name}`
},
minimizer

这个接收单个对象或对象数组,指定压缩插件和配置,相对比较简单,这里就不详细描述了

minimizer: [
    // 配置UglifyJsPlugin压缩js文件
    new UglifyJsPlugin({
        cache: true,
        parallel: true,
        sourceMap: true 
    }),
    // 配置css文件压缩
    new OptimizeCSSAssetsPlugin({
        cssProcessor: require('cssnano'),
        cssProcessorOptions: {
        discardComments: {removeAll: true},
        // 避免 cssnano 重新计算 z-index
            safe: true
        },
        canPrint: false
     })
]

mini-css-extract-plugin

webpack4之后,Extract-text-plugin不再适用于css文件抽取,如果还要继续使用安装时只能通过@next版本安装(yarn add extract-text-plugin@next),除此之外contenthash不支持使用在文件名中、会生成一些多余的chunk css文件

mini-css-extract-plugin专用于抽取css文件支持async-loading,只能配合webpack4使用,但目前暂时还不支持HMR(Hot Module Replace),本项目只在production下使用这个插件

配置相对Extract-text-plugin是简单一些

// loader部分(项目使用scss)
test: /\.(sa|sc|c)ss$/,
    use: [
      isProd ? MiniCssExtractPlugin.loader : 'style-loader',
      'css-loader',
      {
        loader: 'sass-loader',
        options: {
                    ... ...
        }
    },
    ],
},

// plugin部分
plugins.push(
    new MiniCssExtractPlugin({
        filename: isProd ? "css/[name].[contenthash:8].css" : "css/[name].css";
    })
);

vue-loader

vue-loader配合webpack4升级到了v15版本,升级之后配置方式发生了一些改变,以下是项目中使用到的部分:

  • 增加一个步骤:需要以plugin方式添加到webpack配置中
  • v15版本之后,使用了不同的策略推导.vue文件中各个语言块使用的loader,将各个语言块视为独立的文件使用webpack中配置了规则的loader处理,由此带来的配置变化就是针对样式处理,webpack.rules中必须显示提供对应loader处理的规则,原vue-loader配置中内联传入的样式相关loader可以去除
  • 鉴于推导变化,<script></script>标签内的js代码将被视为独立的js文件并根据webpack配置使用babel-loader转译;项目配置babel-loader时使用exclude: /node_modules/排除依赖包中代码的转译,如果导入了/node_modules/中的.vue文件,<script>部分将不能被转译,故需要将.vue文件加入到排除白名单中
// 增加一个plugin
const VueLoaderPlugin = require('vue-loader/lib/plugin')
plugin.push( new VueLoaderPlugin())

// rules loader配置
// @UPDATED 
// vue-loader v15+版本 .vue文件中的样式将被抽取出来并认为和独立引入的css文件相同
// 故需要配置单独loader处理
... ...
{
    test: /\.(sa|sc|c)ss$/,
    use: [
        isProd ? MiniCssExtractPlugin.loader : 'style-loader',
        'css-loader',
        {
            loader: 'sass-loader',
            options: {
                includePaths: ['src/static/scss']
            }
        },
    ],
},
// .vue文件
{
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
        // @UPDATED @DEPRECATED
        // v15+版本不再需要提供内联的cssloader配置
        // 如果不去掉会报错
        // loaders: util.cssLoaders({
        //  sourceMap: false,
        //  extract: build,
        //  build: build
        // })
    }
},
// .js文件
{
    test: /\.js$/,
    loader: 'babel-loader',
    exclude: file => (
        // @UPDATED
        // vue-loader v15+版本 
        // /node_modules/中的.vue文件需要经过babel-loader转译
        /node_modules/.test(file) &&
        !/\.vue\.js/.test(file)
    )
}
... ...

其他变更可以参考vue-loader官方文档说明https://vue-loader.vuejs.org/migrating.html#notable-breaking-changes

DEMO

项目webpack4配置demo,可以参考~~
https://github.com/icyfanfan/try-webpack4

参考

webpack官方文档
https://medium.com/webpack/webpack-4-mode-and-optimization-5423a6bc597a
https://medium.com/webpack/webpack-4-import-and-commonjs-d619d626b655
https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366

mini-css-extract-plugin
https://github.com/webpack-contrib/mini-css-extract-plugin

vue-loader
https://vue-loader.vuejs.org/migrating.html#notable-breaking-changes

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 1 Webpack 1.1 概念简介 1.1.1 WebPack是什么 1、一个打包工具 2、一个模块加载工具 3...
    Kevin_Junbaozi阅读 6,636评论 0 16
  • GitChat技术杂谈 前言 本文较长,为了节省你的阅读时间,在文前列写作思路如下: 什么是 webpack,它要...
    萧玄辞阅读 12,671评论 7 110
  • 很难想象生活里没有你的样子,所有的视线都追逐着你突然有天就消失不见,这里已经没有你。后来才发现,心心念念的人永远都...
    _Dtath阅读 284评论 0 0
  • 我的老家在福建省连城县庙前镇的一个不大不小的村庄一一江畲村。今早打电话给老妈。我问起天气。老妈说不冷。往年百公僚打...
    汐鲌阅读 1,190评论 0 2
  • 近年来前往日本旅游的人越来越多,去日本旅行对中国许多年轻人来说越来越像周末去霓虹国度假~(此处满满哒国家富强...
    大白to小黑阅读 253评论 0 0