一. Tree Shaking
- Tree Shaking 描述用于移除 JavaScript 上下文中的未引用代碼,它依賴于 ES2015 模塊系統(tǒng)中的靜態(tài)結(jié)構(gòu)特性,例如 import 和 export
- 使用類似 UglifyJSPlugin 等插件來實現(xiàn)代碼壓縮與精簡
- 安裝 uglifyjs-webpack-plugin
npm install uglifyjs-webpack-plugin --save-dev
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
modules.exports = {
//...
plugins: [new UglifyJSPlugin],
};
二. 生產(chǎn)環(huán)境構(gòu)建
- 開發(fā)環(huán)境(development)與生產(chǎn)環(huán)境(production)的構(gòu)建目標差異很大,所以應(yīng)當分離出差異的配置颊埃,保留通用的配置,使用 webpack-merge 來分別合并環(huán)境差異的配置與通用的配置
- 安裝 webpack-merge
npm install webpack-merge --save-dev
- 添加 webpack.common.js 表示通用的配置
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({ title: 'Hello Webpack!' }),
],
output: {
filename: '[name].[hash:4].js',
path: path.resolve(__dirname, 'dist'),
},
};
- 添加 webpack.dev.js 表示開發(fā)環(huán)境下的獨立配置
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
},
});
- 添加 webpack.prod.js 表示生產(chǎn)環(huán)境下的獨立配置
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'source-map',
plugins: [new UglifyJSPlugin()],
});
- 修改 package.json 的 scripts
"scripts": {
"start": "webpack-dev-server --open --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
},
- 在開發(fā)環(huán)境時運行 npm run start,Source Map 配置為 inline-source-map 使調(diào)試更加清晰补疑,并啟用 webpack-dev-server
- 在生產(chǎn)環(huán)境時運行 npm run build,Source Map 配置為 source-map 在運行時更為快速歹撒,并使用 UglifyJSPlugin 來進行代碼壓縮
- 經(jīng)常能見到項目中使用了 process.env.NODE_ENV 這個值莲组,這個值并不是一個變量,而是構(gòu)建開始之前被靜態(tài)化編譯了暖夭,所以需要特定的配置使他生效
// webpack.prod.js
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
},
}),
],
- 當在源碼中需要區(qū)別于開發(fā)環(huán)境與生產(chǎn)環(huán)境的代碼時應(yīng)這樣:
if (process.env.NODE_ENV === 'production') {
// production
} else {
// development
}
三. 代碼分離
1. 多入口
- 使用多個入口的方式來達到分離代碼锹杈,使用 CommonsChunkPlugin 插件來防止多個入口中代碼內(nèi)使用相同文件的情況,做到去重與分離 chunk
- 配置 webpack.config.js
plugins: [
new webpack.optimaize.CommonsChunkPlugin({
name: 'common',
}),
],
2. 動態(tài)導(dǎo)入
- 使用 import() 語法(內(nèi)部使用 Promise)來動態(tài)導(dǎo)入模塊
- 首先迈着,應(yīng)當配置 webpack.config.js 的 output 選項
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
- 使用 chunkFilename 來決定非入口 chunk 的名稱
- 可以使用 async 函數(shù)來搭配石筍 import()竭望,前提是瀏覽器支持或使用了 babel 等的預(yù)處理器
四. 緩存
1. 輸出文件名稱
- 應(yīng)當使用 [hash] 或 [chunkhash] 來配置 webpack.config.js 的 output.filename,以確保當文件內(nèi)容變化后裕菠,防止瀏覽器緩存請求舊的文件而發(fā)現(xiàn)不了變化
2. 提取模板
- 使用 CommonsChunkPlugin 可以將 webpack 的樣板(boilerplate)和 manifest 提取到單獨的包中
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
}),
],
3. 提取 vendor
- 將第三方庫(library)(例如 lodash 或 vue)提取到單獨的 vendor chunk 文件中咬清,因為它們很少像本地源碼一樣頻繁修改,利用客戶端的緩存奴潘,減少向服務(wù)器獲取資源
- 使用一個新的 entry(入口)來配置枫振,并額外配置一個 CommonsChunkPlugin 實例來實現(xiàn)
module.exports = {
entry: {
main: './src/index.js',
vendor: ['lodash'],
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
}),
],
};
- 這里引入 runtime 的目的是說明 CommonsChunkPlugin 的 'vendor' 實例必須在 'runtime' 實例之前引入
4. 模塊標識符
- 每個 module.id 會基于默認的解析順序進行增量,也就是說萤彩,當解析順序發(fā)生變化粪滤,ID 也會隨之改變
- main bundle 會隨著自身的新增內(nèi)容的修改,而發(fā)生變化
- vendor bundle 會隨著自身的 module.id 的修改雀扶,而發(fā)生變化
- runtime bundle 會因為當前包含一個新模塊的引用杖小,而發(fā)生變化
- 使用 HashedModuleIdsPlugin 插件在生產(chǎn)環(huán)境上
plugins: [
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
}),
],