核心:
- entry(打包入口)
- output(打包后的文件處理)
- loader(對各類資源的處理)
- plugin(利用插件對webpack進(jìn)行擴展和加強)
- mode(針對開發(fā)環(huán)境和生產(chǎn)環(huán)境的區(qū)分處理)
其余常用:
- devServer(熱更新)
- resolve(模塊解析)
- optimization(優(yōu)化)
- devtool(源碼調(diào)試)
優(yōu)化手段:
- stats分析
- 速度分析
- 體積分析
- tree-shaking
- scope-hoisting
- 多進(jìn)程構(gòu)建
- 并行壓縮
- 預(yù)編譯資源模塊
- 提高二次構(gòu)建速度
- css的tree-shaking
- webpack圖片壓縮
- 動態(tài)polufil
- entry打包入口
定義打包的入口
module.exports = {
entry: './src/index.js'
}
// 多入口
module.exports = {
entry: {
index: './src/index.js',
list: './src/index.js'
}
}
- output輸出
編譯后文件輸出到磁盤的相關(guān)配置
module.exports = {
output: {
filename: '[name]_[chunkhash:8].js', // 單個文件可以直接杖挣,多入口利用占位符保證文件統(tǒng)一
path: path.join(__dirname, '../dist'), // 寫入文件磁盤路徑
publicPath: 'https://cdn.example.com/assets/' // 使用CDN磅甩,給全部文件引入模板文件時加上路徑前綴
}
}
- loader(資源解析轉(zhuǎn)換)
webpack原生只支持js和json,利用loader绪爸,對不一樣的文件類型支持跛十,轉(zhuǎn)換成有效的模塊
// 1豆巨、解析es6和jsx
module.exports = {
module: {
rules: [
{
test: /\.(j|t)sx?$/,
use: 'babel-loader',
exclude: /node_modules/
}
]
}
}
// 2蜻拨、解析css文件
// style-loader 將樣式經(jīng)過style標(biāo)簽插入模板文件的head中
// css-loader 用于加載css文件,轉(zhuǎn)換成commonJs對象
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
// 3眠冈、解析less
// less-loader
{
test: /.css$/,
use: [
'style-loader',
'css-loader',
{
loader: 'less-loader',
options: { // 可配置屬性略号,修改變量的值,通常利用來修改UI庫的主題樣式洋闽,如下是antd主題樣式配置
modifyVars: {
'@primary-color': '#ec7259',
},
javascriptEnabled: true, // 支持內(nèi)聯(lián)的js
}
}
]
}
// 4玄柠、圖片和字體解析
/* file-loader:解析圖片, 字體等
url-loader:也可處理圖片和字體诫舅,并可設(shè)置較小資源自動base64羽利,url-loader比file-loader功能強大 */
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name: 'static/img/[name].[hash:8].[ext]', // [ext]代表文件后綴名
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 8192,
name: 'static/fonts/[name].[hash:8].[ext]'
}
}
// 5刊懈、移動端適配
/* px2rem-loader: 把px轉(zhuǎn)換成rem这弧,配合lib-flexible使用 */
{
loader: 'px2rem-loader',
options: {
remUnit: 75, // 1rem=多少像素
remPrecision: 8, // rem的小數(shù)點后位數(shù)
}
}
// 6、css前綴補齊
/* postcss-loader:用于瀏覽器適配虚汛,某些css3屬性瀏覽器不支持須要加前綴匾浪,它會自動針對不一樣瀏覽器加不一樣的屬性前綴 */
{
loader: 'postcss-loader',
options: {
plugin: ()=> [autoprefixer()] // 安裝autoprefixer
}
}
- plugin(利用插件對webpack進(jìn)行擴展和加強)
- 解決loader沒法完成的事
- 由于插件能夠攜帶參數(shù)/選項,因此要向 plugins屬性傳入new實例 簡單示例
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin") // 自動生成index.html
const { CleanWebpackPlugin } = require("clean-webpack-plugin") // 每次打包清空文件夾
const MiniCssExtractPlugin = require("mini-css-extract-plugin") // css分離
const TerserWebpackPlugin = require("terser-webpack-plugin") // 壓縮js(在optimization中配置)
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin") // 壓縮css
// 1卷哩、 頁面打包
new HtmlWebpackPlugin({ // 產(chǎn)出html文件蛋辈,編譯時會讀取模板文件
filename: '../dist/index.html', // 指定生成的模板文件名及路徑
template: path.join(__dirname, '../index.html'), // 指定要使用的模板文件
inject: true, // 指定的chunk會自動注入html文件中
chunks: ['index'], // 為了避免緩存,可以在指定產(chǎn)出的資源后面添加hash值
minify: { // 代碼的最小輸出
collapseWhitespace: true, // 刪除空格将谊,但不會刪除script冷溶、style和textarea中的空格
preserveLineBreaks: false, // 是否保留換行符
minifyCss: true, // css壓縮
minifyJs: true, // js壓縮
removeComments: true // 刪除注釋,可是會保留script和style中的注釋
}
})尊浓,
// 2逞频、文件清理
/*
每次打包文件到dist,首先要清理dist內(nèi)部文件栋齿,或直接刪除dist文件夾苗胀,防止文件重復(fù) 咱們可利用rimraf dist
但此方式不太優(yōu)雅,咱們可使用clean-webpack-plugin瓦堵,清理dist內(nèi)部文件 */
new CleanWebpackPlugin(),
// 3基协、css剝離
/*
css代碼默認(rèn)打包在js文件中,但有時候css變了谷丸,js沒變堡掏,或者相反,這是不利于緩存的刨疼,
咱們能夠把css剝離出來單獨生成文件泉唁,去作緩存處理 */
new MiniCssExtractPlugin({
filename: '[name]_[contenthash:8].css', // 代碼塊名字
chunkFilename: "[id].css" // 異步加載用
}),
// 4、css壓縮
/* 既然css單獨剝離出來揩慕,就要作壓縮 */
new OptimizeCssAssetsPlugin({
assetNameRegExp: /\.css$/g,
// cssProcessor: require("cssnao") // cssnano 壓縮和優(yōu)化的css插件
})
// 5亭畜、基礎(chǔ)庫分離
/*
咱們常把一些不太變化的靜態(tài)資源放在cdn上,而后在模版文件里引入
在webpack也提供了插件支持迎卤,可直接配置插入
假如咱們分離react和react-dom
*/
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin');
plugins: [
new HtmlWebpackExternalsPlugin({
externals: [
{
module: 'react',
entry: 'https://cdn.cn/16.8.0/react.min.js',
global: 'React',
},
{
module: 'react-dom',
entry: 'https://cdn.cn/16.8.0/react-dom.min.js',
global: 'ReactDOM',
}
]
})
]
- mode(針對開發(fā)環(huán)境和生產(chǎn)環(huán)境的區(qū)分處理)
對應(yīng)三個屬性:
- development 開發(fā)模式
- production 生產(chǎn)模式
- none 無
webpack會針對不一樣環(huán)境直接作一些優(yōu)化工做拴鸵,例如production模式下會進(jìn)行,tree-shaking和scope-hosting
- devServer(熱更新)
devServer: {
historyApiFallback: true, // 單頁面程序 刷新瀏覽器會出現(xiàn)404,緣由是它經(jīng)過這個路徑(好比: /search/list)來訪問后臺劲藐,因此會出現(xiàn)404八堡,而把historyApiFallback設(shè)置為true那么全部的路徑都執(zhí)行index.html
host: '192.168.1.1', // 域名
open: true, // 支持自動打開瀏覽器
hot: true, // 模塊熱替換,在前端代碼變更的時候無需整個刷新頁面聘芜,只把變化的部分替換掉
inline: false, // inline選項會為入口頁面添加“熱加載”功能兄渺,即代碼改變后從新加載頁面
port: 8080, // 端口
proxy: proxyConfig._proxy, // 代理后端服務(wù)
before(app) { // 其余中間件以前, 提供執(zhí)行自定義中間件
apiMocker(app, path.resolve('./mocks/mock.js'), // 舉例:可用來作mock數(shù)據(jù)
proxyConfig._proxy);
}
}
- resolve(模塊解析)
設(shè)置模塊如何被解析
常用屬性:
- alias 建立 import 或 require 的別名汰现,來確保模塊引入變得更簡單
- extensions 自動解析肯定的擴展
- mainFileds 當(dāng)從 npm 包中導(dǎo)入模塊時挂谍,決定在 package.json 中使用哪一個字段導(dǎo)入模塊
- moudles 告訴 webpack 解析模塊時應(yīng)該搜索的目錄
resolve: {
alias: {
'@': path.resolve('src'),
'@nm': path.resolve('node_modules')
},
extensions: ['.js', '.jsx', '.json'],
moudles: [path.resolve(__dirname, 'node_modules')]
}
- optimization(優(yōu)化)
1、提取公共資源
- 項目多頁面的時候瞎饲,大多數(shù)頁面使用的基礎(chǔ)庫或依賴都是同樣的口叙,這時每一個頁面都單獨打包一份,對資源是一種浪費嗅战,打包后體積較大妄田,頁面加載時間長,
- 因此咱們能夠把公共資源提取出來單獨打包仗哨,訪問多頁面時利用緩存機制形庭,只加載一次,達(dá)到優(yōu)化目的
- splitChunks厌漂,代替以前的CommonsChunkPlugin萨醒,公共資源分離vendors
2、公共文件分離
- 一些公共的工具函數(shù)類文件苇倡,咱們能夠經(jīng)過限制被調(diào)用的次數(shù)來決定是否把它分離出來
- 利用splitChunks 公共文件分離commons
3富纸、提取webpack的模塊化信息清單
- 模塊信息清單在每次有模塊變動(hash 變動)時都會變動, 因此把這部分代碼單獨打包出來, 配合后端緩存策略,
- 避免某個模塊的變化致使包含在模塊化信息中的模塊緩存失效
- 具體使用runtimeChunk
optimization: {
runtimeChunk: {
name: 'manifest',
},
splitChunks: {
minSize: 50000 // 分離的包的體積大小
cacheGroups: {
vendors: {
test: /(react|react-dom)/, //正則匹配要分離的文件
name: 'vendors',
chunks: 'all', // 肯定對何種引入方式的文件進(jìn)行分離
minChunks: 1, // 最小使用的次數(shù)
priority: 10, // 多個緩存組時,須要有優(yōu)先級排列旨椒,優(yōu)先使用哪一個進(jìn)行分離
},
commons: { // 分離公共文件
name: 'commons',
chunks: 'all',
minChunks: 2,
priority: 5,
},
},
},
minimizer: [ // 放優(yōu)化的插件
new TerserWebpackPlugin({ // 壓縮js
parallel: true, // 開啟多進(jìn)程壓縮
cache: true // 開啟緩存(壓縮過的不壓縮)
}),
new OptimizeCssAssetsWebpackPlugin({ // 壓縮css
assetNameRegExp: /\.css$/g,
// cssProcessor: require("cssnao")
})
]
},
- devtool(源碼調(diào)試)
- 控制是否生成晓褪,以及如何生成 source map
- 咱們要進(jìn)行一個配置以方便咱們在測試環(huán)境進(jìn)行問題定位,源碼調(diào)試的加強
關(guān)鍵字定義:
- eval 模塊都使用 eval() 包裹執(zhí)行综慎,而且都有 //@ sourceURL(指向的是原文件index.js涣仿,調(diào)試的時候,根據(jù)sourceUrl找到的index.js文件的)
- source map 產(chǎn)生.map文件(這個map文件會和原始文件作一個映射示惊,調(diào)試的時候好港,就是經(jīng)過這個.map文件去定位原來的代碼位置的 )
- cheap 不包含列的信息,(假如代碼運行出現(xiàn)了錯誤米罚,控制臺報出了钧汹,error,咱們點擊定位到具體源碼的時候录择,就只能定位到行拔莱,而不能定位到具體的列)
- inline .map文件做為dataUrl嵌入到打包文件碗降,而不單獨生成
- moudle 包含loader的sourcemap(調(diào)試的代碼不會被轉(zhuǎn)換,會保留原始代碼語法)
幾種關(guān)鍵字進(jìn)行組合就造成了具體的用法,不一樣用法對構(gòu)建速度是有影響的塘秦,基本狀況你越清晰容易的看到原始的代碼讼渊,構(gòu)建速度就越慢,調(diào)試的方便性和構(gòu)建速度上你們能夠本身權(quán)衡一下
// 開發(fā)環(huán)境
devtool: 'cheap-module-eval-source-map' // 原始源代碼(僅限行)
// 生產(chǎn)環(huán)境嗤形,通常不進(jìn)行設(shè)置
優(yōu)化手段
- 優(yōu)化分析 stats
// 構(gòu)建完成后會生成json文件精偿,顯示構(gòu)建的一些信息,時間赋兵,各模塊的體積等
scripts: {
'build: stats': 'webpack --config build/webpack.prod.config.js --json > stats.json',
}
- 速度分析
分析每一個插件和loader的耗時狀況 使用舉例
const SpeedMeasureWebpackPlugin = require('speed-measure-webpack-plugin')
const smp = new SpeedMeasureWebpackPlugin();
module.exports = smp.wrap(merge(webpackConfigBase, webpackConfigProd));
可以看到每一個插件和loader的耗時狀況, 若是耗時較長搔预,會以紅字提示霹期,咱們就能夠具體分析那個地方為何時間長,能夠用別的插件替換之類的去作構(gòu)建速度優(yōu)化
- 體積分析
以圖形大小的形式拯田,更加直觀的看到各個模塊插件所占用的體積
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
plugins: [
new BundleAnalyzerPlugin({
analyzerPort: 8919 //打包構(gòu)建后體積分析圖展現(xiàn)的窗口
}),
],
- tree-shaking
- 字面意思是搖晃樹历造,就是把樹上壞掉的葉子搖下來,就是死碼清除(即沒有被用到的代碼)
- 某個模塊或文件船庇,的某個方法被用到了吭产,整個模塊都會被打包都bundle文件中去,tree-shaking會把沒有用到的方法去除鸭轮,在uglify階段清除
- 僅支持es6語法 webpack 4 中設(shè)置 production 默認(rèn)開啟了此項優(yōu)化
- 多進(jìn)程構(gòu)建
- webpack構(gòu)建是一個涉及文件的讀寫的過程臣淤,若是項目很是復(fù)雜,構(gòu)建時間就會加長
- 而webpack運行在nodejs上是單線程模型窃爷,同一時間只能處理一個任務(wù)
- 咱們是否可讓webpack同時進(jìn)行多任務(wù)處理呢 happypack和thread loader給咱們提供了方案
- thread loader由官方提供
- thread loader放在最上面邑蒋,就會在最后執(zhí)行,以前的loader會在一個單獨的worker池中運行
- 每一個 worker 都是一個單獨的有 600ms 限制的 node.js 進(jìn)程按厘,從而實現(xiàn)了多進(jìn)程的構(gòu)建医吊,下降構(gòu)建時間 舉例
rules: [
{
test: /.js$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 3, // 產(chǎn)生的 worker 的數(shù)量,默認(rèn)是 cpu 的核心數(shù)
}
}
]
},
]
- 構(gòu)建異常逮京,中斷處理
構(gòu)建過程當(dāng)中卿堂,有時會出現(xiàn)構(gòu)建異常報錯的狀況,咱們能夠經(jīng)過某些方法捕獲懒棉,以及自定義一些邏輯
plugins: [
// 主動捕獲構(gòu)建錯誤
function () {
this.hooks.done.tap('done', (stats) => {
if (stats.compilation.errors
&& process.argv.indexOf('--watch' == -1)) {
console.log('error', stats.compilation.errors);
// 能夠作一個構(gòu)建系統(tǒng)的日志草描,在此處上報錯誤緣由
process.exit(12); // 自定義錯誤code碼
}
});
},
],
- 并行壓縮
- webpack4 推薦使用 terser-webpack-plugin 開啟 parallel
- uglify-webpack-plugin也支持并行壓縮,但不支持es6漓藕,不作具體介紹陶珠,有興趣的同窗自行查詢
optimization: {
minimizer: [
new TerserPluginWebpack({
parallel: 4, // 開啟 不主動指定的話,默認(rèn)數(shù)值是當(dāng)前電腦cpu數(shù)量的2倍減1
})
],
}
- 分包享钞,預(yù)編譯資源模塊
問題 以前的分包存在問題
- externals 分包會打出太多的script標(biāo)簽
- splitchunk 分包須要一個分析的時間
解決
- 預(yù)編譯資源模塊
- 將react揍诽,react-dom redux 等基礎(chǔ)包和業(yè)務(wù)基礎(chǔ)包打包成一個文件
方法
- dll-plugin進(jìn)行分包诀蓉,
- dllreferenceplugin 對mainfest.json(對分離包的描述)引用,將預(yù)編譯的模塊加載進(jìn)來
- 利用add-asset-html-webpack-plugin把生成文件插入模版
// package.json
"scripts": {
"dll": "webpack --config build/webpack.dll.js" // 打包前只需執(zhí)行一次暑脆,只要基礎(chǔ)包不變則不須要執(zhí)行
},
// webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: { // 指定要分離的包
library: [ // 基礎(chǔ)包
'react',
'react-dom',
],
},
output: {
filename: "[name]_[hash].dll.js",
path: path.resolve(__dirname, './library'),
library: "[name]_[hash]", //包名稱 注意此名需和下面的DllPlugin渠啤,name名一致
},
plugins: [
new webpack.DllPlugin({
name: "[name]_[hash]",
path: path.resolve(__dirname, './library/[name].json')
})
]
}
// webpack.prod.js
plugins: [
...
// 將給定的 JS文件添加到 webpack 配置的文件中,并插入到模版文件中
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, '../build/library/*.dll.js'),
}),
//
new webpack.DllReferencePlugin({
manifest: require('../build/library/library.json')
}),
]
- 提高二次構(gòu)建后的速度
緩存插件 hard-source-webpack-plugin
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
plugins: [
...
new HardSourceWebpackPlugin()
]
]}
- css的tree-shaking(Remove unused CSS)
- 清除css無用代碼
- 早期PurifyCSSPlugin添吗,它主要的做用是能夠去除沒有用到的CSS代碼沥曹,相似JS的Tree Shaking,現(xiàn)已再也不維護(hù)
- 如今使用purgecss-webpack-plugin碟联,配合mini-css-extract-plugin使用
const PATHS = {
src: path.join(__dirname, '../src')
}
plugin: [
new PurgecssPlugin({
paths: glob.sync(`${PATHS.src}/**/*`, { nodir: true }), // 注意是絕對路徑匹配
}),
]
- webpack 圖片壓縮
- 使圖片壓縮更加自動化
- 基于node庫的imagemin
/* 支持定制選項妓美,
可引入第三方插件
支持多個圖片格式 */
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8192,
name:'[name]_[hash:8].[ext]'
}
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.90],
speed: 4
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 75
}
}
},
],
},
- 動態(tài)polyfill服務(wù)
polyfill-service
- 獲取瀏覽器的useragent判斷支持狀況,
- 動態(tài)的返回瀏覽器不支持的新特性
- 官方提供了cdnhttps://polyfill.io/v3/polyfill.min.js
- 也能夠基于官方自建polyfill服務(wù)鲤孵,更加自由的配置屬性(好比壶栋,指定只判斷promise的支持程度) 例如 https://polyfill.alicdn.com/polyfill.min.js?features=Promise
基礎(chǔ)配置
解析js
解析css
解析less
解析圖片
解析字體
前綴補齊
移動端適配
目錄清理
頁面打包
css抽離
異常主動捕獲提升構(gòu)建速度
resolve縮小文件的搜索范圍
使用DllPlugin減小基礎(chǔ)模塊編譯次數(shù)
thread loader 多進(jìn)程構(gòu)建
terser并行壓縮
hard-source-webpack-plugin提高二次構(gòu)建速度
dll分包,預(yù)編譯資源模塊減少構(gòu)建體積
公共資源分離
Tree Shaking
scope-hoisting
js普监,css贵试,字體,圖片壓縮
動態(tài)polyfill
css的tree-shaking
代碼分割凯正,按需引入毙玻,import動態(tài)加載提高開發(fā)體驗
sourcemap源碼調(diào)試
devserver熱更新
友好錯誤提示保證穩(wěn)定安全
代碼壓縮混淆