一、webpack簡(jiǎn)介
1.1 webpack是什么
webpack 是一種前端資源構(gòu)建工具,一個(gè)靜態(tài)模塊打包器(module bundler)。
在 webpack 看來(lái), 前端的所有資源文件(js/json/css/img/less/...)都會(huì)作為模塊處理。
它將根據(jù)模塊的依賴關(guān)系進(jìn)行靜態(tài)分析,打包生成對(duì)應(yīng)的靜態(tài)資源(bundle)。
1.2 webpack五個(gè)核心概念
1.2.1 Entry
入口(Entry)指示 webpack 以哪個(gè)文件為入口起點(diǎn)開(kāi)始打包,分析構(gòu)建內(nèi)部依賴圖。
1.2.2 Output
輸出(Output)指示 webpack 打包后的資源 bundles 輸出到哪里去,以及如何命名。
1.2.3 Loader
Loader 讓 webpack 能 夠 去 處 理 那 些 非 JavaScript 文 件 (webpack 自 身 只 理 解 JavaScript)
1.2.4 Plugins
插件(Plugins)可以用于執(zhí)行范圍更廣的任務(wù)。插件的范圍包括,從打包優(yōu)化和壓縮, 一直到重新定義環(huán)境中的變量等
1.2.5 Mode
模式(Mode)指示 webpack 使用相應(yīng)模式的配置。
選項(xiàng) 描述 特點(diǎn)
development 會(huì)將 DefinePlugin 中 process.env.NODE_ENV 的值設(shè)置 為 development。啟用 NamedChunksPlugin 和NamedModulesPlugin。 能讓代碼本地調(diào)試 運(yùn)行的環(huán)境
production 會(huì)將 DefinePlugin 中 process.env.NODE_ENV 的值設(shè)置 為 production。啟用 FlagDependencyUsagePlugin, FlagIncludedChunksPlugin, ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin, SideEffectsFlagPlugin 和 TerserPlugin。 能讓代碼優(yōu)化上線 運(yùn)行的環(huán)境
二、webpack的初體驗(yàn)
2.1 初始化配置
1.初始化 package.json npm init -y
2.下載安裝webpack:(webpack4以上的版本需要全局/本地都安裝webpack-cli)
全局安裝:cnpm i webpack webpack-cli -g
本地安裝:cnpm i webpack webpack-cli -D
2.2 編譯打包應(yīng)用
- 創(chuàng)建文件
- 運(yùn)行指令
開(kāi)發(fā)環(huán)境指令:webpack --entry src/js/index.js -o build/js/built.js --mode=development
功能:webpack 能夠編譯打包 js 和 json 文件,并且能將 es6 的模塊化語(yǔ)法轉(zhuǎn)換成 瀏覽器能識(shí)別的語(yǔ)法。
生產(chǎn)環(huán)境指令:webpack --entry src/js/index.js -o build/js/built.js --mode=production
功能:在開(kāi)發(fā)配置功能上多一個(gè)功能,壓縮代碼。 - 結(jié)論
webpack 能夠編譯打包 js 和 json 文件。
能將 es6 的模塊化語(yǔ)法轉(zhuǎn)換成瀏覽器能識(shí)別的語(yǔ)法。
能壓縮代碼。 - 問(wèn)題
不能編譯打包 css、img 等文件。
不能將 js 的 es6 基本語(yǔ)法轉(zhuǎn)化為 es5 以下語(yǔ)法。
三、webpack開(kāi)發(fā)環(huán)境的基本配置
3.1 webpack.config.js
- webpack的配置文件
- 作用: 指示 webpack 干哪些活(當(dāng)你運(yùn)行 webpack 指令時(shí),會(huì)加載里面的配置)
- 所有構(gòu)建工具都是基于nodejs平臺(tái)運(yùn)行的~模塊化默認(rèn)采用commonjs。
- src文件夾里面的代碼是基于ES6模塊化的
3.2 開(kāi)發(fā)環(huán)境基礎(chǔ)配置
3.2.1 打包樣式資源
// resolve用來(lái)拼接絕對(duì)路徑的方法
const { resolve } = require('path');
module.exports = {
// webpack配置
// 入口起點(diǎn)
entry: './src/index.js',
// 輸出
output: {
// 輸出文件名
filename: 'built.js',
// 輸出路徑
// __dirname nodejs的變量,代表當(dāng)前文件的目錄絕對(duì)路徑
path: resolve(__dirname, 'build')
},
// loader的配置
module: {
rules: [
// 詳細(xì)loader配置
// 不同文件必須配置不同loader處理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader進(jìn)行處理
use: [
// use數(shù)組中l(wèi)oader執(zhí)行順序:從右到左,從下到上 依次執(zhí)行
// 創(chuàng)建style標(biāo)簽,將js中的樣式資源插入進(jìn)行,添加到head中生效
'style-loader',
// 將css文件變成commonjs模塊加載js中,里面內(nèi)容是樣式字符串
'css-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
// 將less文件編譯成css文件
// 需要下載 less-loader和less
'less-loader'
]
}
]
},
// plugins的配置
plugins: [
// 詳細(xì)plugins的配置
],
// 模式
mode: 'development', // 開(kāi)發(fā)模式
// mode: 'production'
}
3.2.2 打包html資源
/*
loader: 1. 下載 2. 使用(配置loader)
plugins: 1. 下載 2. 引入 3. 使用
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
]
},
plugins: [
// plugins的配置
// html-webpack-plugin
// 功能:默認(rèn)會(huì)創(chuàng)建一個(gè)空的HTML,自動(dòng)引入打包輸出的所有資源(JS/CSS)
// 需求:需要有結(jié)構(gòu)的HTML文件
new HtmlWebpackPlugin({
// 復(fù)制 './src/index.html' 文件,并自動(dòng)引入打包輸出的所有資源(JS/CSS)
template: './src/index.html'
})
],
mode: 'development'
};
3.2.3 打包圖片資源
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多個(gè)loader處理用use
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 問(wèn)題:默認(rèn)處理不了html中img圖片
// 處理圖片資源
test: /\.(jpg|png|gif)$/,
// 使用一個(gè)loader
// 下載 url-loader file-loader
loader: 'url-loader',
options: {
// 圖片大小小于8kb,就會(huì)被base64處理
// 優(yōu)點(diǎn): 減少請(qǐng)求數(shù)量(減輕服務(wù)器壓力)
// 缺點(diǎn):圖片體積會(huì)更大(文件請(qǐng)求速度更慢)
limit: 8 * 1024,
// 問(wèn)題:因?yàn)閡rl-loader默認(rèn)使用es6模塊化解析,而html-loader引入圖片是commonjs
// 解析時(shí)會(huì)出問(wèn)題:[object Module]
// 解決:關(guān)閉url-loader的es6模塊化,使用commonjs解析
esModule: false,
// 給圖片進(jìn)行重命名
// [hash:10]取圖片的hash的前10位
// [ext]取文件原來(lái)擴(kuò)展名
name: '[hash:10].[ext]'
}
},
{
test: /\.html$/,
// 處理html文件的img圖片(負(fù)責(zé)引入img,從而能被url-loader進(jìn)行處理)
loader: 'html-loader'
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
3.2.5 打包其他資源(不需要做優(yōu)化的資源,比如字體圖標(biāo))
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他資源(除了html/js/css資源以外的資源)
{
// 排除css/js/html資源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
3.2.4 devServer
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他資源(除了html/js/css資源以外的資源)
{
// 排除css/js/html資源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
// 開(kāi)發(fā)服務(wù)器 devServer:用來(lái)自動(dòng)化(自動(dòng)編譯,自動(dòng)打開(kāi)瀏覽器,自動(dòng)刷新瀏覽器~~)
// 特點(diǎn):只會(huì)在內(nèi)存中編譯打包,不會(huì)有任何輸出
// 啟動(dòng)devServer指令為:npx webpack-dev-server
devServer: {
// 項(xiàng)目構(gòu)建后路徑
contentBase: resolve(__dirname, 'build'),
// 啟動(dòng)gzip壓縮
compress: true,
// 端口號(hào)
port: 3000,
// 自動(dòng)打開(kāi)瀏覽器
open: true
}
};
3.3 開(kāi)發(fā)環(huán)境總結(jié)配置
3.3.1 問(wèn)題總結(jié)
- 處理html中的img圖片問(wèn)題,在webpack5中html-loader中也需要配置,esModule為false,否則還是不生效,像下面這樣
{
test: /.html$/,
/**
* html-loader可以處理html中的img圖片,可負(fù)責(zé)將其中的圖片引入,然后交由url-loader進(jìn)行解析
*/
loader: 'html-loader',
options: {
esModule: false
}
} - TypeError: Cannot read property 'tap' of undefined at HtmlWebpackPlugin.apply
所以考慮到html-webpack-plugin的版本,我們需要把html-webpack-plugin的版本降低一些
npm uninstall html-webpack-plugin
npm install html-webpack-plugin@3.2.0 -D - ERROR in Error: Child compilation failed:
Module build failed (from ../node_modules/html-loader/dist/cjs.js):
TypeError: this.getOptions is not a function
需要將html-loader降低版本
npm uninstall html-loader
npm install html-loader@0.5.5 -D - 打包后圖片不顯示
需要多添加排除的選項(xiàng)|jpg|png|gif,否則圖片不顯示
{
// 排除css/js/html等資源
exclude: /.(html|js|css|less|jpg|png|gif)/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
outputPath: "media",
},
},
3.3.2 配置總結(jié)
開(kāi)發(fā)環(huán)境配置:能讓代碼運(yùn)行
運(yùn)行項(xiàng)目指令:
webpack 會(huì)將打包結(jié)果輸出出去
npx webpack-dev-server 只會(huì)在內(nèi)存中編譯打包,沒(méi)有輸出
// resolve用來(lái)拼接絕對(duì)路徑的方法
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
// webpack配置
// 入口起點(diǎn)
entry: "./src/js/index.js",
// 輸出
output: {
// 輸出文件名
filename: "js/built.js",
// 輸出路徑
// __dirname nodejs的變量,代表當(dāng)前文件的目錄絕對(duì)路徑
path: resolve(__dirname, "build"),
},
// loader的配置
module: {
rules: [
// 詳細(xì)loader配置
// 不同文件必須配置不同loader處理
{
// 匹配哪些文件
test: /\.css$/,
// 使用哪些loader進(jìn)行處理
use: [
// use數(shù)組中l(wèi)oader執(zhí)行順序:從右到左,從下到上 依次執(zhí)行
// 創(chuàng)建style標(biāo)簽,將js中的樣式資源插入進(jìn)行,添加到head中生效
"style-loader",
// 將css文件變成commonjs模塊加載js中,里面內(nèi)容是樣式字符串
"css-loader",
],
},
{
test: /\.less$/,
use: [
"style-loader",
"css-loader",
// 將less文件編譯成css文件
// 需要下載 less-loader和less
"less-loader",
],
},
{
// 問(wèn)題:默認(rèn)處理不了html中img圖片
// 處理圖片資源
test: /\.(jpg|png|gif)$/,
// 使用一個(gè)loader
// 下載 url-loader file-loader
loader: "url-loader",
options: {
// 圖片大小小于8kb,就會(huì)被base64處理
// 優(yōu)點(diǎn): 減少請(qǐng)求數(shù)量(減輕服務(wù)器壓力)
// 缺點(diǎn):圖片體積會(huì)更大(文件請(qǐng)求速度更慢)
//建議對(duì)8kb-12kb的圖片進(jìn)行處理
limit: 8 * 1024,
// 問(wèn)題:因?yàn)閡rl-loader默認(rèn)使用es6模塊化解析,而html-loader引入圖片是commonjs
// 解析時(shí)會(huì)出問(wèn)題:[object Module]
// 解決:關(guān)閉url-loader的es6模塊化,使用commonjs解析
esModule: false,
// 給圖片進(jìn)行重命名
// [hash:10]取圖片的hash的前10位
// [ext]取文件原來(lái)擴(kuò)展名
name: "[hash:10].[ext]",
outputPath: "imgs",
},
},
{
test: /\.html$/,
// 處理html文件的img圖片(負(fù)責(zé)引入img,從而能被url-loader進(jìn)行處理)
loader: "html-loader",
//webpack5也需要關(guān)閉es6模塊化,使用commonJs解析才能夠打包
options: {
esModule: false,
},
},
// 打包其他資源(除了html/js/css資源以外的資源)
{
// 排除css/js/html等資源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: "file-loader",
options: {
name: "[hash:10].[ext]",
outputPath: "media",
},
},
],
},
// plugins的配置
plugins: [
// 詳細(xì)plugins的配置
// html-webpack-plugin
// 功能:默認(rèn)會(huì)創(chuàng)建一個(gè)空的HTML,自動(dòng)引入打包輸出的所有資源(JS/CSS)
// new HtmlWebpackPlugin({}),
// 需求:需要有結(jié)構(gòu)的HTML文件
new HtmlWebpackPlugin({
// 復(fù)制 './src/index.html' 文件,并自動(dòng)引入打包輸出的所有資源(JS/CSS)
template: "./src/index.html",
}),
],
// 開(kāi)發(fā)服務(wù)器 devServer:用來(lái)自動(dòng)化(自動(dòng)編譯,自動(dòng)打開(kāi)瀏覽器,自動(dòng)刷新瀏覽器~~)
// 特點(diǎn):只會(huì)在內(nèi)存中編譯打包,不會(huì)有任何輸出,不會(huì)輸出build文件
// 啟動(dòng)devServer指令為:npx webpack-dev-server(啟動(dòng)前提需要下載webpack-dev-server包)
devServer: {
// 項(xiàng)目構(gòu)建后路徑
contentBase: resolve(__dirname, "build"),
// 啟動(dòng)gzip壓縮,讓我們代碼體積更小,速度更快
compress: true,
// 端口號(hào)
port: 3000,
// 自動(dòng)打開(kāi)瀏覽器
open: true,
},
// 模式
mode: "development", // 開(kāi)發(fā)模式
// mode: 'production',//生產(chǎn)模式
};
四、webpack生產(chǎn)環(huán)境的基本配置
4.1 生產(chǎn)環(huán)境基礎(chǔ)配置
4.1.1 提取CSS成單獨(dú)文件
提取css成單獨(dú)文件需要的插件mini-css-extract-plugin
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
//提取css成單獨(dú)文件需要的插件mini-css-extract-plugin
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
// 創(chuàng)建style標(biāo)簽,將樣式放入
// 'style-loader',
// 這個(gè)loader取代style-loader。作用:提取js中的css成單獨(dú)文件
MiniCssExtractPlugin.loader,
// 將css文件整合到j(luò)s文件中
'css-loader'
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
// 對(duì)輸出的css文件進(jìn)行重命名
filename: 'css/built.css'
})
],
mode: 'development'
};
4.1.2 CSS兼容性處理
css兼容性處理需要的插件postcss-loader postcss-preset-env
會(huì)出現(xiàn)編譯不成功,將postcss-loader版本從4+降低為3.0.0
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 設(shè)置nodejs環(huán)境變量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
/*
css兼容性處理:postcss --> postcss-loader postcss-preset-env
幫postcss找到package.json中browserslist里面的配置,通過(guò)配置加載指定的css兼容性樣式
"browserslist": {
// 開(kāi)發(fā)環(huán)境 --> 設(shè)置node環(huán)境變量:process.env.NODE_ENV = development
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
],
// 生產(chǎn)環(huán)境:默認(rèn)是看生產(chǎn)環(huán)境
"production": [
">0.2%",
"not dead",
"not op_mini all"
]
}
*/
// 使用loader的默認(rèn)配置
// 'postcss-loader',
// 修改loader的配置
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
})
],
mode: 'development'
};
4.1.3 壓縮CSS
壓縮CSS需要的插件:optimize-css-assets-webpack-plugin
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
// 設(shè)置nodejs環(huán)境變量
// process.env.NODE_ENV = 'development';
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [
// postcss的插件
require('postcss-preset-env')()
]
}
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
// 壓縮css
new OptimizeCssAssetsWebpackPlugin()
],
mode: 'development'
};
4.1.4 JS語(yǔ)法檢查
需要下載的插件:eslint-loader eslint
檢查規(guī)則需要的插件:eslint-config-airbnb-base eslint-plugin-import eslint
如果想忽視eslint的語(yǔ)法檢查可以在代碼上一行添加: // eslint-disable-next-line
這樣下一行eslint所有規(guī)則都失效(下一行不進(jìn)行eslint檢查)
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
語(yǔ)法檢查: eslint-loader eslint
注意:只檢查自己寫(xiě)的源代碼,第三方的庫(kù)是不用檢查的
設(shè)置檢查規(guī)則:
package.json中eslintConfig中設(shè)置~
"eslintConfig": {
"extends": "airbnb-base"
}
airbnb --> eslint-config-airbnb-base eslint-plugin-import eslint
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自動(dòng)修復(fù)eslint的錯(cuò)誤
fix: true
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
4.1.5 JS兼容性處理
js兼容性處理需要下載的插件:babel-loader @babel/core @babel/preset-env @babel/polyfill core-js
基本js兼容性處理 --> @babel/preset-env
問(wèn)題:只能轉(zhuǎn)換基本語(yǔ)法,如promise高級(jí)語(yǔ)法不能轉(zhuǎn)換全部js兼容性處理 --> @babel/polyfill
問(wèn)題:我只要解決部分兼容性問(wèn)題,但是將所有兼容性代碼全部 引入,體積太大了~-
需要做兼容性處理的就做:按需加載 --> core-js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
/*
js兼容性處理:babel-loader @babel/core @babel/preset-env @babel/polyfill core-js
1. 基本js兼容性處理 --> @babel/preset-env
問(wèn)題:只能轉(zhuǎn)換基本語(yǔ)法,如promise高級(jí)語(yǔ)法不能轉(zhuǎn)換
2. 全部js兼容性處理 --> @babel/polyfill
問(wèn)題:我只要解決部分兼容性問(wèn)題,但是將所有兼容性代碼全部引入,體積太大了~
3. 需要做兼容性處理的就做:按需加載 --> core-js
*/
{
test: /.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
// 預(yù)設(shè):指示babel做怎么樣的兼容性處理
presets: [
[
'@babel/preset-env',
{
// 按需加載
useBuiltIns: 'usage',
// 指定core-js版本
corejs: {
version: 3
},
// 指定兼容性做到哪個(gè)版本瀏覽器
targets: {
chrome: '60',
firefox: '60',
ie: '9',
safari: '10',
edge: '17'
}
}
]
]
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
4.1.6 JS壓縮
將mode設(shè)置為production 就可以自動(dòng)壓縮js代碼
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
// 生產(chǎn)環(huán)境下會(huì)自動(dòng)壓縮js代碼
mode: 'production'
};
4.1.7 html壓縮
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
// 壓縮html代碼
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注釋
removeComments: true
}
})
],
mode: 'production'
};
4.2 生產(chǎn)環(huán)境總結(jié)配置
4.2.1 問(wèn)題總結(jié)
- ERROR in ./src/css/a.css
Module build failed (from ../node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ../node_modules/postcss-loader/dist/cjs.js):
TypeError: this.getOptions is not a function
at Object.loader (Z:\learn\webpack-study\mycode\node_modules\postcss-loader\dist\index.js:38:24)
at Z:\learn\webpack-study\mycode\node_modules\webpack\lib\NormalModule.js:316:20
at Z:\learn\webpack-study\mycode\node_modules\loader-runner\lib\LoaderRunner.js:367:11
at Z:\learn\webpack-study\mycode\node_modules\loader-runner\lib\LoaderRunner.js:233:18
@ ./src/js/index.js 1:0-22
ERROR in ./src/css/b.css
Module build failed (from ../node_modules/mini-css-extract-plugin/dist/loader.js):
ModuleBuildError: Module build failed (from ../node_modules/postcss-loader/dist/cjs.js):
TypeError: this.getOptions is not a function
at Object.loader (Z:\learn\webpack-study\mycode\node_modules\postcss-loader\dist\index.js:38:24)
at Z:\learn\webpack-study\mycode\node_modules\webpack\lib\NormalModule.js:316:20
at Z:\learn\webpack-study\mycode\node_modules\loader-runner\lib\LoaderRunner.js:367:11
at Z:\learn\webpack-study\mycode\node_modules\loader-runner\lib\LoaderRunner.js:233:18
@ ./src/js/index.js 2:0-22
降低postcss-loader的版本,從4+降到了3.0.0,后來(lái)就可以正常編譯了。 - error 'core-js' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
1:8 error Unexpected use of file extension "js" for "core-js/modules/es.promise.js" import/extensions
1:8 error Strings must use singlequote quotes
2:8 error 'core-js' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
2:8 error Unexpected use of file extension "js" for "core-js/modules/es.object.to-string.js" import/extensions
2:8 error Strings must use singlequote quotes
3:8 error 'core-js' should be listed in the project's dependencies, not devDependencies import/no-extraneous-dependencies
3:8 error Unexpected use of file extension "js" for "core-js/modules/web.timers.js" import/extensions
下載corejs插件不限制在開(kāi)發(fā)環(huán)境 不加-D
還需要添加 enforce: "pre",
{
test: /.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
// 優(yōu)先執(zhí)行
enforce: "pre",
options: {
// 自動(dòng)修復(fù)eslint的錯(cuò)誤
fix: true,
},
},
4.2.2 總結(jié)配置
注意:正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
const { resolve } = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCssAssetsWebpackPlugin = require("optimize-css-assets-webpack-plugin");
// 設(shè)置nodejs環(huán)境變量
// process.env.NODE_ENV = "development";
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
"css-loader",
{
// 還需要在package.json中定義browserslist
loader: "postcss-loader",
options: {
ident: "postcss",
plugins: () => [require("postcss-preset-env")()],
},
},
];
module.exports = {
entry: "./src/js/index.js",
output: {
filename: "js/built.js",
path: resolve(__dirname, "build"),
},
module: {
rules: [
{
test: /\.css$/,
use: [...commonCssLoader],
// use: [
// // 創(chuàng)建style標(biāo)簽,將樣式放入
// // 'style-loader',
// // 這個(gè)loader取代style-loader。作用:提取js中的css成單獨(dú)文件
// MiniCssExtractPlugin.loader,
// // 將css文件整合到j(luò)s文件中
// "css-loader",
// /*
// css兼容性處理:postcss --> postcss-loader postcss-preset-env
// postcss-preset-env插件幫postcss找到package.json中browserslist里面的配置,通過(guò)配置加載指定的css兼容性樣式
// package.json中的配置:
// "browserslist": {
// // 開(kāi)發(fā)環(huán)境 --> 設(shè)置node環(huán)境變量:process.env.NODE_ENV = development
// "development": [
// "last 1 chrome version",
// "last 1 firefox version",
// "last 1 safari version"
// ],
// // 生產(chǎn)環(huán)境:默認(rèn)是看生產(chǎn)環(huán)境 與mode:development設(shè)置無(wú)關(guān) 與process.env.NODE_ENV = development有關(guān)
// "production": [
// ">0.2%",
// "not dead",
// "not op_mini all"
// ]
// }
// */
// // 使用loader的默認(rèn)配置
// // "postcss-loader",
// // 修改loader的配置,就要是如下的寫(xiě)法
// {
// loader: "postcss-loader",
// options: {
// //固定寫(xiě)法
// ident: "postcss",
// plugins: () => [
// // postcss的插件
// require("postcss-preset-env")(),
// ],
// },
// },
// ],
},
{
test: /\.less$/,
use: [...commonCssLoader, "less-loader"],
},
/*
語(yǔ)法檢查: eslint-loader eslint
注意:只檢查自己寫(xiě)的源代碼,第三方的庫(kù)是不用檢查的
設(shè)置檢查規(guī)則:
package.json中eslintConfig中設(shè)置~
"eslintConfig": {
"extends": "airbnb-base"
}
airbnb --> eslint-config-airbnb-base eslint eslint-plugin-import eslint
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: "eslint-loader",
// 優(yōu)先執(zhí)行
enforce: "pre",
options: {
// 自動(dòng)修復(fù)eslint的錯(cuò)誤
fix: true,
},
},
/*
js兼容性處理:babel-loader @babel/core @babel/preset-env
1. 基本js兼容性處理 --> @babel/preset-env
問(wèn)題:只能轉(zhuǎn)換基本語(yǔ)法,如promise高級(jí)語(yǔ)法不能轉(zhuǎn)換
2. 全部js兼容性處理 --> @babel/polyfill 簡(jiǎn)單粗暴直接引入js文件中
問(wèn)題:我只要解決部分兼容性問(wèn)題,但是將所有兼容性代碼全部引入,體積太大了~
3. 需要做兼容性處理的就做:按需加載 --> core-js
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
// 預(yù)設(shè):指示babel做怎么樣的兼容性處理
presets: [
[
"@babel/preset-env",
{
// 按需加載
useBuiltIns: "usage",
// 指定core-js版本
corejs: {
version: 3,
},
// 指定兼容性做到哪個(gè)版本瀏覽器
targets: {
chrome: "60",
firefox: "60",
ie: "9",
safari: "10",
edge: "17",
},
},
],
],
},
},
{
test: /\.(jpg|png|gif)/,
loader: "url-loader",
options: {
limit: 8 * 1024,
name: "[hash:10].[ext]",
outputPath: "imgs",
esModule: false,
},
},
{
test: /\.html$/,
loader: "html-loader",
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: "file-loader",
options: {
outputPath: "media",
},
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/index.html",
// 壓縮html代碼
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注釋
removeComments: true,
},
}),
//提取css成單獨(dú)文件
new MiniCssExtractPlugin({
// 對(duì)輸出的css文件進(jìn)行重命名
filename: "css/built.css",
}),
// 壓縮css
new OptimizeCssAssetsWebpackPlugin(),
],
mode: "development",
};
五、webpack優(yōu)化配置
總的來(lái)說(shuō),開(kāi)發(fā)環(huán)境需要優(yōu)化打包構(gòu)建速度,對(duì)開(kāi)發(fā)者更加友好,因?yàn)榇a會(huì)越來(lái)越多,導(dǎo)致包的體積越來(lái)越大,就需要我們注重打包時(shí)間,這樣對(duì)調(diào)試開(kāi)發(fā)更加友好;還需要我們優(yōu)化代碼調(diào)試,了解代碼出錯(cuò)在哪里。
生產(chǎn)環(huán)境配置需要代碼上線運(yùn)行即可,需要優(yōu)化代碼的性能,讓用戶體驗(yàn)感更好,所以要求性能提升。
開(kāi)發(fā)環(huán)境性能優(yōu)化:
- 優(yōu)化打包構(gòu)建速度
- HMR
- 優(yōu)化代碼調(diào)試
- source-map
生產(chǎn)環(huán)境性能優(yōu)化:
優(yōu)化打包構(gòu)建速度
oneOf
babel緩存
多進(jìn)程打包
externals
dll
優(yōu)化代碼運(yùn)行的性能
緩存(hash-chunkhash-contenthash)
tree shaking
code split
懶加載/預(yù)加載
pwa
5.1 開(kāi)發(fā)環(huán)境性能優(yōu)化配置
5.1.1 HMR(熱膜替換)
為什么會(huì)提出這個(gè)HMR?是因?yàn)榧僭O(shè)有1000個(gè)模塊代碼,其中一個(gè)模塊更改,其他都要重新跑一邊,速度會(huì)很慢。所以就提出HMR,一個(gè)模塊發(fā)生變化,只會(huì)重新打包這一個(gè)模塊(而不是打包所有模塊) ;
/*
HMR: hot module replacement 熱模塊替換 / 模塊熱替換
作用:一個(gè)模塊發(fā)生變化,只會(huì)重新打包這一個(gè)模塊(而不是打包所有模塊)
極大提升構(gòu)建速度
樣式文件:可以使用HMR功能:因?yàn)閟tyle-loader內(nèi)部實(shí)現(xiàn)了~
js文件:默認(rèn)不能使用HMR功能 --> 需要修改js代碼,添加支持HMR功能的代碼
注意:HMR功能對(duì)js的處理,只能處理非入口js文件的其他文件。
html文件: 默認(rèn)不能使用HMR功能.同時(shí)會(huì)導(dǎo)致問(wèn)題:html文件不能熱更新了~ (不用做HMR功能)
解決:修改entry入口,將html文件引入
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 處理less資源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 處理css資源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 處理圖片資源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 關(guān)閉es6模塊化
esModule: false,
outputPath: 'imgs'
}
},
{
// 處理html中img資源
test: /\.html$/,
loader: 'html-loader'
},
{
// 處理其他資源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
// 開(kāi)啟HMR功能
// 當(dāng)修改了webpack配置,新配置要想生效,必須重新webpack服務(wù)
hot: true
}
};
// 引入
import print from './print';
import '../css/iconfont.css';
import '../css/index.less';
console.log('index.js文件被加載了~');
print();
function add(x, y) {
return x + y;
}
console.log(add(1, 3));
if (module.hot) {
// 一旦 module.hot 為true,說(shuō)明開(kāi)啟了HMR功能。 --> 讓HMR功能代碼生效
module.hot.accept('./print.js', function() {
// 方法會(huì)監(jiān)聽(tīng) print.js 文件的變化,一旦發(fā)生變化,其他模塊不會(huì)重新打包構(gòu)建。
// 會(huì)執(zhí)行后面的回調(diào)函數(shù)
print();
});
}
5.1.2 source-map
/*
source-map: 一種 提供源代碼到構(gòu)建后代碼映射 技術(shù) (如果構(gòu)建后代碼出錯(cuò)了,通過(guò)映射可以追蹤源代碼錯(cuò)誤)
[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map
source-map:外部
錯(cuò)誤代碼準(zhǔn)確信息 和 源代碼的錯(cuò)誤位置
inline-source-map:內(nèi)聯(lián)
只生成一個(gè)內(nèi)聯(lián)source-map
錯(cuò)誤代碼準(zhǔn)確信息 和 源代碼的錯(cuò)誤位置
hidden-source-map:外部
錯(cuò)誤代碼錯(cuò)誤原因,但是沒(méi)有錯(cuò)誤位置
不能追蹤源代碼錯(cuò)誤,只能提示到構(gòu)建后代碼的錯(cuò)誤位置
eval-source-map:內(nèi)聯(lián)
每一個(gè)文件都生成對(duì)應(yīng)的source-map,都在eval
錯(cuò)誤代碼準(zhǔn)確信息 和 源代碼的錯(cuò)誤位置(位置是哈希值)
nosources-source-map:外部
錯(cuò)誤代碼準(zhǔn)確信息, 但是沒(méi)有任何源代碼信息
cheap-source-map:外部
錯(cuò)誤代碼準(zhǔn)確信息 和 源代碼的錯(cuò)誤位置
只能精確的行,不能精確到列
cheap-module-source-map:外部
錯(cuò)誤代碼準(zhǔn)確信息 和 源代碼的錯(cuò)誤位置
module會(huì)將loader的source map加入
內(nèi)聯(lián) 和 外部的區(qū)別:1. 外部生成了文件,內(nèi)聯(lián)沒(méi)有 2. 內(nèi)聯(lián)構(gòu)建速度更快
開(kāi)發(fā)環(huán)境:速度快,調(diào)試更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
調(diào)試更友好
souce-map
cheap-module-souce-map
cheap-souce-map
--> eval-source-map(vue腳手架是這個(gè)) / eval-cheap-module-souce-map
生產(chǎn)環(huán)境:源代碼要不要隱藏? 調(diào)試要不要更友好
內(nèi)聯(lián)會(huì)讓代碼體積變大,所以在生產(chǎn)環(huán)境不用內(nèi)聯(lián)
nosources-source-map 全部隱藏
hidden-source-map 只隱藏源代碼,會(huì)提示構(gòu)建后代碼錯(cuò)誤信息
--> source-map / cheap-module-souce-map
*/
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/index.html'],
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
// 處理less資源
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
},
{
// 處理css資源
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
// 處理圖片資源
test: /\.(jpg|png|gif)$/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
// 關(guān)閉es6模塊化
esModule: false,
outputPath: 'imgs'
}
},
{
// 處理html中img資源
test: /\.html$/,
loader: 'html-loader'
},
{
// 處理其他資源
exclude: /\.(html|js|css|less|jpg|png|gif)/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]',
outputPath: 'media'
}
}
]
},
plugins: [
// plugins的配置
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development',
devServer: {
contentBase: resolve(__dirname, 'build'),
compress: true,
port: 3000,
open: true,
hot: true
},
devtool: 'eval-source-map'
};
5.2 生產(chǎn)環(huán)境性能優(yōu)化配置
5.2.1優(yōu)化打包構(gòu)建速度
5.2.1.1 oneOf
優(yōu)化生產(chǎn)環(huán)境構(gòu)建速度的
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 定義nodejs環(huán)境變量:決定使用browserslist的哪個(gè)環(huán)境
process.env.NODE_ENV = 'production';
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 優(yōu)先執(zhí)行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只會(huì)匹配一個(gè)
// 注意:不能有兩個(gè)配置處理同一種類型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: {version: 3},
targets: {
chrome: '60',
firefox: '50'
}
}
]
]
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
5.2.1.2 緩存(babel緩存和文件資源緩存)
為什么會(huì)有babel緩存呢?因?yàn)閎abel會(huì)對(duì)我們js代碼進(jìn)行編譯處理,編譯成瀏覽器能夠識(shí)別的語(yǔ)法。
HMR是對(duì)開(kāi)發(fā)環(huán)境來(lái)說(shuō)的,生產(chǎn)環(huán)境下不能用HMR功能,因?yàn)镠MR是基于devserver的,而生產(chǎn)環(huán)境是不需要devServer。
而babel想做的是其中一個(gè)js文件變,其他文件不變,就需要開(kāi)啟babel緩存。假設(shè)對(duì)100個(gè)文件進(jìn)行編譯后的緩存,當(dāng)后面再去做的時(shí)候文件沒(méi)有變化,就是使用緩存了,而不是重新構(gòu)建一次了。
文件資源緩存:通過(guò)添加hash值去更新文件,當(dāng)文件改變之后,只有改變的文件對(duì)應(yīng)的打包文件的hash值會(huì)變化
推薦使用contenthash
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
緩存:
babel緩存
cacheDirectory: true
--> 讓第二次打包構(gòu)建速度更快
文件資源緩存
hash: 每次wepack構(gòu)建時(shí)會(huì)生成一個(gè)唯一的hash值。
問(wèn)題: 因?yàn)閖s和css同時(shí)使用一個(gè)hash值。
如果重新打包,會(huì)導(dǎo)致所有緩存失效。(可能我卻只改動(dòng)一個(gè)文件)
chunkhash:根據(jù)chunk生成的hash值。如果打包來(lái)源于同一個(gè)chunk,那么hash值就一樣
問(wèn)題: js和css的hash值還是一樣的
因?yàn)閏ss是在js中被引入的,所以同屬于一個(gè)chunk
contenthash: 根據(jù)文件的內(nèi)容生成hash值。不同文件hash值一定不一樣
--> 讓代碼上線運(yùn)行緩存更好使用
*/
// 定義nodejs環(huán)境變量:決定使用browserslist的哪個(gè)環(huán)境
process.env.NODE_ENV = 'production';
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 優(yōu)先執(zhí)行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只會(huì)匹配一個(gè)
// 注意:不能有兩個(gè)配置處理同一種類型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 開(kāi)啟babel緩存
// 第二次構(gòu)建時(shí),會(huì)讀取之前的緩存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
};
5.2.1.3 tree shaking(樹(shù)搖)
目的:為了去除我們應(yīng)用程序中沒(méi)有使用的代碼,減少打包體積,提高加載速度
注意要在package.json中配置 "sideEffects": [".css", ".less"],防止把副作用文件給干掉
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
tree shaking:去除無(wú)用代碼
前提:1. 必須使用ES6模塊化 2. 開(kāi)啟production環(huán)境
作用: 減少代碼體積
在package.json中配置
"sideEffects": false 所有代碼都沒(méi)有副作用(都可以進(jìn)行tree shaking)
問(wèn)題:可能會(huì)把css / @babel/polyfill (副作用)文件干掉
"sideEffects": ["*.css", "*.less"]
*/
// 定義nodejs環(huán)境變量:決定使用browserslist的哪個(gè)環(huán)境
process.env.NODE_ENV = 'production';
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 優(yōu)先執(zhí)行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只會(huì)匹配一個(gè)
// 注意:不能有兩個(gè)配置處理同一種類型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 開(kāi)啟babel緩存
// 第二次構(gòu)建時(shí),會(huì)讀取之前的緩存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production',
devtool: 'source-map'
};
5.2.1.3 code split (代碼分割)
目的:將打包的一個(gè)文件輸出成多個(gè)文件,比如說(shuō)將一個(gè)大的文件分割成三個(gè)文件,加載的時(shí)候可以并行加載,從而速度更快,還可以實(shí)現(xiàn)按需加載的功能(就是需要這個(gè)文件我們就加載使用)
demo1:多入口打包
單頁(yè)面對(duì)應(yīng)單入口,多頁(yè)面應(yīng)用對(duì)應(yīng)多入口
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 單入口
// entry: './src/js/index.js',
entry: {
// 多入口:有一個(gè)入口,最終輸出就有一個(gè)bundle
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
mode: 'production'
};
demo2:
demo1問(wèn)題是多入口不太靈活,如果后面有多個(gè)入口,改來(lái)改去太麻煩,所以就有demo2
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 單入口
// entry: './src/js/index.js',
entry: {
index: './src/js/index.js',
test: './src/js/test.js'
},
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以將node_modules中代碼單獨(dú)打包一個(gè)chunk最終輸出
2. 自動(dòng)分析多入口chunk中,有沒(méi)有公共的文件。如果有會(huì)打包成單獨(dú)一個(gè)chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
};
demo3:
demo2問(wèn)題:可以對(duì)node_modules中代碼進(jìn)行單獨(dú)打包一個(gè)chunk最終輸出,并且也可以對(duì)多入口的情況下,對(duì)公共的文件打包成一個(gè)chunk,但是對(duì)單入口下,自己寫(xiě)的公共js代碼無(wú)法進(jìn)行打包成一個(gè)chunk。
通過(guò)js代碼,讓單入口情況下,某個(gè)文件單獨(dú)打包成一個(gè)chunk
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
/*
通過(guò)js代碼,讓某個(gè)文件被單獨(dú)打包成一個(gè)chunk
import動(dòng)態(tài)導(dǎo)入語(yǔ)法:能將某個(gè)文件單獨(dú)打包
加上/* webpackChunkName: 'test' */是給打包的chunk取一個(gè)名字為test
*/
import(/* webpackChunkName: 'test' */'./test')
.then(({ mul, count }) => {
// 文件加載成功~
// eslint-disable-next-line
console.log(mul(2, 5));
})
.catch(() => {
// eslint-disable-next-line
console.log('文件加載失敗~');
});
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 單入口
entry: './src/js/index.js',
output: {
// [name]:取文件名
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
/*
1. 可以將node_modules中代碼單獨(dú)打包一個(gè)chunk最終輸出
2. 自動(dòng)分析多入口chunk中,有沒(méi)有公共的文件。如果有會(huì)打包成單獨(dú)一個(gè)chunk
*/
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
};
5.2.1.4 lazy loading (懶加載/預(yù)加載)
懶加載指的是js文件的懶加載
利用代碼分割的思路,將import語(yǔ)法放入異步回調(diào)代碼中;
懶加載中添加預(yù)加載,預(yù)加載:在觸發(fā)js代碼之前就加載了,之后點(diǎn)擊按鈕進(jìn)行回調(diào)是讀取的緩存中的js
console.log('index.js文件被加載了~');
// import { mul } from './test';
document.getElementById('btn').onclick = function() {
// 懶加載~:當(dāng)文件需要使用時(shí)才加載~
// 預(yù)加載 prefetch:會(huì)在使用之前,提前加載js文件
// 正常加載可以認(rèn)為是并行加載(同一時(shí)間加載多個(gè)文件)
// 預(yù)加載 prefetch:等其他資源加載完畢,瀏覽器空閑了,再偷偷加載資源 但是這種兼容性不好,只能在高版本的瀏覽器中使用,在移動(dòng)端和IE慎用
import(/* webpackChunkName: 'test', webpackPrefetch: true */'./test').then(({ mul }) => {
console.log(mul(4, 5));
});
};
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 單入口
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
],
optimization: {
splitChunks: {
chunks: 'all'
}
},
mode: 'production'
};
5.2.1.5 pwa (離線可訪問(wèn)技術(shù))
PWA:漸進(jìn)式網(wǎng)絡(luò)應(yīng)用程序
目的:實(shí)現(xiàn)像應(yīng)用程序一樣,離線也可以訪問(wèn),性能也更好,缺點(diǎn)是兼容性不太好
需要下載插件 workbox-webpack-plugin
問(wèn)題:打包報(bào)錯(cuò)
'workbox-routing/registerRoute.js' is imported by ..\node_modules\workbox-precaching\addRoute.js, but could not be resolved – treating it as an external dependency
'workbox-core/private/getFriendlyURL.js' is imported by ..\node_modules\workbox-precaching\PrecacheRoute.js, but could not be resolved – treating it as an external dependency
'workbox-core/private/logger.js' is imported by ..\node_modules\workbox-precaching\PrecacheRoute.js, but could not be resolved – treating it as an external dependency
'workbox-routing/Route.js' is imported by ..\node_modules\workbox-precaching\PrecacheRoute.js, but could not be resolved – treating it as an external dependency
'workbox-core/private/assert.js' is imported by ..\node_modules\workbox-precaching\PrecacheController.js, but could not be resolved – treating it as an external dependency
'workbox-core/private/cacheNames.js' is imported by ..\node_modules\workbox-precaching\PrecacheController.js, but could not be resolved – treating it as an external dependency
因?yàn)閣orkbox-webpack-plugin版本的問(wèn)題,pwa技術(shù)在cache里面沒(méi)有緩存,后來(lái)我是降低版本為5.0.0.才解決這個(gè)問(wèn)題的
index.js
import { mul } from './test';
import '../css/index.css';
function sum(...args) {
return args.reduce((p, c) => p + c, 0);
}
// eslint-disable-next-line
console.log(mul(2, 3));
// eslint-disable-next-line
console.log(sum(1, 2, 3, 4));
/*
1. eslint不認(rèn)識(shí) window、navigator全局變量
解決:需要修改package.json中eslintConfig配置
"env": {
"browser": true // 支持瀏覽器端全局變量
}
2. sw代碼必須運(yùn)行在服務(wù)器上
--> nodejs
-->
npm i serve -g
serve -s build 啟動(dòng)服務(wù)器,將build目錄下所有資源作為靜態(tài)資源暴露出去
*/
// 注冊(cè)serviceWorker
// 處理兼容性問(wèn)題
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker
.register('/service-worker.js')
.then(() => {
console.log('sw注冊(cè)成功了~');
})
.catch(() => {
console.log('sw注冊(cè)失敗了~');
});
});
}
webpack.config.js
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
/*
PWA: 漸進(jìn)式網(wǎng)絡(luò)開(kāi)發(fā)應(yīng)用程序(離線可訪問(wèn))
workbox --> workbox-webpack-plugin
*/
// 定義nodejs環(huán)境變量:決定使用browserslist的哪個(gè)環(huán)境
process.env.NODE_ENV = 'production';
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 優(yōu)先執(zhí)行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只會(huì)匹配一個(gè)
// 注意:不能有兩個(gè)配置處理同一種類型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 開(kāi)啟babel緩存
// 第二次構(gòu)建時(shí),會(huì)讀取之前的緩存
cacheDirectory: true
}
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 幫助serviceworker快速啟動(dòng)
2. 刪除舊的 serviceworker
生成一個(gè) serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
],
mode: 'production',
devtool: 'source-map'
};
5.2.1.6 多進(jìn)程打包
多進(jìn)程打包:
進(jìn)程啟動(dòng)大概為600ms,進(jìn)程通信也有開(kāi)銷。
只有工作消耗時(shí)間比較長(zhǎng),才需要多進(jìn)程打包
一個(gè)項(xiàng)目中通常js文件比較多,所以通常是對(duì)js進(jìn)行多進(jìn)程打包的,減少整體打包的時(shí)間
const { resolve } = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
/*
PWA: 漸進(jìn)式網(wǎng)絡(luò)開(kāi)發(fā)應(yīng)用程序(離線可訪問(wèn))
workbox --> workbox-webpack-plugin
*/
// 定義nodejs環(huán)境變量:決定使用browserslist的哪個(gè)環(huán)境
process.env.NODE_ENV = 'production';
// 復(fù)用loader
const commonCssLoader = [
MiniCssExtractPlugin.loader,
'css-loader',
{
// 還需要在package.json中定義browserslist
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: () => [require('postcss-preset-env')()]
}
}
];
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.[contenthash:10].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
// 在package.json中eslintConfig --> airbnb
test: /\.js$/,
exclude: /node_modules/,
// 優(yōu)先執(zhí)行
enforce: 'pre',
loader: 'eslint-loader',
options: {
fix: true
}
},
{
// 以下loader只會(huì)匹配一個(gè)
// 注意:不能有兩個(gè)配置處理同一種類型文件
oneOf: [
{
test: /\.css$/,
use: [...commonCssLoader]
},
{
test: /\.less$/,
use: [...commonCssLoader, 'less-loader']
},
/*
正常來(lái)講,一個(gè)文件只能被一個(gè)loader處理。
當(dāng)一個(gè)文件要被多個(gè)loader處理,那么一定要指定loader執(zhí)行的先后順序:
先執(zhí)行eslint 在執(zhí)行babel
*/
{
test: /\.js$/,
exclude: /node_modules/,
use: [
/*
開(kāi)啟多進(jìn)程打包。
進(jìn)程啟動(dòng)大概為600ms,進(jìn)程通信也有開(kāi)銷。
只有工作消耗時(shí)間比較長(zhǎng),才需要多進(jìn)程打包
*/
{
loader: 'thread-loader',
options: {
workers: 2 // 進(jìn)程2個(gè)
}
},
{
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
useBuiltIns: 'usage',
corejs: { version: 3 },
targets: {
chrome: '60',
firefox: '50'
}
}
]
],
// 開(kāi)啟babel緩存
// 第二次構(gòu)建時(shí),會(huì)讀取之前的緩存
cacheDirectory: true
}
}
]
},
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/built.[contenthash:10].css'
}),
new OptimizeCssAssetsWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
}),
new WorkboxWebpackPlugin.GenerateSW({
/*
1. 幫助serviceworker快速啟動(dòng)
2. 刪除舊的 serviceworker
生成一個(gè) serviceworker 配置文件~
*/
clientsClaim: true,
skipWaiting: true
})
],
mode: 'production',
devtool: 'source-map'
};
5.2.1.7 externals
目的:防止將一些包打包輸出在我們的budle中。有時(shí)候我們不想講juery包進(jìn)行打包,我們是使用的CDN進(jìn)行juery的獲取,此時(shí)我們就需要在打包的時(shí)候排除打包juery
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'production',
externals: {
// 拒絕jQuery被打包進(jìn)來(lái)
jquery: 'jQuery'
}
};
5.2.1.8 dll(動(dòng)態(tài)鏈接庫(kù))
dll:讓某些庫(kù)單獨(dú)打包,后直接引入到 build 中。可以在 code split 分割出 node_modules 后再用 dll 更細(xì)的分割,優(yōu)化代碼運(yùn)行的性能
webpack.dll.js
/*
使用dll技術(shù),對(duì)某些庫(kù)(第三方庫(kù):jquery、react、vue...)進(jìn)行單獨(dú)打包
當(dāng)你運(yùn)行 webpack 時(shí),默認(rèn)查找 webpack.config.js 配置文件
需求:需要運(yùn)行 webpack.dll.js 文件
--> webpack --config webpack.dll.js
*/
const { resolve } = require('path');
const webpack = require('webpack');
module.exports = {
entry: {
// 最終打包生成的[name] --> jquery
// ['jquery'] --> 要打包的庫(kù)是jquery
jquery: ['jquery'],
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'dll'),
library: '[name]_[hash]' // 打包的庫(kù)里面向外暴露出去的內(nèi)容叫什么名字
},
plugins: [
// 打包生成一個(gè) manifest.json --> 提供和jquery映射 將來(lái)我們可以知道我們juery不需要打包,juery庫(kù)的名稱是[name]_[hash]
new webpack.DllPlugin({
name: '[name]_[hash]', // 映射庫(kù)的暴露的內(nèi)容名稱
path: resolve(__dirname, 'dll/manifest.json') // 輸出文件路徑
})
],
mode: 'production'
};
webpack.config.js
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');
const AddAssetHtmlWebpackPlugin = require('add-asset-html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
// 告訴webpack哪些庫(kù)不參與打包,同時(shí)使用時(shí)的名稱也得變~
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 將某個(gè)文件打包輸出去,并在html中自動(dòng)引入該資源
new AddAssetHtmlWebpackPlugin({
filepath: resolve(__dirname, 'dll/jquery.js')
})
],
mode: 'production'
};
六、webpack配置詳情
6.1 entry
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
/*
entry: 入口起點(diǎn)
1. string --> './src/index.js'
單入口
打包形成一個(gè)chunk。 輸出一個(gè)bundle文件。
此時(shí)chunk的名稱默認(rèn)是 main
2. array --> ['./src/index.js', './src/add.js']
多入口
所有入口文件最終只會(huì)形成一個(gè)chunk, 輸出出去只有一個(gè)bundle文件。
--> 只有在HMR功能中讓html熱更新生效~
3. object
多入口
有幾個(gè)入口文件就形成幾個(gè)chunk,輸出幾個(gè)bundle文件
此時(shí)chunk的名稱是 key
--> 特殊用法
{
// 所有入口文件最終只會(huì)形成一個(gè)chunk, 輸出出去只有一個(gè)bundle文件。
index: ['./src/index.js', './src/count.js'],
// 形成一個(gè)chunk,輸出一個(gè)bundle文件。
add: './src/add.js'
}
*/
module.exports = {
entry: {
index: ['./src/index.js', './src/count.js'],
add: './src/add.js'
},
output: {
filename: '[name].js',
path: resolve(__dirname, 'build')
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
6.2 output
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
// 文件名稱(指定名稱+目錄)
filename: 'js/[name].js',
// 輸出文件目錄(將來(lái)所有資源輸出的公共目錄)
path: resolve(__dirname, 'build'),
// 所有資源引入公共路徑前綴 --> 'imgs/a.jpg' --> '/imgs/a.jpg'
publicPath: '/',
chunkFilename: 'js/[name]_chunk.js', // 非入口chunk的名稱
// library: '[name]', // 整個(gè)庫(kù)向外暴露的變量名
// libraryTarget: 'window' // 變量名添加到哪個(gè)上 browser
// libraryTarget: 'global' // 變量名添加到哪個(gè)上 node
// libraryTarget: 'commonjs'
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
6.3 module
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader的配置
{
test: /\.css$/,
// 多個(gè)loader用use
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/,
// 排除node_modules下的js文件
exclude: /node_modules/,
// 只檢查 src 下的js文件
include: resolve(__dirname, 'src'),
// 優(yōu)先執(zhí)行
enforce: 'pre',
// 延后執(zhí)行
// enforce: 'post',
// 單個(gè)loader用loader
loader: 'eslint-loader',
options: {}
},
{
// 以下配置只會(huì)生效一個(gè)
oneOf: []
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development'
};
6.4 resolve
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
// 解析模塊的規(guī)則
resolve: {
// 配置解析模塊路徑別名: 優(yōu)點(diǎn)簡(jiǎn)寫(xiě)路徑 缺點(diǎn)路徑?jīng)]有提示
alias: {
$css: resolve(__dirname, 'src/css')
},
// 配置省略文件路徑的后綴名
extensions: ['.js', '.json', '.jsx', '.css'],
// 告訴 webpack 解析模塊是去找哪個(gè)目錄
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
}
};
6.5 dev server
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'development',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
devServer: {
// 運(yùn)行代碼的目錄
contentBase: resolve(__dirname, 'build'),
// 監(jiān)視 contentBase 目錄下的所有文件,一旦文件變化就會(huì) reload
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},
// 啟動(dòng)gzip壓縮
compress: true,
// 端口號(hào)
port: 5000,
// 域名
host: 'localhost',
// 自動(dòng)打開(kāi)瀏覽器
open: true,
// 開(kāi)啟HMR功能
hot: true,
// 不要顯示啟動(dòng)服務(wù)器日志信息
clientLogLevel: 'none',
// 除了一些基本啟動(dòng)信息以外,其他內(nèi)容都不要顯示
quiet: true,
// 如果出錯(cuò)了,不要全屏提示~
overlay: false,
// 服務(wù)器代理 --> 解決開(kāi)發(fā)環(huán)境跨域問(wèn)題
proxy: {
// 一旦devServer(5000)服務(wù)器接受到 /api/xxx 的請(qǐng)求,就會(huì)把請(qǐng)求轉(zhuǎn)發(fā)到另外一個(gè)服務(wù)器(3000)
'/api': {
target: 'http://localhost:3000',
// 發(fā)送請(qǐng)求時(shí),請(qǐng)求路徑重寫(xiě):將 /api/xxx --> /xxx (去掉/api)
pathRewrite: {
'^/api': ''
}
}
}
}
};
6.6 optimization
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin')
module.exports = {
entry: './src/js/index.js',
output: {
filename: 'js/[name].[contenthash:10].js',
path: resolve(__dirname, 'build'),
chunkFilename: 'js/[name].[contenthash:10]_chunk.js'
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()],
mode: 'production',
resolve: {
alias: {
$css: resolve(__dirname, 'src/css')
},
extensions: ['.js', '.json', '.jsx', '.css'],
modules: [resolve(__dirname, '../../node_modules'), 'node_modules']
},
optimization: {
splitChunks: {
chunks: 'all'
// 默認(rèn)值,可以不寫(xiě)~
/* minSize: 30 * 1024, // 分割的chunk最小為30kb
maxSiza: 0, // 最大沒(méi)有限制
minChunks: 1, // 要提取的chunk最少被引用1次
maxAsyncRequests: 5, // 按需加載時(shí)并行加載的文件的最大數(shù)量
maxInitialRequests: 3, // 入口js文件最大并行請(qǐng)求數(shù)量
automaticNameDelimiter: '~', // 名稱連接符
name: true, // 可以使用命名規(guī)則
cacheGroups: {
// 分割chunk的組
// node_modules文件會(huì)被打包到 vendors 組的chunk中。--> vendors~xxx.js
// 滿足上面的公共規(guī)則,如:大小超過(guò)30kb,至少被引用一次。
vendors: {
test: /[\\/]node_modules[\\/]/,
// 優(yōu)先級(jí)
priority: -10
},
default: {
// 要提取的chunk最少被引用2次
minChunks: 2,
// 優(yōu)先級(jí)
priority: -20,
// 如果當(dāng)前要打包的模塊,和之前已經(jīng)被提取的模塊是同一個(gè),就會(huì)復(fù)用,而不是重新打包模塊
reuseExistingChunk: true
}
}*/
},
// 將當(dāng)前模塊的記錄其他模塊的hash單獨(dú)打包為一個(gè)文件 runtime
// 解決:修改a文件導(dǎo)致b文件的contenthash變化
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
minimizer: [
// 配置生產(chǎn)環(huán)境的壓縮方案:js和css
new TerserWebpackPlugin({
// 開(kāi)啟緩存
cache: true,
// 開(kāi)啟多進(jìn)程打包
parallel: true,
// 啟動(dòng)source-map
sourceMap: true
})
]
}
};