webpack中Tree-Shaking性能優化

Tree-Shaking的作用

  • Tree-shaking的本質是消除無用的js代碼:在 webpack 項目中,當我們在入口文件中引入一個模塊的時候,可能不會引入這個模塊的所有代碼,只引入了我們需要的代碼,那麼在使用webpack進行打包時,tree-shaking會自動幫我們把不用的代碼過濾掉。
  • 提升項目性能:JS絕大多數情況需要通過網絡進行加載,然後執行,加載的文件越小,整體執行時間更短,所以去除無用代碼以減少文件體積, 從而提升項目性能。

Tree-Shaking的模塊引入方式

tree-shaking只支持ES模塊的引入(import方式的引入),如果使用CommonJS的引入方法,tree-shaking是不支持的。因爲CommonJS底層是動態引入的方式,import底層是靜態引入的方式,tree-shaking只支持靜態引入的方法,所以只支持ES模塊引入。

// 正確的引入方式
import { add } from './math.js';
// 錯誤的引入方式 (tree shaking不支持)
// const add = require('./math.js');

Tree-Shaking的用法(配置)

目錄結構:

|--demo
	|--node_modules
	|--src
		|--index.html
		|--index.js
		|--math.js
	|--package-lock.json
	|--package.json
	|--webpack.config.js

index.js

// 引入math.js模塊中的一個方法
import { add } from './math.js';
add(1, 2);

math.js

// 導出兩個方法
export const add = (a, b) => {
  console.log(a + b)
}

export const minus = (a, b) => {
  console.log(a - b)
}
開發模式下的使用(development)

在開發模式下(development), 默認是沒有tree-shaking這個功能的,如果想在此模式下添加tree-shaking, 需要配置optimization項: (webpack.config.js具體如下)

// 在這裏做打包配置
const path = require('path'); // 引入node的path模塊(loader模塊)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// Common.js語法
module.exports = {
  mode: 'development', // 開發模式
  devtool: 'cheap-module-eval-source-map', // 開發環境下的devtool
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8080
  }, 
  module: {
    rules: [{ 
      test: /\.js$/, 
      exclude: /node_modules/,
      loader: "babel-loader",
      options: {
        presets: [["@babel/preset-env", {
          targets: { 
            chrome: "67"
          },
          useBuiltIns: "usage"
        }]]
      }
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }), 
    new CleanWebpackPlugin()
  ],
  optimization: { // 在開發環境裏需要使用此配置
     usedExports: true // 哪些導出的模塊被使用了,再做打包
  },
  output: {
    filename: 'dist.js', // 打包之後的輸出文件
    path: path.resolve(__dirname, 'dist') 
  }
}
  • optimization :開發環境下需要此配置項,使用usedExports屬性,來幫助webpack識別哪些導出的模塊被使用了,再做打包。

在package.json裏做如下配置:

也可以通過數組的形式配置:

"sideEffects": false,
// "sideEffects": ["@babel/polyfill"],
// "sideEffects": ["*.css"], 

sideEffects配置的含義:遇到任何的css文件和@babel/polyfill需要填充注入的特性,不使用tree-shaking。如果某些文件,不想讓它做tree-shaking, 那麼就可以通過數組的形式配置在sideEffects裏邊就可以了。若沒有要配置的東西,此值就設置爲false.

打包:

npx  webpack

在打包後的dist.js中,可以看出,tree-shaking已經幫我們做了處理,已經區分了哪些是導出模塊,哪些是導出使用了的模塊。但在development環境下做打包的時候,即時用了tree-shaking, 也不會幫我們把導出沒有使用的模塊從打包生成的dist.js文件裏去除掉,只是會在代碼裏給與提示。⭐️(這個問題出現的原因是:因爲在開發環境中,我們可能會對代碼做一定的調試,如果tree-shaking 把部分代碼去除,可能在調試時,代碼對應的行數都會出錯,所以開發環境下,tree-shaking還會保留代碼)

生產模式下的使用(production)

當我們的項目要打包上線的時候,mode的值爲production的時候。此時tree-shaking就會生效了,配置如下:

// 在這裏做打包配置
const path = require('path'); // 引入node的path模塊(loader模塊)
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// Common.js語法
module.exports = {
  mode: 'production', // 生產模式
  devtool: 'cheap-module-source-map', // 生產環境下的devtool
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    open: true,
    port: 8080
  }, 
  module: {
    rules: [{ 
      test: /\.js$/, 
      exclude: /node_modules/,
      loader: "babel-loader",
      options: {
        presets: [["@babel/preset-env", {
          targets: { 
            chrome: "67"
          },
          useBuiltIns: "usage"
        }]]
      }
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }), 
    new CleanWebpackPlugin()
  ],
  output: {
    filename: 'dist.js', // 打包之後的輸出文件
    path: path.resolve(__dirname, 'dist') 
  }
}

由於在生產環境下,tree-shaking是默認配置好的,所以生產環境下,不需要寫以下配置項:

optimization: { // 在開發環境裏需要使用此配置
    usedExports: true // 哪些導出的模塊被使用了,再做打包
}

在package.json中同樣做如下配置:

執行打包:

npx  webpack

由此可以看出,在我們打包生成線上代碼的時候,Tree-Shaking已經把導出未使用的模塊代碼剔除掉了。使項目在運行時,加載腳本體積減小,縮短了加載時間,從而提升項目性能。✨

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章