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已經把導出未使用的模塊代碼剔除掉了。使項目在運行時,加載腳本體積減小,縮短了加載時間,從而提升項目性能。✨