ESM存在環(huán)境兼容問題
模塊文件過多
網(wǎng)絡(luò)請求頻繁
所有的前端資源都需要模塊化
綜上所述熙暴,模塊化是必要的
- 新特性代碼編譯
- 模塊化JavaScript打包
- 支持不同類型的資源模塊
模塊打包工具
Webpack
- 模塊打包器(Module bundler)解決模塊化JavaScript代碼打包的問題,可以將零散的模塊代碼統(tǒng)合到一個JS文件當(dāng)中
- 模塊加載器(Lodar)將環(huán)境兼容問題的代碼進(jìn)行編譯轉(zhuǎn)換
- 代碼拆分(Code Splitting)將應(yīng)用中所有的代碼按照需求打包乃摹,不用擔(dān)心代碼打包到一起峡懈,比如應(yīng)用加載過程中初次運行所必要的代碼打包到一塊肪康,在運行過程中,實現(xiàn)增量加載雾狈,不用擔(dān)心文件太大
- 資源模塊(Asset Module)支持在JavaScript中以模塊化的方式去載入任意類型的資源文件善榛,比如在webpack當(dāng)中移盆,通過JavaScript import一個CSS文件咒循,最終通過style標(biāo)簽的形式工作叙甸,其他文件類似如此
打包工具解決的是整個前端的模塊化熔萧,并非單指JavaScript
webpack初體驗
- 步驟1:
初始化項目
yarn init --yes
- 步驟2:
添加webpack依賴作為開發(fā)依賴
yarn add webpack webpack-cli --dev
- 步驟3:
檢驗webpack版本號
yarn webpack --version
- 步驟4:
使用webpack打包
yarn webpack
webpack會將文件打包為運行文件夾dist哪痰,并且將js代碼壓縮為main.js
- 如果覺得每次都用指令
yarn webpack
很麻煩的話,可以在package.json里用script注冊build指令替換掉
再次進(jìn)行打包就是
yarn build
webpack 配置文件
webpack 4以后的版本支持0配置的方式直接啟動打包肋演,整個打包過程會按照約定爹殊,將src/index.js作為入口,存入dist/main.js中
- 自定義打包配置
項目根目錄創(chuàng)建webpack.config.js的文件反症。這個文件是運行在node環(huán)境中的JS文件铅碍,需要按照commonJS的方法編寫代碼
const path = require('path')
module.exports = {
// 指定webpack打包入口文件的路徑 ./是不能省略的
entry: './src/main.js',
// 設(shè)置輸出文件的位置胞谈,要求是對象,通過對象的filename配紫,指定輸出名稱睹晒,
output: {
filename: 'bundle.js',
// 指定輸出文件所在的目錄伪很,path必須要是絕對路徑锉试,載入path模塊呆盖,獲得路徑
path: path.join(__dirname, 'output')
}
}
webpack工作模式
不同環(huán)境的幾組預(yù)設(shè)配置
默認(rèn)的工作模式的production
修改工作模式的指令就是在運行webpack打包時的指令加上mode应又,例如
yarn webpack --mode 工作模式
工作模式分為三種:
- production 生產(chǎn)模式,webpack會自動優(yōu)化打包結(jié)果洞就,這也是默認(rèn)的工作模式
- development 開發(fā)模式旬蟋,webpack會自動優(yōu)化打包的速度倾贰,添加一些調(diào)試過程中的輔助
- None模式,webpack就是運行最原始的打包架忌,不作任何的額外處理
差異可以在官方文檔找到:
也可以在配置文件里設(shè)置工作模式
-
在webpack.config.js文件里聲明mode屬性的屬性值饰恕,就無需配置指令的參數(shù)了
webpack打包結(jié)果運行原理
小知識:VScode快捷折疊代碼的快捷鍵是ctrl+k+ctrl+0
將所有的模塊放入一個文件埋嵌,并且構(gòu)造成為一個立即執(zhí)行函數(shù)范舀,可以通過打斷點的方式進(jìn)行一步步調(diào)試锭环,將各個模塊通過互相調(diào)用聯(lián)系起來
webpack 資源模塊加載
通過webpack引入前端項目中的任意文件
- webpack內(nèi)部默認(rèn)只處理JavaScript文件
- 要想讓webpack處理其他類型的文件例如css等等就需要新的loader
- CSS需要的新loader有:
- css-loader
- style-loader
yarn add style-loader --dev
yarm add css-style --dev
另外安裝了loader之后還需要在webpack.config.js文件里進(jìn)行設(shè)置
設(shè)置module下的rules
test:表示的是匹配打包過程中的文件路徑
use:匹配到的文件需要使用的loader,多個loader的話執(zhí)行順序是從后往前執(zhí)行
Loader是webpack的核心特性
通過不同的Loader可以實現(xiàn)加載任何類型的資源
webpack 導(dǎo)入資源模塊
打包入口=>運行入口
JavaScript驅(qū)動整個前端應(yīng)用的業(yè)務(wù)
例如:
因為是單獨的類名玫锋,所以還需要使用element.classList.add來添加標(biāo)簽的類名實現(xiàn)選擇器
- 邏輯合理,JS確實需要資源文件
- 保證上線資源不缺失悦屏,都是必要的
webpack 文件資源加載器
導(dǎo)入一個png資源
這個時候同樣是需要新的Loader墓贿,因為導(dǎo)入了webpack默認(rèn)不能識別的資源類型
yarn add file-loader --dev
同樣聋袋,需要在webpack配置文件設(shè)置
webpack會默認(rèn)的認(rèn)為打包的內(nèi)容會放在網(wǎng)站的根目錄下面幽勒,可能會造成路徑問題
更改問題:
通過配置文件告知webpack
publicPath: 'dist/'
publicPath是默認(rèn)空字符串的啥容,所以要記得修改
webpack Data URLs 與 url-loader
-
特殊的URL協(xié)議咪惠,當(dāng)前的url就可以直接表示文件內(nèi)容的方式
例子
圖片或者是字體這一類無法通過文本表示的二進(jìn)制文件姨拥,就可以通過base64編碼結(jié)果為字符串來標(biāo)示內(nèi)容
yarn add url-loader --dev
然后將rules下的圖片類改成url-loader
loader: 'url-loader',
url-load 適合小文件的使用,小文件使用Data URLs徽缚,可以減少請求次數(shù)凿试。大文件單獨提取存放那婉,使用file-loader,提高加載速度
- use作為類寞奸,loader指定url-loader隐岛,options的limit則是指定范圍大小內(nèi)的文件進(jìn)行url處理聚凹,之外的進(jìn)行file-loader處理妒牙,前提是必須要添加file-loader的依賴
use: {
loader: 'url-loader',
// 添加配置選項
options: {
// 只將10KB以下的文件進(jìn)行url-loader的處理单旁,以上的依然使用file-loader
limit: 10 * 1024 // 10 KB
}
}
webpack 常用加載器分類
- 編譯轉(zhuǎn)換類
加載到的資源模塊轉(zhuǎn)換為JavaScript代碼蔫饰,比如css-loader - 文件操作類
加載到的資源模塊拷貝到輸出目錄篓吁,導(dǎo)出訪問路徑杖剪,比如file-loader -
代碼檢查類
統(tǒng)一代碼風(fēng)格盛嘿,提高代碼質(zhì)量次兆,比如eslint-loader
webpack 處理ES2015
因為模塊打包需要,所以處理import园蝠,export彪薛,并不能處理ES6的其他特性
如果需要webpack打包過程中同時處理其他的ES6特性的轉(zhuǎn)換陪汽,需要為JS文件配置一個額外的編譯器loader挚冤。比如babel-loader
yarn add babel-loader @babel/core @babel/preset-env --dev
修改webpack.config.js文件
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
- webpack只是打包工具
- 加載器可以用來轉(zhuǎn)換編譯代碼
webpack 模塊加載方式
- 遵循ESM 標(biāo)準(zhǔn)的import聲明
- 遵循CommonJS標(biāo)準(zhǔn)的require函數(shù)
- 遵循AMD標(biāo)準(zhǔn)的define函數(shù)和require函數(shù)
不要混合使用,不方便統(tǒng)一標(biāo)準(zhǔn)的實施 - Loader加載的非JavaScript也會觸發(fā)資源加載
-
樣式代碼中的@import屬性和url函數(shù)
-
HTML代碼中圖片標(biāo)簽的src屬性
要使用html還得添加html-loader
html-loader只會處理img標(biāo)簽的src屬性,如果其他屬性也想要觸發(fā)打包的話肤京,添加attrs屬性的規(guī)則就行了
-
webpack核心工作原理
loader機(jī)制是webpack的核心
先找到一個.js文件作為入口忘分,就猶如樹狀一樣妒峦,每個支點找到對應(yīng)的資源文件肯骇,最后整合到一起寫入bundle.js文件
webpack Loader的工作原理
loader就是負(fù)責(zé)資源文件從輸入到輸出的轉(zhuǎn)換
對于同一個資源可以依次使用多個loader
比如:
css-loader->style-loader
webpack 插件機(jī)制
增強webpack自動化能力
Loader專注實現(xiàn)資源模塊加載
Plugin解決其他自動化工作
比如:清除dist目錄,拷貝靜態(tài)文件到輸出目錄漾脂,壓縮輸出代碼
webpack 自動清除輸出目錄插件
yarn add clean-webpack-plugin --dev
使用
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
plugins: [
new CleanWebpackPlugin()
]
webpack 自動生成HTML插件
通過webpack輸出HTML文件
插件:html-webpack-plugin
不需要解構(gòu):
const HtmlWebpackPlugin = require('html-webpack-plugin')
與上述自動清除目錄插件的導(dǎo)入與使用基本是一致的
生成模板符相,以供webpack生成html參照結(jié)構(gòu)
同時輸出多個頁面文件
以后如果要添加多個HTML文件就寫多個實例對象就可以了
webpack常用插件使用總結(jié)©-webpack-plugin
以下這個插件最好不要在開發(fā)階段使用,一般都是留在上線前的那一次打包中使用
- copy-webpack-plugin的作用就是將指定文件夾下面的文件拷貝到輸出目錄
用法與導(dǎo)入導(dǎo)出都與上述一致已卸,不需要贅述
之后在 官方說明多看看特別用法累澡,社區(qū)還提供了更多的插件
需求->關(guān)鍵詞->搜索
webpack 開發(fā)一個插件
相比于loader愧哟,plugin擁有更寬的能力范圍
plugin通過鉤子機(jī)制實現(xiàn)
class MyPlugin {
apply (compiler) {
console.log('MyPlugin 啟動')
compiler.hooks.emit.tap('MyPlugin', compilation => {
// compilation => 可以理解為此次打包的上下文
for (const name in compilation.assets) {
// console.log(name)
// console.log(compilation.assets[name].source())
if (name.endsWith('.js')) {
const contents = compilation.assets[name].source()
const withoutComments = contents.replace(/\/\*\*+\*\//g, '')
compilation.assets[name] = {
source: () => withoutComments,
size: () => withoutComments.length
}
}
}
})
}
}
插件通過在生命周期的鉤子中掛載函數(shù)實現(xiàn)拓展
webpack 開發(fā)體驗的設(shè)想
理想的開發(fā)環(huán)境
- 以HTTP server 運行
- 自動編譯+自動刷新
- 提供Source Map支持
實現(xiàn)自動編譯
監(jiān)聽文件變化,自動重新打包
啟動命令后面加個watch參數(shù)肥矢,啟動監(jiān)聽模式
yarn webpack --watch
自動刷新瀏覽器
browserSync工具甘改,以前有過介紹
browser-sync dist --files "**/*"
弊端:
操作麻煩楼誓,要開兩個終端主守,效率上降低了
webpack Dev Server
集成了自動編譯和自動刷新瀏覽器等功能
yarn add webpack-dev-server --dev
運行
yarn webpack-dev-server
打包結(jié)果不會存放在磁盤上参淫,而是存放在內(nèi)存當(dāng)中涎才,所以不會有dist文件夾耍铜,可以減少磁盤讀寫操作棕兼,大大提高效率
自動喚醒瀏覽器
yarn webpack-dev-server --open
webpack Dev Server靜態(tài)資源訪問
Dev Server默認(rèn)只會serve打包輸出文件
只要是webpack輸出的文件伴挚,都可被直接訪問到
靜態(tài)資源文件也需要serve
devServer: {
// 指定額外的靜態(tài)資源路徑,可以為字符串或者數(shù)組蜈出,也就是一個或者多個
contentBase: './public',
}
webpack Dev Server 代理API
并不是任何情況下API都應(yīng)該支持CORS同源策略
如果是同源部署皱蹦,根本沒必要開啟CORS
出現(xiàn)問題:開發(fā)階段接口跨域問題
解決問題:配置代理沪哺,把接口服務(wù)代理到本地的開發(fā)地址
webpack Dev Server支持配置代理
目標(biāo):將Github的API代理到本地開發(fā)服務(wù)器
在devServer當(dāng)中添加一個proxy屬性辜妓,這個屬性就是添加代理服務(wù)配置的
devServer: {
proxy: {
// 請求路徑前綴
'/api': {
// http://localhost:8080/api/users -> https://api.github.com/api/users
// 代理目標(biāo)
target: 'https://api.github.com',
// http://localhost:8080/api/users -> https://api.github.com/users
// 實現(xiàn)代理路徑的重寫
pathRewrite: {
// 替換為空,^為開頭
'^/api': ''
},
// 不能使用 localhost:8080 作為請求 GitHub 的主機(jī)名
// 默認(rèn)使用的就是用戶的localhost:8080
// changeOrigin:true就會以實際代理的主機(jī)名去請求酪夷,就是api.github.com
changeOrigin: true
}
}
},
Source Map
運行代碼和源代碼之間完全不同,如果需要調(diào)試應(yīng)用坦报,錯誤信息沒法定位片择,調(diào)試或者報錯都是基于運行代碼字管,Source Map就是解決這類問題的辦法(源代碼地圖)
用于映射源代碼和轉(zhuǎn)換代碼之間的關(guān)系
version屬性:記錄Source Map版本號
sources屬性:轉(zhuǎn)換之前源文件的名稱嘲叔,可能是多個文件借跪,所以是數(shù)組
name屬性:源代碼成員名稱
mapping屬性:轉(zhuǎn)換之后的代碼的字符與轉(zhuǎn)換之前對應(yīng)的映射關(guān)系
最新版jQuery已經(jīng)去除了引入source map的注釋
source map 解決了源代碼和運行代碼不一致所產(chǎn)生的問題
webpack 配置 Source Map
在webpack配置文件里有一個屬性叫做devtool
卵牍,配置開發(fā)過程中的輔助工具
webpack 支持12種不同的方式
每種方式的效率和效果不同
eval模式下的Source Map
這種模式下不會生成source-map文件涡驮,只能定位源代碼名稱捉捅,不知道行列信息
不同devtool之間的差異
所有的不同模式下的devtool測試:
const HtmlWebpackPlugin = require('html-webpack-plugin')
const allModes = [
'eval',
'cheap-eval-source-map',
'cheap-module-eval-source-map',
'eval-source-map',
'cheap-source-map',
'cheap-module-source-map',
'inline-cheap-source-map',
'inline-cheap-module-source-map',
'source-map',
'inline-source-map',
'hidden-source-map',
'nosources-source-map'
]
module.exports = allModes.map(item => {
return {
devtool: item,
mode: 'none',
entry: './src/main.js',
output: {
filename: `js/${item}.js`
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: `${item}.html`
})
]
}
})
// module.exports = [
// {
// entry: './src/main.js',
// output: {
// filename: 'a.js'
// }
// },
// {
// entry: './src/main.js',
// output: {
// filename: 'b.js'
// }
// }
// ]
運行之后可以慢慢觀察各個模式的差距
- eval:是否使用eval執(zhí)行模塊代碼
- cheap:Source Map是否包含行信息
- module:是否能夠得到Loader處理之前的源代碼
- inline:使用dataURL的方式嵌入到url當(dāng)中(最少用到的)
- hidden:看不到source-map的效果即碗,但是確實生成了map文件剥懒,跟jquery是一樣的初橘,代碼中并沒有引入保檐,開發(fā)第三方包比較有用
- nosources:能看到錯誤出現(xiàn)的位置夜只,但是點擊錯誤信息扔亥,看不到源代碼的旅挤,可以找到錯誤,確保源代碼不會被暴露的情況
webpack選擇合適的 Source Map模式
來自師傅的個人開發(fā)經(jīng)驗之談:
選擇cheap-module-eval-source-map
- 代碼每行不超過80個字符(定位到行就可以了)
- 經(jīng)過Loader轉(zhuǎn)換過后的差異較大秕脓,頻繁使用框架(需要查閱轉(zhuǎn)換之前的代碼)
- 首次打包速度比較慢芙贫,但是重寫打包相對較快
生產(chǎn)環(huán)境下
選擇None
- Source Map會暴露源代碼
- 調(diào)試是開發(fā)階段的事情屹培,在開發(fā)階段盡可能找到所有的bug
再不濟(jì)也要選擇nosources-source-map - 不要暴露源代碼的內(nèi)容
沒有選擇的差異,理解不同模式的差異蓄诽,適配不同的環(huán)境
webpack 自動刷新的問題
比如我測試一個文本輸入頁面仑氛,一旦有變化锯岖,文本會丟失出吹,又要重新輸入
頁面不刷新的前提下捶牢,模塊也可以及時更新
webpack HMR
HMR又名模塊熱替換(熱更新)
應(yīng)用程序運行過程中實時替換掉某個模塊秋麸,運行狀態(tài)不會改變灸蟆,以解決自動刷新導(dǎo)致頁面內(nèi)容丟失的問題炒考。
熱替換只是將修改的模塊實時替換到應(yīng)用中
HMR是webpack中最強大的功能之一
已經(jīng)集成到了webpack-dev-server中,不必要專門添加什么依賴
命令:
webpack-dev-server --hot
相對應(yīng)的也有可以在配置文件中添加相應(yīng)的配置打開HMR
devServer: {
hot: true
},
然后載入webpack模塊
const webpack = require('webpack')
再在plugins里寫入實例
new webpack.HotModuleReplacementPlugin()
HMR還需要額外的操作才能正常工作
webpack中的HMR需要手動處理模塊熱替換邏輯
樣式文件熱更新開箱即用的原理:
經(jīng)過loader處理了,style-loader中已經(jīng)自動處理了熱更新
在框架下的開發(fā)测柠,每種文件都是有規(guī)律的谒主。所以JS就可以自動熱更新霎肯,通過腳手架創(chuàng)建的項目內(nèi)部都集成了HMR方案
HMR APIs
// ============ 以下用于處理 HMR,與業(yè)務(wù)代碼無關(guān) ============
// console.log(createEditor)
if (module.hot) {
let lastEditor = editor
module.hot.accept('./editor', () => {
// console.log('editor 模塊更新了搂捧,需要這里手動處理熱替換邏輯')
// console.log(createEditor)
const value = lastEditor.innerHTML
document.body.removeChild(lastEditor)
const newEditor = createEditor()
newEditor.innerHTML = value
document.body.appendChild(newEditor)
lastEditor = newEditor
})
module.hot.accept('./better.png', () => {
img.src = background
console.log(background)
})
}
HMR注意事項
- 處理HMR的代碼報錯會導(dǎo)致自動刷新
解決方法:
hotOnly: true // 只使用 HMR允跑,不會 fallback 到 live reloading
- 沒啟用HMR的情況下聋丝,HMR API報錯
缺失:
new webpack.HotModuleReplacementPlugin()
解決:
添加控制條件
if(module.hot)
- 代碼中多了一些與業(yè)務(wù)無關(guān)的代碼
移除了熱更新的實例與導(dǎo)入代碼弱睦,業(yè)務(wù)模塊的相關(guān)代碼會自動移除
webpack 生產(chǎn)環(huán)境優(yōu)化
生產(chǎn)環(huán)境和開發(fā)環(huán)境有很大的差異
生產(chǎn)環(huán)境注重運行效率
開發(fā)環(huán)境注重開發(fā)效率
webpack 提供模式(mode) 為不同的工作環(huán)境創(chuàng)建不同的配置
webpack不同環(huán)境下的配置
- 配置文件根據(jù)環(huán)境不同導(dǎo)出不同配置
(中小型項目) - 一個環(huán)境對應(yīng)一個配置文件
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = (env, argv) => {
const config = {
mode: 'development',
entry: './src/main.js',
output: {
filename: 'js/bundle.js'
},
devtool: 'cheap-eval-module-source-map',
devServer: {
hot: true,
contentBase: 'public'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: 'file-loader',
options: {
outputPath: 'img',
name: '[name].[ext]'
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack Tutorial',
template: './src/index.html'
}),
new webpack.HotModuleReplacementPlugin()
]
}
// 判斷什么模式
if (env === 'production') {
config.mode = 'production'
config.devtool = false
config.plugins = [
...config.plugins,
new CleanWebpackPlugin(),
new CopyWebpackPlugin(['public'])
]
}
return config
}
-
不同環(huán)境的配置文件
公共端圈,開發(fā)環(huán)境,生產(chǎn)環(huán)境
prod
dev
common.js:
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
filename: 'js/bundle.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: 'file-loader',
options: {
outputPath: 'img',
name: '[name].[ext]'
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack Tutorial',
template: './src/index.html'
})
]
}
使用什么模式,就用這條指令:
yarn webpack --config 哪一個文件
webpack DefinePlugin
為代碼注入全局成員
這是webpack內(nèi)置的插件
plugins: [
new webpack.DefinePlugin({
// 值要求的是一個代碼片段
API_BASE_URL: JSON.stringify('https://api.example.com')
})
]
webpack Tree-shaking
- [搖掉]代碼中沒有引用的部分张症,未引用代碼(dead-code)
- Tree-shaking會在生產(chǎn)模式production下自動開啟
- Tree-shaking不是某一個配置選項
- 非生產(chǎn)模式下的配置:
// 集中配置webpack內(nèi)部的優(yōu)化功能
optimization: {
// 模塊只導(dǎo)出被使用的成員
usedExports: true,
// 盡可能合并每一個模塊到一個函數(shù)中
concatenateModules: true,
// 壓縮輸出結(jié)果
minimize: true
}
webpack Tree-shaking 與 babel
- Tree Shaking的前提是ESM
- 由webpack打包的代碼必須使用ESM
options: {
presets: [
// 如果 Babel 加載模塊時已經(jīng)轉(zhuǎn)換了 ESM俗他,則會導(dǎo)致 Tree Shaking 失效
// ['@babel/preset-env', { modules: 'commonjs' }]
// ['@babel/preset-env', { modules: false }]
// 也可以使用默認(rèn)配置兆衅,也就是 auto羡亩,這樣 babel-loader 會自動關(guān)閉 ESM 轉(zhuǎn)換
['@babel/preset-env', { modules: 'auto' }]
]
}
Babel并不會讓Tree-shaking失效
webpack sideEffcts(副作用)
副作用:模塊執(zhí)行時除了導(dǎo)出成員之外所作的事情
一般用于npm包標(biāo)記是否有副作用
optimization: {
sideEffects: true,
}
確保你的代碼真的沒有副作用畏铆,否則會誤刪
-
樣式文件屬于副作用模塊
extend是寫的一個有副作用的模塊辞居,這樣設(shè)置不會誤刪
Code Splitting(代碼分割)
所有的代碼都會被打包到一起瓦灶,bundle體積過大
并不是每一個模塊在啟動的時候都是必要的
分包倚搬,按需加載
-
多入口打包(多頁面應(yīng)用程序)
一個頁面去對應(yīng)一個打包入口
公共部分單獨提取
提取公共模塊
- ESM動態(tài)導(dǎo)入
按需加載:需要用到某個模塊時捅僵,再加載這個模塊
動態(tài)導(dǎo)入的模塊會被自動分包(更為靈活)
魔法注釋
靈活組織動態(tài)加載的模塊輸出的文件
MinCssExtraCtPlugin
提取CSS到單個文件
yarn add mini-css-extract-plugin --dev
在webpack配置文件中導(dǎo)入,再通過實例引用
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
new MiniCssExtractPlugin()
會將樣式的CSS代碼單獨提取到一個文件中馒闷,再引用纳账,也就是說不需要style-loader了捺疼,取而代之的是
MiniCssExtractPlugin.loader
如果css文件體積大于150kb了啤呼,就考慮提取到單獨文件當(dāng)中
OptimizeCssAssetsWebpackPlugin
壓縮輸出的CSS文件
webpack內(nèi)置的壓縮插件只針對JS的壓縮官扣,CSS沒有壓縮,需要額外的插件
yarn add optimize-css-assets-webpack-plugin --dev
運行原理照舊蚯涮,有一點需要注意:配置在optimization的minimizer屬性當(dāng)中
但是有一個缺點,如果配置了minimizer,編輯器就會自動認(rèn)為要使用配置的壓縮規(guī)則挟炬,那么JS就不會被壓縮了
輸出文件名Hash
生產(chǎn)模式下橘券,文件名使用Hash值
一旦資源發(fā)生改變卿吐,文件名也會發(fā)生改變嗡官,對于客戶端來說全新的文件名就是全新的請求衍腥,就沒有緩存的問題,不用擔(dān)心文件更新之后的問題
webpack中的filename屬性和絕大多數(shù)插件的filename屬性都支持通過占位符的方式為文件名設(shè)置Hash
- [name]-[hash]:項目級別竹捉,有任何一個地方發(fā)生變化块差,hash值就全部發(fā)生變化了
- [name]-[chunkhash]:同一路的打包憾儒,chunkhash都是同樣的hash,在同一路下的任意文件作出改動起趾,其他的同一路文件都會發(fā)生變化
-
[name]-[contenthash]:文件級別的hash
(解決緩存問題最好的方式)
可以通過:number的方式來指定hash長度
八位hash是解決緩存最好的選擇