為什么選擇 webpack
- 社區(qū)生態(tài)豐富
- 配置靈活和插件化擴(kuò)展
- 官方更新迭代速度快
配置文件名稱(chēng)
- webpack 默認(rèn)配置文件 webpack.config.js
- 也可以通過(guò) webpack --config 執(zhí)行配置文件
webpack 配置組成
module.exports = {
entry: ----> 打包文件的入口
output: -----> 打包的輸出
mode: 'production' ----> 環(huán)境
module: {
rules: [
{ test: /\.txt$/ } -----> Loader 配置
]
},
plugins: [ -------> 插件配置
new HtmlwebpackPlugin({
template: ''
})
]
}
使用 webpack 打包文件
- 使用 webpack 小案例
準(zhǔn)備文件及安裝webapck
- 打開(kāi)終端 常見(jiàn)文件 及 初始化項(xiàng)目 (注意要先安裝 node)
mkdir my-webpack
cd my-webpack
npm init -y
- 安裝 webpack 及 webpack-cli
npm install webpack webpack-cli --save-dev
- 新建webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'main.js'
},
mode: 'production'
}
- 創(chuàng)建src 下的 index.js 文件箍土,簡(jiǎn)單寫(xiě)一寫(xiě)邏輯代碼
- 然后在項(xiàng)目目錄下的終端執(zhí)行
./node_modules/.bin/webpack
- 然后會(huì)在 dist 文件夾中找到打包后的 main.js 文件
- 使用 npm 命令 替代 ./node_modules/.bin/webpack 打包
- 在 package.json 中的 scripts 添加 build 命令
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
- 執(zhí)行 npm run build 一樣可以打包
entry 和 output
單入口
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'build.js'
}
多入口
entry: {
app: './src/index.js'
app2: './src/main.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].js'
},
Loaders
- 本身就是一個(gè)函數(shù),接收源文件作為參數(shù)附帽,返回轉(zhuǎn)換的結(jié)果
常用的 Loaders
- babel-loader
- css-loader
- less-loader
- ts-loader
- file-loader
Plugins
- 插件用于 bundle 文件的優(yōu)化乾吻,資源管理和環(huán)境變量注入
- 作用于整個(gè)構(gòu)建構(gòu)成
常見(jiàn)的 Plugins
- CleanWbpackPlugin 清理構(gòu)建目錄
- CommonsChunkPlugin 講chunks相同的模塊代碼提取成公共 js
- HtmlWebpackPlugin 創(chuàng)建 HTML 文件去承載輸出的 bundle
- UglifyjsWebpackPlugin 壓縮JS
Mode
- 用來(lái)指定當(dāng)前的構(gòu)建環(huán)境是 production development 還是 none
- 設(shè)置 mode 可以使用 webpack 內(nèi)置函數(shù)枪萄,默認(rèn)值是 production
module.exports = {
mode: 'development'
};
- 或者從 cli 參數(shù)中傳遞
webpack --mode=development
內(nèi)置函數(shù)功能
- 選項(xiàng) development
會(huì)將 DefinePlugin 中 process.env.NODE_ENV 的值設(shè)置為 development. 為模塊和 chunk 啟用有效的名农尖。
- production
會(huì)將 DefinePlugin 中 process.env.NODE_ENV 的值設(shè)置為 production。為模塊和 chunk 啟用確定性的混淆名稱(chēng)扔役,F(xiàn)lagDependencyUsagePlugin肄鸽,F(xiàn)lagIncludedChunksPlugin卫病,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 典徘。
- node
不使用任何默認(rèn)優(yōu)化選項(xiàng)
使用 babel 解析 ES6
- 安裝 babel 解析文件
npm i @babel/core @babel/preset-env babel-loader -D
- 創(chuàng)建 .babelrc 文件 并添加:
{
"presets": [
"@babel/press-env"
]
}
- webpack.config.js 中添加 rules
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
}
]
}
解析 CSS 文件
- 安裝 style-loader 和 css-loader
- 修改 webpack.config.js 文件
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
}
loader 的執(zhí)行順序是 從又右到左的
url-loader 解析圖片
- 安裝 url-loader 和 file-loader
module: {
rules: [
{
test: /.js$/,
use: 'babel-loader'
},
{
test: /.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: 'url-loader',
options: { // 圖片大小的限制 如果小于 10k 轉(zhuǎn)成 base64 格式
limit: 10240
}
}
]
}
]
}
webpack 文件監(jiān)聽(tīng)
- 啟動(dòng) webpack 命令時(shí)蟀苛,帶上 --watch 參數(shù)
- 缺點(diǎn)是: 每次需要手動(dòng)刷新瀏覽器
- 在配置 webpack.config.js 中設(shè)置 watch: true
- 文件監(jiān)聽(tīng)的原理分析
- 輪詢(xún)判斷文件的最后編譯事件是否變化
- 某個(gè)文件發(fā)生了變化,并不會(huì)立即監(jiān)聽(tīng)者逮诲,而是先緩存起來(lái)帜平,等 aggregateTimeout
watch: true,
watchOptions: {
// 默認(rèn)為空,不監(jiān)聽(tīng)文件或文件件梅鹦,支持正則
ignored: /node_modules/,
// 監(jiān)聽(tīng)發(fā)生變化后等待 xxx 毫秒去執(zhí)行裆甩,默認(rèn) 300
aggregateTimeout: 300,
// 判斷文件是否發(fā)生變化,通過(guò)不停的詢(xún)問(wèn)系統(tǒng)指定文件有沒(méi)有變化實(shí)現(xiàn)齐唆,默認(rèn)每秒問(wèn) 1000 次
poll: 1
}
熱更新 webpack-dev-server
- 特點(diǎn): 不刷新瀏覽器嗤栓,不輸出文件,而是放在內(nèi)存中
- webpack-dev-server --open
熱更新 使用 webpack-dev-middleware
- 通過(guò) node express/koa 創(chuàng)建一個(gè) server 編寫(xiě)相關(guān)邏輯
- 將 webpack 輸出文件傳輸給服務(wù)器
- 適用于靈活的定制場(chǎng)景
熱更新的原理分析
- Webpack Compile
- 將 JS 編譯成 Bundle (打包好輸出的文件)
- HMR (Hot Module Replacement) Server:
- 將熱更新文件傳輸給 HMR Rumtime
- Bundle Server:
- 提供文件在瀏覽器的訪問(wèn) (通過(guò)服務(wù)器的方式訪問(wèn),例如 127.0.0.1:8080)
- HMR Rumtime:
- 打包時(shí)會(huì)被注入到瀏覽器中茉帅,使瀏覽器和服務(wù)器建立連接叨叙,通常的連接方式是用 websocket, 用來(lái)更新文件的變化
- bundle.js
- 構(gòu)建輸出的文件
熱更新的過(guò)程
- 熱更新的啟動(dòng)階段
- 代碼通過(guò) Webpack Compile 進(jìn)行編譯打包,然后將編譯好的文件傳輸給 Bundle Server (服務(wù)器)堪澎,讓文件以 server 的方式被 瀏覽器 訪問(wèn)到擂错。
- 更新階段
- 代碼通過(guò) Webpack Compile 進(jìn)行編譯打包,將代碼發(fā)送給 HMR Server 知道哪些 js 文件發(fā)生變動(dòng)樱蛤,然后通知 HMR Rumtime (HMR Server 在 服務(wù)端钮呀,HMR Rumtime 在客戶(hù)端)哪些文件發(fā)生變化,通常是已JSON 的方式傳輸昨凡,然后 HMR Rumtime 更新代碼.
文件指紋
- 打包后輸出的文件名的后綴
Hash
- 和整個(gè)項(xiàng)目的構(gòu)建相關(guān), 只要項(xiàng)目文件有修改爽醋,整個(gè)項(xiàng)目構(gòu)建的 hash 值就會(huì)更改
Chunkhash
- 和 webpack 打包的 chunk 有關(guān),不同的 entry 會(huì)生成不同的 chunkhash 值
Contenthash
- 根據(jù)文件內(nèi)容來(lái)定義 hash土匀,文件內(nèi)容不變子房,則 Contenthash 不變
module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: '[name][chunkhash:8].js'
},
module: {
rules: [
{
test: /\.(png|svg|jpg)$/,
use: [
{
loader: 'file-loader',
options: {
name: 'img/[name][hash:8].[ext]'
}
}
]
},
{
test: /.css$/,
use: [
// 'style-loader', 這個(gè)是把 css 放到 style 里面和用 MiniCssExtractPlugin 有沖突,它是把 css 放到一個(gè)獨(dú)立的文件中
MiniCssExtractPlugin.loader,
'css-loader'
]
},
]
}
mode: 'production',
plugins: [
new MiniCssExtractPlugin({
filename: '[name][contenthash:8].css'
})
]
}
:8 意思是只取前 8 位
- 圖片文件指紋設(shè)置可選參數(shù)
- [ext] : 資源后綴名
- [name] : 文件名稱(chēng)
- [path] : 文件相對(duì)路徑
- [folder] : 文件所在的文件夾
- [contenthash]: 文件內(nèi)容的 hash 默認(rèn) MD5 生成
- [hash] : 文件內(nèi)容的 hash 默認(rèn) MD5 生成
- [emoji] : 一個(gè)隨機(jī)的指定文件內(nèi)容的 emoji
代碼壓縮
JS 文件的壓縮
- uglifyjs-webpack-plugin webpack4.0 后內(nèi)置了
css 壓縮
- 安裝
- npm i optimize-css-assets-webpack-plugin -D
- npm i cssnano -D
- 代碼
new OpeimizeCssAssetsPlugin({
assetNameEegExp: /\.css$/g,
cssProcessor: require('cssnano')
}),
html 壓縮
- 安裝
npm i html-webpack-plugin -D
- 代碼
new HtmlWebpackPlugin({
// 模板 所在的位置
template: path.join(__dirname, 'src/index.html'),
// 指定打包后的文件名稱(chēng)
filename: 'index.html',
// 聲明 HTML 使用什么 chunks
chunks: ['index'],
// 把引入的 js 或 css 自動(dòng)注入
inject: true,
minify: {
html5: true,
collapseWhitespace: true,
preserveLineBreaks: false,
minifyCSS: true,
minifyJS: true,
removeComments: false
}
})