基于vue多入口項目升級webpack4實踐

項目背景簡介

  • 多頁面應用,每個頁面獨立entry,單個頁面內(nèi)使用vue-router
  • 基于vue,使用vue-loader加載.vue文件
  • 單頁內(nèi)使用懶加載異步chunk

項目二期上線后,相對不辣么忙,眼看著webpack4也出來快半年了并且日趨穩(wěn)定,之前雖然寫過demo測試使用,但還未在項目中用過,于是擇日不如撞日一鼓作氣開啟了升級【踩坑】之旅

升級之旅

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

相關依賴包安裝或更新

以下是我的項目中使用到的依賴安裝或更新情況,不同項目使用loader、插件不同,這部分得根據(jù)自身情況調(diào)整
主要依賴:
- 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本次構建模式,使其可以對構建使用對應的優(yōu)化策略?;叵胫皩懝こ袒渲茫矔^(qū)分開發(fā)模式和生產(chǎn)模式的配置入口,webpack4提供了mode降低了不少配置成本。

mode可被設置為development(默認)或production

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

development側重于優(yōu)化開發(fā)體驗,production側重于優(yōu)化模塊體積和線上部署,具體優(yōu)化內(nèi)容這里就不搬運官方文檔了,對于我的項目而言比較在意的有以下幾點:

  • 將自動設置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根據(jù)mode配置對構建進行優(yōu)化,也可以通過覆蓋optimization配置進一步定制兩種構建模式下的優(yōu)化策略,并且官方移除了CommonsChunkPlugin插件。

其中項目升級最大的變更就在CommonsChunkPlugin插件的移除和optimizationsplitChunks、runtimeChunk的配置
另外由于代碼壓縮功能將在production模式下自動開啟,如果需要對js壓縮或css壓縮策略定制,則需要覆蓋默認optimization.minimizer配置

splitChunks

關于splitChunks可以單獨用一篇文章進行詳細說明,這里我只是按原項目的緩存策略修改(CommonsChunkPlugin配置): 抽取/node_modules/下第三方依賴作為公共vendor(基于第三方依賴更新頻率低)

默認配置下,splitChunks只對懶加載的模塊產(chǎn)生影響
注釋部分是splitChunks的默認配置,這里僅修改cacheGroups內(nèi)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
  • 配置為一個生成函數(shù),可以基于每個entry獨立抽取runtime代碼(本項目使用,多個獨立頁面多入口)

配置成生成函數(shù)的代碼:

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

這個接收單個對象或?qū)ο髷?shù)組,指定壓縮插件和配置,相對比較簡單,這里就不詳細描述了

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文件抽取,如果還要繼續(xù)使用安裝時只能通過@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版本,升級之后配置方式發(fā)生了一些改變,以下是項目中使用到的部分:

  • 增加一個步驟:需要以plugin方式添加到webpack配置中
  • v15版本之后,使用了不同的策略推導.vue文件中各個語言塊使用的loader,將各個語言塊視為獨立的文件使用webpack中配置了規(guī)則的loader處理,由此帶來的配置變化就是針對樣式處理,webpack.rules中必須顯示提供對應loader處理的規(guī)則,原vue-loader配置中內(nèi)聯(lián)傳入的樣式相關loader可以去除
  • 鑒于推導變化,<script></script>標簽內(nèi)的js代碼將被視為獨立的js文件并根據(jù)webpack配置使用babel-loader轉(zhuǎn)譯;項目配置babel-loader時使用exclude: /node_modules/排除依賴包中代碼的轉(zhuǎn)譯,如果導入了/node_modules/中的.vue文件,<script>部分將不能被轉(zhuǎn)譯,故需要將.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+版本不再需要提供內(nèi)聯(lián)的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文件需要經(jīng)過babel-loader轉(zhuǎn)譯
        /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

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 1 Webpack 1.1 概念簡介 1.1.1 WebPack是什么 1、一個打包工具 2、一個模塊加載工具 3...
    Kevin_Junbaozi閱讀 7,022評論 0 16
  • GitChat技術雜談 前言 本文較長,為了節(jié)省你的閱讀時間,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,891評論 7 110
  • 很難想象生活里沒有你的樣子,所有的視線都追逐著你突然有天就消失不見,這里已經(jīng)沒有你。后來才發(fā)現(xiàn),心心念念的人永遠都...
    _Dtath閱讀 339評論 0 0
  • 我的老家在福建省連城縣廟前鎮(zhèn)的一個不大不小的村莊一一江畬村。今早打電話給老媽。我問起天氣。老媽說不冷。往年百公僚打...
    汐鲌閱讀 1,644評論 0 2
  • 近年來前往日本旅游的人越來越多,去日本旅行對中國許多年輕人來說越來越像周末去霓虹國度假~(此處滿滿噠國家富強...
    大白to小黑閱讀 328評論 0 0

友情鏈接更多精彩內(nèi)容