webpack 4 新特性 & Vue-cli 升級

vavaZheng發表於2018-06-25

介紹webpack

webpack誕生之初主要想解決程式碼拆分問題,是現代JS應用程式的靜態模組打包器。
4個核心概念:

  • 入口(entry)
    指示 webpack 應該使用哪個模組,來作為構建其內部依賴圖的開始複製程式碼
  • 輸出(output)
    webpack 在哪裡輸出它所建立的 bundles,以及如何命名這些檔案複製程式碼
  • loader
    由於webpack只能處理javascript,所以我們需要對一些非js檔案
    處理成webpack能夠處理的模組,比如sass檔案複製程式碼
  • 外掛(plugins)
    Loaders將各型別的檔案處理成webpack能夠處理的模組,plugins
    有著很強的能力。外掛的範圍包括,從打包優化和壓縮,一直到重新定
    義環境中的變數。複製程式碼

安裝

$> npm i webpack webpack-cli -D
$> npm i webpack-cli -D
* Tips: webpack4 中 cli 工具分離成了 webpack 核心庫 與 webpack-cli 命令列工具兩個模組,需要
使用 CLI,必安裝 webpack-cli 至專案中
複製程式碼

零配置


webpack4 設定了預設值,以便無配置啟動專案
  • entry 預設值是 ./src/
  • output.path 預設值是 ./dist
  • mode 預設值是 production
複製程式碼

模式

mode: development / production / none

開發模式 development
  • 瀏覽器除錯工具
  • 註釋、開發階段的詳細錯誤日誌和提示
  • 快速和優化的增量構建機制
  • 開啟 output.pathinfo 在 bundle 中顯示模組資訊
  • 開啟 NamedModulesPlugin
  • 開啟 NoEmitOnErrorsPlugin
生產模式 production
  • 啟用所有優化程式碼的功能
  • 更小的bundle大小
  • 去除只在開發階段執行的程式碼
  • 關閉記憶體快取
  • Scope hoisting 和 Tree-shaking
  • 開啟 NoEmitOnErrorsPlugin
  • 開啟 ModuleConcatenationPlugin
  • 開啟 optimization.minimize
none 會禁用所有的預設設定,可以使用 optimization.* 的方式去設定更詳細的配置(搭建你的自定義模式)複製程式碼

webpack 更新日誌

配置更新:

* NoEmitOnErrorsPlugin
-> optimization.noEmitOnErrors(production 模式預設開啟)
* ModuleConcatenationPlugin
-> optimization.concatenateModules(production 模式預設開啟)
* NameModulesPlugin 
-> optimization.nameModules(development 模式預設開啟)
* CommonsChunkPlugin已經被移除 
-> optimization.splitChunks,optimization.runtimeChunk
* ExtractTextWebpackPlugin調整
-> 建議選用新的CSS檔案提取外掛mini-css-extract-plugin
複製程式碼

JSON:

* webpack現在能處理原生的json
    1.當你需要通過loader去把json轉換成js的時候,你可能需要新增
    type:"javascript/auto"
    2.不使用loader也可以直接使用JSON
* 允許通過ESM語法匯入JSON
    1.JSON模組的未使用的匯出部分會被消除
複製程式碼

其他相關細節-> webpack更新日誌

基本配置 webpack.base.conf.js

1.主入口檔案 entry:
entry: {
  //入口檔案,如果是多頁專案,可配置多個
  app: '.src/main.js'
}
複製程式碼
2.輸出檔案 output:
output: {
  // 匯出目錄的絕對路徑,通過HtmlWebpackPlugin外掛生成的html檔案
  存放在這個目錄下面
  path: path.resolve(__dirname, '../dist/' + outputDir),
  // 生產模式或者開發模式下的html,js等檔案內部引用的公共路徑
  publicPath: '/', 
  //匯出檔案的檔名,編譯生成的js檔案存放到根目錄下面的js目錄下面,
  如果js目錄不存在則自動建立
  filename: 'js/[name]' + chunkhash + '.js’, 
  /*
      * chunkFilename用來打包require.ensure方法中引入的模組,如果該
        方法中沒有引入任何模組則不會生成任何chunk塊檔案
      * 比如在main.js檔案中,require.ensure([],function(require)
        {alert(11);}),這樣不會打包塊檔案
      * 只有這樣才會打包生成塊檔案require.ensure([],function(require)
        {alert(11);require('./greeter')})
      * 或者這樣require.ensure(['./greeter'],function(require)
        {alert(11);})
      * chunk的hash值只有在require.ensure中引入的模組發生變化,hash
        值才會改變
      * 注意:對於不是在ensure方法中引入的模組,此屬性不會生效,只能用
        CommonsChunkPlugin外掛來提取(webpack 4中用splitChunks&runtimeChunk)
      * 
   */
  chunkFilename: 'js/[name]' + chunkhash + '.js'
},
複製程式碼
3.檔案解析
resolve: {
 //自動解析確定的副檔名,使倒入模組時不帶副檔名
 extensions: ['.js', '.vue', '.json'],
 // 定義引用路徑別名 配置別名可以加快webpack查詢模組的速度
 alias: {
   'vue$': 'vue/dist/vue.esm.js’, 
   '@': path.resolve(__dirname, '../src’),
   'src': path.resolve(__dirname, '../src')
  }
}
複製程式碼
4.模組解析module
{
  test: /\.vue$/, //規則對vue字尾
  loader: 'vue-loader’, //使用vue-loader進行處理
    query:{  //query是對loader做的額外配置
    limit: 10000    
  }
  include: /src/, //必須包含src資料夾
 }
 
複製程式碼
loader 的用法準則:
    1.單一職責,一個loader只做一件事情,這樣設計的原因是因為,職責越單一,組合性就強,
    可配置性就好。
    2.從右到左,鏈式執行,上一個loader的處理結果傳給下一個loader接著處理
    3.模組化,一個loader就是一個模組,單獨存在不依賴其他的任何模組
    4.無狀態,就類似於純函式。
    5.loader有實用工具loader-utils解析loader引數的和schema-utils校驗格式的
    6.loader的依賴
複製程式碼

Vue-cli 升級 Q&A

1.webpack4推薦使用了最新版本的vue-loader("vue-loader": "^15.0.10"),
但是最新的vue-loader需要在webapck config檔案中設定VueLoaderPlugin外掛,
否則會報以下錯誤:
vue-loader was used without the corresponding plugin.
Make sure to include VueLoaderPlugin in your webpack config.
解決:
const { VueLoaderPlugin } = require('vue-loader');
module.exports = {
    ...
    plugins: [
        // 新增VueLoaderPlugin,以響應vue-loader
        new VueLoaderPlugin()
  ],
    ...
}

複製程式碼
2.Error: No PostCSS Config found in… 
解決:在專案根目錄新建postcss.config.js檔案,並對postcss進行配置:
module.exports = {  
  plugins: [
    require('autoprefixer')()
    ...
  ]  
}
複製程式碼
3.關於CSS Modules相關
現在 Vue Loader v15 使用了一個不一樣的策略來推導語言塊使用的 loader。
拿`< style lang="less" >` 舉例:在 v14 或更低版本中,它會嘗試使用 
less-loader 載入這個塊,並在其後面隱式地鏈上 css-loader 
和 vue-style-loader,這一切都使用內聯的 loader 字串。
在 v15 中,`< style lang="less" >` 會完成把它當作一個真實的 *.less 檔案
來載入。因此,為了這樣處理它,你需要在你的主 webpack 配置中顯式地提供一條規則:
{
  module: {
    rules: [
      // ... 其它規則
      {
        test: /\.less$/,
        use: [
          'vue-style-loader',
          'css-loader',
          'less-loader'
        ]
      }
    ]
  }
}
在 v15 中你再也不用在 Vue Loader 自己的 loaders 選項中將它重複一遍~
* 關於 CSS modules: https://juejin.im/post/5b2f6f42e51d4558da1adba7
複製程式碼
4.提取 js 中的 css 部分到單獨的檔案
* 新的替代外掛 mini-css-extract-plugin
loader 部分:
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
rules: [
  {
    test: /\.css$/,
    use: [
      MiniCssExtractPlugin.loader,
      "css-loader"
    ]
  }
]
plugins 部分(區分環境決定hash值):
plugins: [
    new MiniCssExtractPlugin({
      filename: 'css/[name]' + hash + '.css',
      chunkFilename: 'css/[name]' + hash + '.css'
    })
],
複製程式碼
5.影響也最大的就是webpack4使用optimization.splitChunks替代了
CommonsChunkPlugin.以前的CommonsChunkPlugin主要用來抽取程式碼中的共用部分,
webpack runtime之類的程式碼,結合chunkhash,實現最好的快取策略。
而optimization.splitChunks則實現了相同的功能,並且配置更加靈活,具體解釋如下:
optimization: {
  //! 替代 CommonsChunkPlugin 提取公共程式碼
  splitChunks: {
    // chunks: "async",
    // minSize: 30000, //!塊生成最小大小。
    // minChunks: 1, //!最小數量的塊分裂之前,必須共享一個模組。
    // maxAsyncRequests: 5, //!按需載入時並行請求的最大數量。
    // maxInitialRequests: 3, //!最大數量的並行請求一個入口點。
    // name: true, //!分割塊的名稱。提供true將根據塊和快取組金鑰自動生成名稱
    //!快取組會從splitChunks.*中繼承相應的選項值,
    test、priority和reuseExistingChunk則只能在快取組層次上配置。
    cacheGroups: {
        // default: {
        //   minChunks: 2,
        //   priority: -20,
        //   reuseExistingChunk: true
        // },
        //!"initial"、"async"和"all"。分別用於選擇初始塊、按需載入的塊和所有塊。
        vendors: {
            test: /[\\/]node_modules[\\/]/, //! 不繼承
            priority: -10, //!不繼承,該配置項是設定處理的優先順序,數值越大越優先處理
            chunks: 'initial',
            reuseExistingChunk: true, //!不繼承 ,沒有預設值,選項用於配置在模組完全
            匹配時重用已有的塊,而不是建立新塊
            name: 'vendors',
        },
        'async-vendors': {
            test: /[\\/]node_modules[\\/]/,
            minChunks: 2,
            chunks: 'async',
            reuseExistingChunk: true,
            name: 'async-vendors'
        },
        //!多個css chunk合併成一個css檔案
        styles: {
            name: 'styles',
            test: /\.(scss|sass|less|css)$/,
            chunks: 'all',
            minChunks: 1,
            reuseExistingChunk: true
        }
      }  
    },
   // !分離出webpack編譯執行時的程式碼
   runtimeChunk: { name: 'manifest' }
},

* webpack.optimize.UglifyJsPlugin現在也不需要了,只需要使用
  optimization.minimize為true就行,
  production mode下面自動為true,當然如果想使用第三方的壓縮外掛也可以
  在optimization.minimizer的陣列列表中進行配置
/** like this code **/
optimization:{
  minimizer: [
    new UglifyJsPlugin({
        exclude: /\.min\.js$/,
        cache: false, //! 檔案快取 
        parallel: true, //! 利用多程式並行執行提高構建速度
        sourceMap: false,
        extractComments: false, //! 移除註釋
        //! uglifyES
        uglifyOptions: {
          compress: {
            warnings: false, //! 在UglifyJs刪除沒有用到的程式碼時不輸出警告
            drop_console: true, //! 刪除所有的 `console` 語句,可以相容ie瀏覽器
            collapse_vars: true, //! 內嵌定義了但是隻用到一次的變數
            reduce_vars: true //! 提取出出現多次但是沒有定義成變數去引用的靜態值
          },
          output: {
            beautify: false, //!不需要格式化
            comments: false //!不保留註釋
          }
        }
    })
  ]
}
複製程式碼

效能優化

* 使用happypack
HappyPack就能讓Webpack把任務分解給多個子程式去併發的執行,子程式處理完後再把結果傳送給主程式

* babel-loader設定快取
cacheDirectory: 指定的目錄將用來快取 loader 的執行結果。之後的 webpack 構建,將會嘗試讀取快取,來避免在每次執行時,可能產生的、高效能消耗的 Babel 重新編譯過程
複製程式碼

Tips

1.建議在 webpack 構建流程中使用到的 loaders 及 plugins 都升級到最新版本,
如果 pakage.json 中有相應的模組配置,可刪除之後重新安裝
複製程式碼
Webpack5展望:
* ESM 模組匯出支援
* 持久快取
* WebAssembly 支援從 experimental 升級為 stable 穩定版。並增加 * tree-shaking 和未使用程式碼去除!
* Presets —— 基於零配置設計,任何東西都能支援零配置
* CSS 模組型別——支援 CSS 作為入口檔案(再見吧 ExtractTextWebpackPlugin)
* HTML 模組型別——支援 HTML 作為入口檔案
* URL/檔案 模組型別
* 自定義模組型別
* 多執行緒
* 重新定義我們的組織章程和計劃任務
* Google Summer of Code (之後單獨寫問說明!!!)
複製程式碼


參考閱讀:
webpack 更新日誌-English
webpack4.0 升級日誌-中文版
webpack-module官網
webpack 4 釋出English
webpack 4 釋出

相關文章