淺析webpack中mode的取值及不同取值的作用/打包方式及搖樹優化(tree-shaking)的理解


  Mode 用來指定當前的構建環境是:production、development、還是none。設置 mode 可以使用 webpack 的內置函數,默認值是 production。

  mode 的內置函數功能如下:

  模式(mode):提供 mode 配置選項,告知 webpack 使用相應模式的內置優化。

  用法:只在配置中提供 mode 選項:

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

  或者從 CLI 參數中傳遞:

webpack --mode=production

一、mode取值

1、development:會將 process.env.NODE_ENV 的值設為 development。啟用 NamedChunksPlugin 和 NamedModulesPlugin。

// webpack.development.config.js
module.exports = { + mode: 'development'
- plugins: [ -  new webpack.NamedModulesPlugin(), -  new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") }), - ] } 

2、production:會將 process.env.NODE_ENV 的值設為 production。啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 UglifyJsPlugin。

// webpack.production.config.js
module.exports = { + mode: 'production', - plugins: [ -  new UglifyJsPlugin(/* ... */), -  new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), -  new webpack.optimize.ModuleConcatenationPlugin(), -  new webpack.NoEmitOnErrorsPlugin() - ] }

  production模式下會啟用UglifyJsPlugin插件(移除未使用的內容和文件壓縮)

二、mode取值的區別

  分別用 production 和 development 打包,編譯的區別如下:

1、development打包后,一些沒有依賴的方法、變量、文件會保留;而 production 則會移除。

2、production 打包后,代碼會進行壓縮,比 development 的文件小。

三、mode不同值的打包

1、none模式下的模塊打包

  在沒有任何優化處理的情況下,按照webpack默認的情況下打包出模塊,它會將模塊打包至數組之中,調用模塊的時候,就是直接調用模塊在此數組中的一個序號,然后沒有進行壓縮、混淆之類的優化。

  但是無論是在開發環境development下,還是在正式環境production下,這個代碼都是不過關的。對於開發環境,此代碼可讀性太差,對於正式環境,此代碼不夠簡潔。因此為了減少一次重復操作,webpack4提供的development/production可以很大程度上幫我們做一大部分的事情,我們要做的,就是在這些事的基礎上增加功能。

2、development模式下,webpack做了哪些打包工作

  development是告訴程序,我現在是開發狀態,也就是打包出來的內容要對開發友好。在此mode下,就做了以下插件的事情,其他什么都沒有做,所以這些插件可以省略。

//webpack.config.js module.exports = {   mode:'development',   devtool:'eval',   plugins: [     new webpack.NamedModulesPlugin(),     new webpack.NamedChunksPlugin(),     new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("development") })   ] }

  我們看看NamedModulesPlugin和NamedChunksPlugin這兩個插件都做了啥,原本我們的webpack並不會給打包的模塊加上名字,一般都是按照序號來,從0開始,然后加載第幾個模塊,這個對機器來說無所謂,查找載入很快,但是對於人腦來說就是災難了,所以這個時候給各個模塊加上姓名,便於開發的時候查找。

  沒有NamedModulesPlugin,模塊就是一個數組,引用也是按照在數組中的順序引用,新增模塊都會導致序號的變化。有了NamedModulesPlugin,模塊都擁有了姓名,而且都是獨一無二的key,不管新增減少多少模塊,模塊的key都是固定的。

  除了NamedmodulesPlugin,還有一個NamedChunksPlugin,這個是給配置的每個chunks命名,原本的chunks也是數組,沒有名字。NamedChunksPlugin其實就是提供了一個功能,你可以自定義chunks的名字,假如我在不同的包中有相同的chunk名,怎么辦?這個時候就要在進行進一步的區分了,我們可以用所有的依賴模塊名加上本模塊名,因為Chunk.modules已經廢棄了,現在用其他的方法來代替chunk.mapModules,然后重命名chunk的名字

new webpack.NameChunksPlugin( (chunk) => { return chunk.mapMudoles( m => { return path.relative(m.context,m.request); }).join('_') })

  總結:development也就給我們省略了命名的過程,但是其他還是要我們自己加的。

3、production

  在正式版本中,所省略的插件們,如下所示,我們會一個個分析

//webpack.config.js
module.exports = { mode:'production', plugins: [ new UglifyJsPlugin(/*...*/), new webpack.DefinePlugin({ "process.env.NODE_ENV": JSON.stringify("production") }), new webpack.optimize.ModuleConcatenationPlugin(), new webpack.NoEmitOnErrorsPlugin() ] }

(1)UglifyJsPlugin

  我們第一個需要處理的就是混淆&壓縮js了吧,這個時候就要請出UglifyJs了,他在webpack中的名字是:const UglifyJsPlugin = require('uglifyjs-webpack-plugin');這樣,就可以使用他了。不過 new UglifyJsPlugin() 這個插件我們可以在 optimize 中配置,效果是一樣的,那么我們是不是不用在導入一個新的插件了,這樣反而會拖慢webpack的打包速度

optimization: { minimize: true }

  將插件去除,混淆壓縮放入optimization,這樣webpack速度快的起飛了,只有第一次打包會慢,之后在打包就快了

(2)ModuleConcatenationPlugin

  webpack.optimize.ModuleConcatenationPlugin() 這個插件的作用是什么呢?此插件僅適用於由webpack直接處理的ES6模塊,在使用轉譯器(transpiler)時,你需要禁用對模塊的處理(例如Babel中的modules選項)。

(3)NoEmitOnErrorsPlugin

  最后一個插件就是webpack.NoEmitOnErrorsPlugin(),這個就是用於防止程序報錯,就算有錯誤也給我繼續編譯,很暴力的做法。

四、搖樹優化

1、概念

  一個模塊可能有多個方法,只要其中的某個方法使用到了,則整個文件都會被打包到bundle中去,tree shaking 就是只把用到的的方法打入 bundle,沒用到的方法會在 uglify 階段被擦除掉。
  • 代碼不會被執行,不可到達
  • 代碼執行的結果不會被用到
  • 代碼只會影響死變量(只寫不讀)
  比如:
if (false) {   console.log('這段代碼永遠不會執行') }

  搖樹是一種消除死代碼的方法,應用程序的依賴項是樹狀結構,樹的每個節點都代表了一個依賴項,這些依賴項為應用程序提供了不同的功能,通過消除不需要的依賴項來減少樹的節點,這個過程叫搖樹。只能適用於es6模塊的導入,不適用於commonJS的require,因為es6的模塊是靜態引入。

(1)應用程序采用按需加載的方式導出,沒有被引用的模塊不會被打包進來,減少包大小,縮小應用的加載時間。

(2)es6的模塊是靜態分析

(3)webpack自帶tree shaking,只需要加些配置

// webpack.config.js
optimization: { // 使用tree-shaking
    usedExports: true, // mode為production時,默認開啟
},

2、示例

// print.js:導出了兩個函數
export const add = (a, b) => { console.log(a + b); } export const minus = (a, b) => { console.log(a - b); } // index.js:只引用了其中一個函數
import { add } from "./print"; add(1, 2);

  tree-shaking結果:

  mode:development,依然將未引入的函數打包了,只是有一句注釋標記未被引用,這樣做是為了在開發模式下調試方便,如果把代碼刪除,程序報錯時,位置定位不准。

  mode:production,打包后的代碼被壓縮,且未被引入的函數沒有打包。

參考文章:https://blog.csdn.net/qq_40677590/article/details/106817327


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM