瞭解了webpack的基本配置以後,接下來應該關注其優化策略。webpack
的優化策略對咱們的程序有着極大的性能提高。這是我記錄學習webpack
優化的文章,紀錄的同時也但願分享給你們。css
在開發的過程當中,咱們會引入像react
、react-dom
這樣的庫,這樣的庫基本上每一次打包時它們的內容都不會改變,因此咱們引入動態連接庫。將它們打包一次,在以後的構建過程當中它們就不會被打包,打包的模塊也會使用動態連接庫裏面的代碼而不是去node_modules
中取,這樣咱們的構建速度就會大大提高。下面讓咱們來看看webpack
中怎麼構建動態連接庫。html
咱們新建一個webpack.dll.config.js
的文件,配置以下node
const path = require('path')
const DllPlugin = require('webpack/lib/DllPlugin')
module.exports = {
entry:{
//將react、react-dom放到動態連接庫中
react:['react','react-dom']
},
output:{
//輸出的文件名稱,[name]指的是當前動態連接庫的名稱,即react
filename:'[name].dll.js',
//輸出到dist目錄下
path:path.resolve(__dirname,'dist'),
//存動態連接庫的全局變量名稱,即_dll_react,加上_dll_防止全局變量衝突
library:'_dll_[name]',
},
plugins:[
new DllPlugin({
//動態連接庫的全局變量名稱,須要和library一致
name:'_dll_[name]',
path:path.join(__dirname,'dist','[name].manifest.json')
})
]
}
複製代碼
下面執行命令npx webpack --config webpack.dll.config.js
,dist目錄下多了兩個文件,分別是react.dll.js
和react.manifest.json
react.dll.js
裏面包含React
的基礎運行環境,即react
、react-dom
模塊。react.manifest. json
用於描述在動態連接庫文件中包含哪些模塊。react
而後再新建一個webpack.config.js
文件,在打包出來的chunk
塊中聲明須要引入的動態連接庫,具體配置以下webpack
const path = require('path')
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin')
module.exports = {
entry: {
main: './main.js'
},
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'dist')
},
module:{
rules:[
]
},
plugins:[
new DllReferencePlugin({
manifest:require('./dist/react.manifest.json')
})
]
}
複製代碼
執行命令npx webpack
,在dist
目錄下生成bundle.js
。web
而後咱們在dist
目錄下新建一個index.html
文件,引入打包構建出來的文件和動態連接庫。json
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script src="./react.dll.js"></script>
<script src="./buncld.js"></script>
</body>
</html>
複製代碼
當文件數量變多時,webpack
構建速度慢的問題會變得特別明顯。可是運行在node
之上的webpack
是單線程的,不能同時處理多個任務。而HappyPack
可讓webpack
作到這一點,它將任務分解成多個子進程去併發執行。因爲JavaScript
是單線程模型,因此想要發揮多核CPU的做用只能經過多進程而不能經過多線程來實現。 接入HappyPack
的代碼以下瀏覽器
const path = require('path')
const HappyPack = require('happypack');
module.exports = {
entry: {
main: './main.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.js$/,
//以babel爲id,轉交給happypack處理
use: ['happypack/loader?id=babel'],
},
{
test: /\.css$/,
//以css爲id,轉交給happypack處理
use: ['happypack/loader?id=css']
}
]
},
plugins: [
new HappyPack({
id: 'babel',
loaders: ['babel-loader']
}),
new HappyPack({
id: 'css',
loaders: ['style-loader','css-loader']
})
]
}
複製代碼
執行構建命令 npx webpack
從命令行的輸出能夠看出HappyPack
已經生效bash
Happy[babel]: Version: 5.0.1. Threads: 3
Happy[babel]: All set; signaling webpack to proceed.
Happy[css]: Version: 5.0.1. Threads: 3
Happy[css]: All set; signaling webpack to proceed.
複製代碼
爲了提高網頁的加載速度,能夠對資源進行壓縮。服務器
這裏咱們會用到UglifyJS
,它經過去掉無效代碼、去掉日誌輸出、縮短變量名,從而來優化咱們的代碼。 簡單的配置以下
const UglifyJSPlugin = require('webpack/lib/optimize/UglifyJsPlugin')
module.exports = {
//以上省略。。。
plugins: [
//壓縮輸出的 JavaScript 代碼
new UglifyJSPlugin({
compress: {
//在 UglifyJS 刪除沒有用到的代碼時不輸出警告
warnings: false,
//刪除全部 console 語句, 能夠兼容IE瀏覽器
drop_console: true,
//內嵌己定義可是隻用到一次 的變量
collapse_vars: true,
//提取出現了屢次可是沒有定義成變量去 用的靜態值
reduce_vars: true,
output: {
//最緊湊的輸出
beautify: false,
//刪除全部註釋
comments: false,
}
}
})
]
複製代碼
CSS
也能夠向JavaScript
同樣被壓縮,這裏用到的工具是cssnano
。cssnano
的意義不單單是刪除空格,它能夠理解CSS
代碼。例如 margin:10px 20px 10px 20px
會被壓縮爲 margin:10px 20px
基本配置以下
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-plugin')
module.exports = {
//以上省略。。。。
module: {
rules: [{
test: /\.css$/,
use: [ExtractTextPlugin.extract({
use: ['style-loader', 'css-loader?minimize']
})]
}]
},
plugins:[
new HtmlWebpackPlugin({
template:'./index.html',
filename:'index.html'
}),
new ExtractTextPlugin({
filename: '[name]_[contenthash:8].css'
})
]
}
複製代碼
若是將多個頁面的公共代碼抽離成單獨的文件,就能優化一些問題。例如相同的資源被重複加載,浪費用戶的流量和服務器的成本。每一個頁面要加載的資源太大,致使網頁首屏加載緩慢,影響用戶體驗。 基本配置以下,此配置主要針對多頁面。單頁就不存在於公共代碼這一說法了。
import 'react'
import 'react-dom'
import './index.css' //每一個頁面都用到的樣式
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin')
module.exports = {
module: {
entry: './main.js',
rules: [{
test: /\.css$/,
use: [ExtractTextPlugin.extract({
use: ['style-loader', 'css-loader?minimize']
})]
}]
},
plugins: [
new CommonsChunkPlugin({
//從已有的common和base兩個現成的chunks中提取公共部分
chunks: ['common', 'base'],
//將公共部分放到base中 這樣配置以後 common會變小,由於公共部分都跑到了base裏,而base不變
name: 'base'
})
]
}
複製代碼
爲了能使網頁運行,以網頁A爲例,除了打包出來的A頁面的JavaScrip
t代碼還需引入公共部分代碼
<script src= 'base.js'></script>
<script src='common.js'></script>
<script src='a.js'></script>
複製代碼
單頁應用首次渲染緩慢,一個很重要的緣由是一次性加載了全部功能對應的代碼。這個時候若是採用按需加載,咱們網站的性能將會大大提高。 在webpac
k裏,按需加載能夠這樣來寫。例如咱們只打包出了一個bundle.js
。在bundle.js
中,有這麼一段代碼
window.document.getElementById('button').addEventListener('click',()=>{
import('./show').then(show=>{
show('webpack')
})
})
複製代碼
在show.js
中
module.exports= function (content) {
window.aleat(`hello ${content}`)
}
複製代碼
webpack
中內置了import
語句的支持,當遇到這樣的語句時,首先會生成一個新的chunk
,而後觸發import
的時候再去加載這個chunk
,返回的是一個Promise
對象,在加載成功時使用then
方法進行下面的操做,爲了讓webpack
正確打包chunk
,配置文件中需加入
output:{
//從entry打包生成的chunk
filename:'[name].js',
//動態加載生成的chunk
chunkFileName:'[name].js'
}
複製代碼
webpack
的優化配置還有不少,這裏只記錄了我平時經常使用的,具體詳情還請查閱官方文檔。