Webpack 之常用配置(二)

作者:余韻之

Tree Shaking

1、什么是Tree Shaking

表示 只引入需要的模塊里的代碼,沒有使用的是不會打包

import { add } from './math.js';
add(1, 2);

math.js里有兩個方法,如果使用了Tree Shaking 那么只會打包add方法

2、如何配置

webpack.prod.js 生產(chǎn)環(huán)境不需要配置這個,即使配置了這個也是無作用的。

optimization: { // 使用tree shaking
     usedExports: true
}

package.json

"sideEffects": false, // 表示對所有的模塊都要使用 tree shaking
"sideEffects":["@babel/polly-fill","*.css"] //表示排除@babel/polly-fill ,排除所有的css文件 其余import 模塊都使用 tree shaking

注意如果是開發(fā)環(huán)境development tree shaking 會不生效,因為調(diào)試的話sourceMap行數(shù)會不準,生產(chǎn)環(huán)境production就會生效

Production Development

1、如何切換開發(fā)環(huán)境和生產(chǎn)環(huán)境webpack配置

  • 創(chuàng)建生產(chǎn)環(huán)境文件 ./build/webpack.prod.js
  • 創(chuàng)建開發(fā)環(huán)境文件 ./build/webpack.dev.js
  • 創(chuàng)建公共的代碼文件 ./build/webpack.common.js

使用插件 webpack-merge 把配置文件合并

2、配置打包命令

package.json

"scripts": {
    "dev": "webpack-dev-server --config ./build/webpack.dev.js", // 啟動熱更新,選擇dev配置文件
    "build": "webpack --config ./build/webpack.prod.js" // 直接打包,走prod配置文件
}

Code Splitting

我們?yōu)槭裁匆龃a分割呢?舉個例子。

假設(shè)我們引入了一個lodash第三方庫,它的大小是1MB,我們的業(yè)務(wù)代碼也有1MB。此時不做任何處理最后打包生成一個main.js大小為2MB。用戶打開瀏覽器需要請求一個2MB的main.js文件。

import _ from "lodash";  // 假設(shè)lodash有1MB

// 假設(shè)業(yè)務(wù)代碼有1MB
console.log(_.join(['a', 'a', 'c'],"---"))
console.log(_.join(['a', 'b', 'c'],"---"))

此時我們修改業(yè)務(wù)代碼

import _ from "lodash";  // 假設(shè)lodash有1MB

// 假設(shè)業(yè)務(wù)代碼有1MB
console.log(_.join(['a', 'xxxxx', 'c'],"---"))
console.log(_.join(['a', 'b', 'c'],"---"))

重新打包,生成 main.js 2MB。用戶需要重新拉取2MB的代碼文件。這會使得加載時間很慢,性能不夠好。

所以有什么好的方式來解決這個問題呢?

第一種方式:同步方式

import _ from "lodash"  // 假設(shè)lodash有1MB
window._ = _
// 假設(shè)業(yè)務(wù)代碼有1MB
console.log(_.join(['a', 'd', 'c'],"---"))
console.log(_.join(['a', 'b', 'c'],"---"))

webpack.config.js

entry: {
  lodash: './src/lodash.js',
  main: './src/index.js'
}
  • 首次訪問頁面,加載 main.js: 被拆成vendor~lodash.js 1MB 和 業(yè)務(wù)代碼main.js 1MB
  • 此時修改了業(yè)務(wù)代碼,用戶是不需要重新加載vendor~lodash代碼的。只需要重新加載main.js

優(yōu)點:可以有效提提高代碼運行的速度、用戶體驗提高、性能提高
缺點:需要手動拆分頁面的代碼,不夠智能

第二種方式:同步方式

webpack.config.js

optimization:{
      splitChunks:{
        chunks:'all'
    }
}
import _ from "lodash";  // 假設(shè)有1MB

console.log(_.join(['a', 'd', 'c'],"---"))
// 此處省略10萬行業(yè)務(wù)邏輯
console.log(_.join(['a', 'b', 'c'],"---"))

優(yōu)點:相比第二種方式,可以自動拆分,打包引入 main.js 和 vendors~main.js

第三種方式:異步方式

安裝插件

yarn add -D babel-plugin-dynamic-import-webpack

.babelrc

"plugins": ["babel-plugin-dynamic-import-webpack"]

異步代碼如下

function getComponent(){
  return import('lodash').then(({default:_})=>{
    let element = document.createElement('span')
    element.innerHTML = _.join(['x','y'],'-');
    return element;
  })
}

getComponent().then(ele=>{
  document.body.appendChild(ele)
})

注意:異步代碼import引入的模塊,無需配置額外的webpack.config.js,會自動引入

SplitChunksPlugin 配置參數(shù)詳情

1、webpackChunkName

修改第三方打包的文件的名字

安裝官方的依賴

npm install --save-dev @babel/plugin-syntax-dynamic-import

.babelrc

"plugins": ["@babel/plugin-syntax-dynamic-import"]

項目代碼里添加名字 /_ webpackChunkName:"lodash" _/

function getComponent(){
  return import(/* webpackChunkName:"lodash" */'lodash').then(({default:_})=>{
    let element = document.createElement('span')
    element.innerHTML = _.join(['x','y'],'-');
    return element;
  })
}

getComponent().then(ele=>{
  document.body.appendChild(ele)
})

注意:生成的代碼文件為 ./dist/vendors~lodash.js

如果生成的代碼文件不想加入 vendors~ ,而是直接lodash.js

那么配置webpack.config.js

optimization:{
  splitChunks:{
    chunks:'all',
    cacheGroups:{ // 表示打包的文件是否要帶vendors,無論同步或者異步
        vendors:false,
        default:false
    }
  }
}

2、詳細的splitChunks的參數(shù)功能

optimization: {
    splitChunks: {
      chunks: 'all', // async 表示只對異步代碼分割,initial 表示只對同步代碼分割,all的話是所有同時會走到cacheGroups.vendors
      minSize: 30000, // 表示最小模塊大于30000個字節(jié)才會做代碼分割
      // maxSize: 50000, // 如果拆分的代碼大小超過50000,會進行二次拆分,一般配置的比較少
      minChunks: 1,//引入幾次才分割打包,如果只引入1次就分割,如果是2表示必須大于等于2次才做代碼分割
      maxAsyncRequests: 5,// 表示不能超過5個模塊分割,超過后面的模塊就不分割了
      maxInitialRequests: 3,// 表示整個網(wǎng)站首頁或入口文件 如果做代碼分割不超過3個
      automaticNameDelimiter: '~', //組和文件名鏈接符號 vendors~main.js
      name: true,// 表示要更新名字,一般是不需要改變的
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 如果在node_modules里,那么會打包到vendors.js
          priority: -10, // 比如jquery 符合vendors 也符合default,值越大,說明優(yōu)先級更大
          filename:'vendors.js' // 表示所有的第三方打包到一個叫vendors.js文件
        },
        default: { // 如果是引入自己在項目里寫的模塊引入走這里,非node_modules
          // minChunks: 2,
          priority: -20,// 值越大,說明優(yōu)先級更大
          reuseExistingChunk: true, // 如果代碼已經(jīng)打包過,重復(fù)引用時就不會再分割打包,而是復(fù)用之前的。
          filename: 'common.js'
        }
      }
    }
  },

這里要注意

  • 如果是引入同步代碼不會立刻分割,而是會走cacheGroups,根據(jù)實際情況來分割

對 Electron 感興趣?請關(guān)注我們的開源項目 Electron Playground,帶你極速上手 Electron。

我們每周五會精選一些有意思的文章和消息和大家分享,來掘金關(guān)注我們的 曉前端周刊。


我們是好未來 · 曉黑板前端技術(shù)團隊。
我們會經(jīng)常與大家分享最新最酷的行業(yè)技術(shù)知識。
歡迎來 知乎、掘金Segmentfault、CSDN、簡書開源中國、博客園 關(guān)注我們。

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

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

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