基本使用
webpack 是一個(gè)靜態(tài)資源打包工具
它會(huì)以一個(gè)或多個(gè)文件作為打包的入口,將我們整個(gè)項(xiàng)目所有文件編譯組合成一個(gè)或多個(gè)文件輸出出去扎阶。輸出的文件就是編譯好的文件旭绒,就可以在瀏覽器段運(yùn)行了我們將 Webpack 輸出的文件叫做 bundle 。
功能介紹
Webpack 本身功能是有限的:
- 開發(fā)模式:僅能編譯 JS 中的 ES Module 語法
- 生產(chǎn)模式: 能編譯 JS 中的 ES Module 語法逆粹,還能壓縮 JS 代碼
目標(biāo)
webpack 本身功能比較少织阅,只能處理 js 資源壳繁,一旦遇到 css 等其他資源就會(huì)報(bào)錯(cuò) 。
學(xué)習(xí) webpack 主要是學(xué)習(xí)如何處理其他資源
webpack 核心概念
- 入口(entry)
指示 Webpack 從哪個(gè)文件開始打包 - 輸出(output)
指示 Webpack 打包完的文件輸出到哪里去,如何命名等 - loader
webpack 本身只能處理 js闹炉、json 等資源蒿赢,其他資源需要借助 loader,Webpack 才能解析 - 插件(plugins)
擴(kuò)展 Webpack 的功能 - 模式(mode)
- 開發(fā)模式:development
- 生產(chǎn)模式:production
安裝
npm init -y
npm i webpack webpack-cli -D
配置
在文件根目錄新建 webpack.config.js
const path = require('path'); // nodejs核心模塊,專門處理路徑問題
// 配置
module.exports = {
// 入口
entry: './src/main.js', // 相對(duì)路徑
// 輸出
output: {
// 文件的輸出路徑
// __dirname node.js的變量,代表當(dāng)前文件的文件夾目錄
path: path.resolve(__dirname, 'dist'), // 絕對(duì)路徑
// 文件名稱
filename: 'main.js'
},
// 加載器
module: {
rules: [
// loader的配置
]
},
// 插件
plugins: [
// plugin的配置
],
// 模式
mode: 'development'
}
開發(fā)模式介紹
開發(fā)模式顧名思義就是我們開發(fā)代碼時(shí)使用的模式渣触。
這個(gè)模式下我們主要做兩件事:
- 編譯代碼羡棵,使瀏覽器能識(shí)別運(yùn)行
開發(fā)時(shí)我們有樣式資源、字體圖標(biāo)嗅钻、圖片資源皂冰、html 資源等,webpack 默認(rèn)都不能處理這些資源养篓,所以我們要加載配置來編譯這些資源秃流。
- 編譯代碼羡棵,使瀏覽器能識(shí)別運(yùn)行
- 代碼質(zhì)量檢查,樹立代碼規(guī)范
提前檢查代碼的一些隱患柳弄,讓代碼運(yùn)行時(shí)能更加健壯舶胀。
提前檢查代碼規(guī)范和格式,統(tǒng)一團(tuán)隊(duì)編碼風(fēng)格碧注,讓代碼更優(yōu)雅美觀嚣伐。
- 代碼質(zhì)量檢查,樹立代碼規(guī)范
處理樣式資源
處理 css
- 下載 style-loader 和 css-loader
npm i style-loader css-loader -D
- 配置
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
處理 Less
- 下載 less-loader 和 less
npm i less-loader less -D
- 配置
module: {
rules: [
{
test: /\.less$/,
use: ['style-loader', 'css-loader', 'less-loader']
}
]
}
處理 Sass
- 下載 sass-loader 和 sass
npm i sass-loader sass -D
- 配置
module: {
rules: [
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader']
}
]
}
處理 stylus
- 下載 stylus-loader
npm i stylus-loader -D
- 配置
module: {
rules: [
{
test: /\.styl$/,
use: ['style-loader', 'css-loader', 'stylus-loader']
}
]
}
處理圖片資源
- webpack4 時(shí),處理圖片資源需要通過 file-loader 和 url-loader 進(jìn)行處理
- 下載 url-loader 和 file-loader
npm i url-loader file-loader -D
- 配置
module: {
rules: [
{
test: /\.(jpg|png|gif|bmp|jpeg|webp)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs'
}
}
]
}
]
}
webpack5 時(shí)萍丐,這兩個(gè) loader 已經(jīng)內(nèi)置到 webpack 中,只需要配置 type: 'asset'
配置
module: {
rules: [
{
test: /\.(jpg|png|gif|bmp|jpeg|webp)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 10 * 1024 // 小于10kb會(huì)轉(zhuǎn)base64,(優(yōu)點(diǎn):會(huì)減少請(qǐng)求數(shù)量,缺點(diǎn):體積會(huì)更大)
}
}
}
]
}
修改打包輸出文件目錄
-
- JS 文件的去找 output 配置轩端,并修改其中的 filename
filename: 'static/js/main.js',
-
- 圖片的去找圖片的 loader,并添加 generator 配置
generator: { filename: 'static/images/[hash:10][ext][query]' }
自動(dòng)清空上次打包結(jié)果
- 在 output 配置中添加
clean: true
處理字體圖標(biāo)資源
- 在 loader 中配置(和對(duì)圖片的處理配置一樣)
{
test: /\.(ttf|woff2?|eot|otf)$/,
type: 'asset/resource',
generator: {
// 生成輸出字體圖標(biāo)名稱
filename: 'static/fonts/[hash:10][ext][query]'
}
}
處理其他資源(音視頻等)
- 在 type 為
'asset/resource'
配置的 test 匹配規(guī)則后面繼續(xù)增加
test: /\.(ttf|woff2?|eot|otf|mp3|mp4)$/,
處理 JS 資源
- 針對(duì) js 兼容性處理逝变,我們使用 Babel 來完成
- 針對(duì)代碼格式基茵,我們使用 Eslint 來完成
Eslint
檢測代碼中潛在的問題和錯(cuò)誤的工具,可以配置各項(xiàng)功能
在 webpack4 中是一個(gè) loader,在 webpack5 中是一個(gè) plugin
安裝 Eslint
npm i eslint-webpack-plugin eslint -D
- 在 webpack.config.js 中配置 Eslint 插件
const ESLintWebpackPlugin = require('eslint-webpack-plugin')
module.exports = {
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, 'src') // 指定檢查的目錄
})
]
}
- 在根目錄創(chuàng)建
.eslintrc.js
文件
module.exports = {
extends: ["eslint:recommended"],
env: {
node: true, // 啟用node中全局變量
browser: true // 啟用瀏覽器中全局變量
},
parserOptions: {
ecmaVersion: 6, // es6
sourceType: "module" // es module
},
rules: {
"no-var": 2, // 不能使用var定義變量
}
// ...更多規(guī)則看官網(wǎng)
}
Babel
用于將 ES6 代碼轉(zhuǎn)換成向后兼容的 JS 語法
安裝 Babel
npm i @babel/core @babel/preset-env babel-loader -D
- 在 webpack.config.js 中配置 Babel
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/, // 不處理node_modules中的js文件
use: {
loader: 'babel-loader'
}
}
]
}
}
- 在根目錄創(chuàng)建
babel.config.js
文件
module.exports = {
// 智能預(yù)設(shè),能夠編譯es6的語法
presets: ["@babel/preset-env",]
}
處理 Html 資源
- 安裝 html-webpack-plugin
npm i html-webpack-plugin -D
- 在 webpack.config.js 中配置 html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname,'public/index.html') // 指定模板文件路徑
}
)
]
}
開發(fā)服務(wù)器&自動(dòng)化
- 安裝 webpack-dev-server
npm i webpack-dev-server -D
- 在 webpack.config.js 中配置開發(fā)服務(wù)器
module.exports = {
devServer: {
host: 'localhost', // 設(shè)置啟動(dòng)時(shí)候的主機(jī)地址
port: 3000, // 設(shè)置啟動(dòng)時(shí)候的運(yùn)行端口
open: true // 自動(dòng)打開瀏覽器訪問
}
}
- 啟動(dòng)服務(wù)器
npx webpack serve
生產(chǎn)模式介紹
生產(chǎn)模式是開發(fā)完成代碼后壳影,我們需要得到代碼將來部署上線耿导,這個(gè)模式下我們主要對(duì)代碼進(jìn)行優(yōu)化,讓其運(yùn)行性能更好态贤。
優(yōu)化主要從兩個(gè)角度出發(fā):
- 優(yōu)化代碼運(yùn)行性能
- 優(yōu)化代碼打包速度
生產(chǎn)模式準(zhǔn)備
- 根目錄創(chuàng)建 config 文件夾
- 在下面創(chuàng)建
webpack.dev.js
和webpack.prod.js
,分別用于開發(fā)模式和生產(chǎn)模式下的配置文件醋火,
- 在下面創(chuàng)建
- 2.1 開發(fā)環(huán)境不需要輸出,所以設(shè)置 path: undefined
- 2.2 開發(fā)模式下,不需要輸出,所以注釋 clean: true
- 2.3 生產(chǎn)模式下,需要輸出,所有用到絕對(duì)路徑的都要用
../
返回上一層 - 2.4 生產(chǎn)模式不需要 devServer
- 2.5 開發(fā)模式和生產(chǎn)模式中 mode 要統(tǒng)一
生產(chǎn)模式配置
CSS 處理 (提取 CSS 成單獨(dú)文件)
CSS 文件目前被打包到 JS 中,當(dāng) JS 加載時(shí)創(chuàng)建 style 標(biāo)簽來生成樣式,這會(huì)導(dǎo)致頁面閃屏,影響用戶體驗(yàn),應(yīng)該將 CSS 直接提取成單獨(dú)的樣式文件,通過 link 標(biāo)簽引入
安裝 mini-css-extract-plugin
npm i mini-css-extract-plugin -D
- 在 webpack.prod.js 中配置
- 之前所有寫 style-loader 的地方,現(xiàn)在都需要改成 MiniCssExtractPlugin.loader,因?yàn)?style-loader 會(huì)動(dòng)態(tài)創(chuàng)建 style 標(biāo)簽
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, // 提取成單獨(dú)文件
'css-loader',
]
}
]
},
plugins: [
new MiniCssExtractPlugin()
],
}
CSS 兼容性處理
- 安裝 postcss-loader postcss postcss-preset-env
npm i postcss-loader postcss postcss-preset-env -D
- 在 webpack.prod.js 中配置
- 該配置需要寫在 css-loader 的后面和 less-loader悠汽、sass-loader 的前面
{
loader: 'postcss-loader', // 配置postcss
options: {
postcssOptions: {
plugins: [
postcss-preset-env' // 能解決大多數(shù)樣式兼容性問題
]
}
}
},
- 在 package.json 中配置
- 指定兼容性處理到哪個(gè)瀏覽器版本
- 實(shí)際開發(fā)中可以設(shè)置為 "last 2 version" , "> 1%" , "not dead"
"browserslist": [
"ie >= 8"
]
封裝樣式 loader 函數(shù)
- 由于上面配置的 CSS 兼容性樣式處理代碼冗余,將他封裝成一個(gè) loader 函數(shù)
function getStyleLoader(pre) {
return [ // 執(zhí)行順序,從右到左,從下到上
MiniCssExtractPlugin.loader, // 將css提取成單獨(dú)文件
'css-loader', // 將css編譯成commonjs的模塊到j(luò)s中
{
loader: 'postcss-loader', // 配置postcss
options: {
postcssOptions: {
plugins: [
'postcss-preset-env' // 能解決大多數(shù)樣式兼容性問題
]
}
}
},
pre
].filter(Boolean)
}
- 使用
getStyleLoader()
getStyleLoader('less-loader')
getStyleLoader('sass-loader')
getStyleLoader('stylus-loader')
CSS 壓縮
- 安裝插件
npm i css-minimizer-webpack-plugin -D
- 在 webpack.prod.js 中配置
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
HTML 壓縮
- 默認(rèn)生產(chǎn)模式已經(jīng)開啟了 HTML 和 JS 壓縮
webpack 優(yōu)化
- 提升開發(fā)體驗(yàn)
- 提升打包構(gòu)建速度
- 減少代碼體積
- 頭還代碼運(yùn)行性能
開發(fā)體驗(yàn)優(yōu)化
SourceMap
是一個(gè)源代碼映射文件, 里面存儲(chǔ)了代碼轉(zhuǎn)換后的位置信息
實(shí)際開發(fā)中只需要關(guān)注兩種情況即可
-
在 webpack 中配置
- 開發(fā)模式:cheap-module-source-map
- 優(yōu)點(diǎn): 打包速度快
- 缺點(diǎn): 沒有列映射
module.exports: {
// ...
mode:'development',
devtool:'cheap-module-source-map'
}
- 在 webpack 中配置
- 生產(chǎn)模式:source-map
- 優(yōu)點(diǎn): 包含行/ 列映射
- 缺點(diǎn): 打包速度慢
module.exports: {
// ...
mode:'production',
devtool:'source-map'
}
提升打包構(gòu)建速度
Hot Module Replacement
熱模塊替換, 簡稱 HMR
作用: 一個(gè)模塊發(fā)生變化, 只會(huì)重新打包這一個(gè)模塊(而不是打包所有模塊)
CSS 已經(jīng)由 style-loader 開啟 HMR
JS 需要手動(dòng)開啟(但實(shí)際開發(fā)中,會(huì)使用 vue-loader 或 react-loader 來解決)
在 webpack 中配置
module.exports: {
// ...
devServer: {
// ...
// 開啟HMR功能(只能用于開發(fā)環(huán)境)
// hot默認(rèn)值:開啟
hot:true
}
}
OneOf
- 作用: 防止匹配多個(gè) loader 處理文件
- 在 webpack 中配置(開發(fā)模式和生產(chǎn)模式皆可)
module: {
rules: [
{
// 每個(gè)文件只能被其中一個(gè)loader配置處理
oneOf: [
// ...loader
]
}
]
}
Include/Exclude
- Include: 包含,只處理匹配到的文件
- Exclude: 排除,不處理匹配到的文件
- 注意: 只能使用一種,同時(shí)使用會(huì)報(bào)錯(cuò)
rules: [
{
test: /\.js$/,
// exclude: /node_modules/,
include: path.resolve(__dirname, '../src'),
use: { loader: 'babel-loader' }
}
]
Cache
- 每次打包 JS 文件都要經(jīng)過 Eslint 檢查 和 Babel 編譯,速度比較慢芥驳。緩存之前的編譯結(jié)果柿冲,第二次打包時(shí)速度會(huì)變快。
- 在 webpack.prod.js 中配置
module.exports: {
module:{
rules:[
{
test: /\.js$/,
include: path.resolve(__dirname, '../src'),
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true, // 開啟babel緩存
cacheCompression: false, // 關(guān)閉緩存文件壓縮
}
}
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'), // 指定檢查的目錄
exclude: 'node_modules', // 排除檢查
cache: true, // 開啟緩存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache') // 指定緩存位置
}),
]
}
Thead
- 多進(jìn)程打包:開啟電腦的多個(gè)進(jìn)程同時(shí)干一件事兆旬,速度更快假抄。
- 注意:請(qǐng)僅在特別耗時(shí)的操作中使用,因?yàn)槊總€(gè)進(jìn)程啟動(dòng)就有大約為 600ms 左右開銷。
- 安裝
npm i thread-loader -D
- 在 webpack 中配置
// 獲取cpu核數(shù)
const os = require('os')
const threads = os.cpus().length
const TerserPlugin = require("terser-webpack-plugin");
module.exports: {
module:{
rules:[
{
test: /\.js$/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: 'thread-loader', // 開啟多進(jìn)程
options: {
workers: threads, // 進(jìn)程數(shù)量
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true, // 開啟babel緩存
cacheCompression: false, // 關(guān)閉緩存文件壓縮
}
}
]
}
]
},
plugins: [
new ESLintPlugin({
context: path.resolve(__dirname, '../src'), // 指定檢查的目錄
exclude: 'node_modules', // 排除檢查
cache: true, // 開啟緩存
cacheLocation: path.resolve(__dirname, '../node_modules/.cache/.eslintcache') // 指定緩存位置
threads, // 開啟多進(jìn)程和進(jìn)程數(shù)量
}),
new TerserPlugin({
parallel: threads // 開啟多進(jìn)程和進(jìn)程數(shù)量
})
]
}
減少代碼體積
Tree Shaking
Tree Shaking
是一個(gè)術(shù)語宿饱,通常用于描述移除 JavaScript 中的沒有使用上的代碼熏瞄。(例如我們引入了一些函數(shù)庫,但實(shí)際只使用了其中的幾個(gè)功能,如果將這些都打包進(jìn)來,那么項(xiàng)目的體積就太大了)注意:它依賴
ES Module
。webpack 已經(jīng)默認(rèn)開啟了這個(gè)功能谬以,無需其他配置强饮。
Babel
@babel/plugin-transform-runtime
: 禁用了 Babel 自動(dòng)對(duì)每個(gè)文件的 runtime 注入,而是引入@babel/plugin-transform-runtime
并且使所有輔助代碼從這里引用为黎。安裝
npm i @babel/plugin-transform-runtime -D
- 在 webpack 中配置
module.exports: {
module:{
rules:[
{
test: /\.js$/,
include: path.resolve(__dirname, '../src'),
use: [
{
loader: 'thread-loader', // 開啟多進(jìn)程
options: {
workers: threads, // 進(jìn)程數(shù)量
}
},
{
loader: 'babel-loader',
options: {
cacheDirectory: true, // 開啟babel緩存
cacheCompression: false, // 關(guān)閉緩存文件壓縮
plugins: ["@babel/plugin-transform-runtime"], // 減少代碼體積
}
}
]
}
]
}
}
Image Minimizer
壓縮項(xiàng)目本地圖片體積
安裝
npm i image-minimizer-webpack-plugin imagemin -D
- 安裝無損壓縮
npm install imagemin-gifsicle imagemin-jpegtran imagemin-optipng imagemin-svgo -D
- 安裝有損壓縮
npm install imagemin-gifsicle imagemin-mozjpeg imagemin-pngquant imagemin-svgo -D
- 配置
const ImageMinimizerPlugin = require("image-minimizer-webpack-plugin"); // 無損壓縮
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin({
parallel: threads // 開啟多進(jìn)程和進(jìn)程數(shù)量
}),
// 壓縮圖片
new ImageMinimizerPlugin({
minimizer: {
implementation: ImageMinimizerPlugin.imageminGenerate,
options: {
plugins: [
["gifsicle", { interlaced: true }],
["jpegtran", { progressive: true }],
["optipng", { optimizationLevel: 5 }],
[
"svgo",
{
plugins: [
"preset-default",
"prefixIds",
{
name: "sortAttrs",
params: {
xmlnsOrder: "alphabetical",
},
},
],
},
],
],
},
},
}),
]
},
}
優(yōu)化代碼運(yùn)行性能
Code Split
打包代碼時(shí)會(huì)將所有 js 文件打包到一個(gè)文件中邮丰,體積太大了。我們?nèi)绻灰秩臼醉撁蛻?yīng)該只加載首頁的 js 文件剪廉,其他文件不應(yīng)該加載。
所以我們需要將打包生成的文件進(jìn)行代碼分割炕檩,生成多個(gè) js 文件斗蒋,渲染哪個(gè)頁面就只加載某個(gè) js 文件,這樣加載的資源就少捧书,速度就更快吹泡。
-
代碼分割(Code Split)主要做了兩件事:
- 分割文件:將打包生成的文件進(jìn)行分割,生成多個(gè) js 文件经瓷。
- 按需加載:需要哪個(gè)文件就加載哪個(gè)文件爆哑。
需求: 多入口文件之間有公共代碼需要處理(多次引用的公共方法打包成一個(gè)單獨(dú)的 JS 文件)
- 步驟 1
module.exports = {
// 單入口
entry: './src/main.js',
// 多入口
// 寫幾個(gè)配置就會(huì)輸出多少js文件
entry: {
app: './src/app.js',
main: './src/main.js',
},
// ...
}
- 步驟 2
- 通過
optimization.splitChunks
實(shí)現(xiàn),它是一個(gè)對(duì)象舆吮,里面包含很多配置項(xiàng)揭朝。
optimization: {
// 代碼分割配置
splitChunks: {
chunks: "all", // 對(duì)所有模塊都進(jìn)行分割
// 以下是默認(rèn)值
// minSize: 20000, // 分割代碼最小的大小
// minRemainingSize: 0, // 類似于minSize,最后確保提取的文件大小不能為0
// minChunks: 1, // 至少被引用的次數(shù)色冀,滿足條件才會(huì)代碼分割
// maxAsyncRequests: 30, // 按需加載時(shí)并行加載的文件的最大數(shù)量
// maxInitialRequests: 30, // 入口js文件最大并行請(qǐng)求數(shù)量
// enforceSizeThreshold: 50000, // 超過50kb一定會(huì)單獨(dú)打包(此時(shí)會(huì)忽略minRemainingSize潭袱、maxAsyncRequests、maxInitialRequests)
// cacheGroups: { // 組锋恬,哪些模塊要打包到一個(gè)組
// defaultVendors: { // 組名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
// priority: -10, // 權(quán)重(越大越高)
// reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊屯换,則它將被重用,而不是生成新的模塊
// },
// default: { // 其他沒有寫的配置會(huì)使用上面的默認(rèn)值
// minChunks: 2, // 這里的minChunks權(quán)重更大
// priority: -20,
// reuseExistingChunk: true,
// },
// },
// 修改配置
cacheGroups: {
// 組与学,哪些模塊要打包到一個(gè)組
// defaultVendors: { // 組名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模塊
// priority: -10, // 權(quán)重(越大越高)
// reuseExistingChunk: true, // 如果當(dāng)前 chunk 包含已從主 bundle 中拆分出的模塊彤悔,則它將被重用,而不是生成新的模塊
// },
default: {
// 其他沒有寫的配置會(huì)使用上面的默認(rèn)值
minSize: 0, // 我們定義的文件體積太小了索守,所以要改打包的最小文件體積
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
},
- 步驟 3
- 按需加載晕窑,動(dòng)態(tài)導(dǎo)入(加載頁面時(shí)沒有被使用的 JS 不要引入)
- import 動(dòng)態(tài)導(dǎo)入,會(huì)將動(dòng)態(tài)導(dǎo)入的文件代碼分割(拆分成單獨(dú)模塊)卵佛,在需要使用的時(shí)候自動(dòng)加載
// 導(dǎo)入實(shí)現(xiàn)累加的方法
import('./add.js')
.then((res) => {
console.log('加載成功')
console.log(res.default(2,3))
})
.catch((err) => {
console.log('加載失敗')
})
需求: 單入口文件之間有公共代碼需要處理(多次引用的公共方法打包成一個(gè)單獨(dú)的 JS 文件)
- 步驟 1
- 配置 optimization.splitChunks
// 只需要配置這一個(gè)就可以(配置方法同上),其他都用默認(rèn)值
chunks: "all",
- 步驟 2
- 動(dòng)態(tài)導(dǎo)入語法(同上)
動(dòng)態(tài)導(dǎo)入文件更名
- 步驟 1
// 導(dǎo)入實(shí)現(xiàn)累加的方法
import(/* webpackChunkName:"add" */ "./add.js")
.then((res) => {
console.log('加載成功')
console.log(res.default(2,3))
})
.catch((err) => {
console.log('加載失敗')
})
- 步驟 2
- 在 webpack 的 output 中配置 filename
output: {
// ...
chunkFilename: 'static/js/[name].js'
}
統(tǒng)一命名配置
module.exports = {
output:{
// 步驟1
// 入口文件打包輸出文件名
filename:'static/js/[name].js',
// 非入口文件打包輸出文件名
chunkFilename:'static/js/[name].chunk.js',
// 圖片杨赤、字體等資源文件打包輸出文件名
assetModuleFilename:'static/media/[hash:10][ext][query]'
},
plugins:[
// ...
new MiniCssExtractPlugin({
filename:'static/css/[name].css',
chunkFilename:'static/css/[name].chunk.css'
})
]
}
Preload 和 Prefetch
-
初始 JS 加載完之后,在沒有更多資源需要從服務(wù)器獲取時(shí)敞斋,可以使用
Preload
或Prefetch
來加載更多的將要用到的資源-
Preload
:告訴瀏覽器立即加載資源。 -
Prefetch
:告訴瀏覽器在空閑時(shí)才開始加載資源疾牲。
-
-
共同點(diǎn)
- 它們都只會(huì)加載資源瑞妇,不會(huì)執(zhí)行家坎。
- 都有緩存。
-
它們區(qū)別:
-
Preload
加載優(yōu)先級(jí)高,Prefetch
加載優(yōu)先級(jí)低朱灿。 -
Preload
只能加載當(dāng)前頁面需要使用的資源曼月,Prefetch
可以加載當(dāng)前頁面資源四康,也可以加載下一個(gè)頁面需要使用的資源构舟。
-
-
總結(jié):
- 當(dāng)前頁面優(yōu)先級(jí)高的資源用
Preload
加載。 - 下一個(gè)頁面需要使用的資源用
Prefetch
加載架诞。
- 當(dāng)前頁面優(yōu)先級(jí)高的資源用
安裝
npm i @vue/preload-webpack-plugin -D
- 在 webpack 中配置
const PreloadWebpackPlugin = require("@vue/preload-webpack-plugin");
module.exports = {
plugins: [
new PreloadWebpackPlugin({
// 用preload
rel: "preload", // preload兼容性更好
as: "script",
// 用prefetch
// rel: 'prefetch' // prefetch兼容性更差
}),
],
}
需求
當(dāng)我們修改 math.js 文件再重新打包的時(shí)候拟淮,因?yàn)?contenthash 原因,math.js 文件 hash 值發(fā)生了變化(這是正常的)谴忧。
但是 main.js 文件的 hash 值也發(fā)生了變化很泊,這會(huì)導(dǎo)致 main.js 的緩存失效。明明我們只修改 math.js, 為什么 main.js 也會(huì)變身變化呢沾谓?
- 原因:
- 更新前:math.xxx.js, main.js 引用的 math.xxx.js
- 更新后:math.yyy.js, main.js 引用的 math.yyy.js, 文件名發(fā)生了變化委造,間接導(dǎo)致 main.js 也發(fā)生了變化
- 解決:
將 hash 值單獨(dú)保管在一個(gè) runtime 文件中。
我們最終輸出三個(gè)文件:main均驶、math昏兆、runtime。當(dāng) math 文件發(fā)送變化妇穴,變化的是 math 和 runtime 文件爬虱,main 不變。
runtime 文件只保存文件的 hash 值和它們與文件關(guān)系腾它,整個(gè)文件體積就比較小跑筝,所以變化重新請(qǐng)求的代價(jià)也小。
- 配置
module.exports = {
optimization: {
minimizer: [
// ...
],
splitChunks: {
name: (entrypoint) => `runtime~${entrypoint.name}.js`, // runtime文件命名規(guī)則
}
},
}
Core.js
core-js
是專門用來做 ES6 以及以上 API 的polyfill
瞒滴。polyfill
翻譯過來叫做墊片/補(bǔ)丁曲梗。就是用社區(qū)上提供的一段代碼,讓我們?cè)诓患嫒菽承┬绿匦缘臑g覽器上妓忍,使用該新特性稀并。安裝
npm i core-js
- 入口文件引入
// 手動(dòng)全部引入
import "core-js";
// 手動(dòng)按需引入(需要什么引入什么)
import "core-js/es/promise";
-
配置
- 在根目錄創(chuàng)建 babel.config.js
module.exports = { // 智能預(yù)設(shè):能夠編譯ES6語法 presets: [ [ "@babel/preset-env", // 按需加載core-js的polyfill { useBuiltIns: "usage", corejs: 3 }, ], ], };
PWA
需求: 開發(fā) Web App 項(xiàng)目,項(xiàng)目一旦處于網(wǎng)絡(luò)離線情況单默,就沒法訪問了。我們希望給項(xiàng)目提供離線體驗(yàn)忘瓦。
漸進(jìn)式網(wǎng)絡(luò)應(yīng)用程序(progressive web application - PWA):是一種可以提供類似于 native app(原生應(yīng)用程序) 體驗(yàn)的 Web App 的技術(shù)搁廓。
其中最重要的是引颈,在 離線(offline) 時(shí)應(yīng)用程序能夠繼續(xù)運(yùn)行功能。
內(nèi)部通過 Service Workers 技術(shù)實(shí)現(xiàn)的境蜕。
安裝
npm i workbox-webpack-plugin -D
- 在 webpack 中配置
const WorkboxPlugin = require("workbox-webpack-plugin");
module.exports = {
// ...
plugins: [
// ...
new WorkboxPlugin.GenerateSW({
// 這些選項(xiàng)幫助快速啟用 ServiceWorkers
// 不允許遺留任何“舊的” ServiceWorkers
clientsClaim: true,
skipWaiting: true,
}),
]
}
- 在入口文件中(一般是 main.js)
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/service-worker.js")
.then((registration) => {
console.log("SW registered: ", registration);
})
.catch((registrationError) => {
console.log("SW registration failed: ", registrationError);
});
});
}