作為前端開發者,相信大家或多或少都接觸過webpack
,現如今webpack
已經滲透在了前端的各個方面,所以我們有必要來了解並學習webpack
,webpack
是一種用於構建 JavaScript 應用程式的靜態模組打包器,它能夠以一種相對一致且開放的處理方式,載入應用中的所有資原始檔(圖片、CSS、視訊、字型檔案等),並將其合併打包成瀏覽器相容的 Web 資原始檔。webpack
相比其它構建工具功能更加強大,可延伸性也更強,它能夠融合多種工程化工具,將開發階段的應用程式碼編譯、打包成適合網路分發、使用者端執行的應用產物。
webpack的構建入口,入口起點(entry point) 指示 webpack 應該使用哪個模組,來作為構建其內部 依賴圖(dependency graph) 的開始。進入入口起點後,webpack 會找出有哪些模組和庫是入口起點(直接和間接)依賴的。
// 單入口
module.exports = {
entry: './src/main.js'
}
// 多入口
module.exports = {
entry: {
a: './src/a.js',
b: './src/b.js'
}
}
output 屬性告訴 webpack 在哪裡輸出它所建立的 bundle,以及如何命名這些檔案。主要輸出檔案的預設值是
./dist/main.js
,其他生成檔案預設放置在./dist
資料夾中。
// 單入口
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
}
}
// 多入口
module.exports = {
entry: {
a: './src/a.js',
b: './src/b.js'
},
output: {
filename: '[name].[hash:6].js', // 通過預留位置確保檔名唯一,考慮快取問題,還可以為檔名加上hash
path: __dirname + '/dist',
publicPath: '/', // 生產環境一般是CDN地址,開發環境設定為/或不設定
}
}
webpack 只能理解 JavaScript 和 JSON 檔案,這是 webpack 開箱可用的自帶能力。loader 讓 webpack 能夠去處理其他型別的檔案,並將它們轉換為有效 模組,以供應用程式使用,以及被新增到依賴圖中。
比如:設定webpack為css檔案應用css-loader
module.exports = {
module: {
rules: [
{test: /.css$/, use: 'css-loader'}
]
}
}
module.rules
允許你在 webpack 設定中指定多個 loader。 這種方式是展示 loader 的一種簡明方式,並且有助於使程式碼變得簡潔和易於維護。
外掛 是 webpack 的 支柱 功能。Webpack 自身也是構建於你在 webpack 設定中用到的 相同的外掛系統 之上!
比如:為編譯過程新增進度報告外掛
const Webpack = require('webpack')
module.exports = {
plugins: [new Webpack.ProgressPlugin()]
}
用於設定模組路徑解析規則,可用於幫助 Webpack 更精確、高效地找到指定模組
比如設定別名:
建立 import
或 require
的別名,來確保模組引入變得更簡單。例如,一些位於 src/
資料夾下的常用模組:
module.exports = {
resolve: {
alias: {
node_modules: path.resolve(__dirname, './node_modules'),
'@': path.resolve(__dirname, './src'),
api: path.resolve(__dirname, './src/api'),
components: path.join(__dirname, './src/components'),
}
}
}
這些選項決定了如何處理專案中的不同型別的模組。
比如我們常見的loader就是在module.rules
內設定的。
module.exports = {
module: {
rules: [
{test: /.css$/, use: 'css-loader'}
]
}
}
用於宣告外部資源,Webpack 會直接忽略這部分資源,跳過這些資源的解析、打包操作
比如防止將某些 import
的包(package)打包到 bundle 中,而是在執行時(runtime)再去從外部獲取這些擴充套件依賴(external dependencies) 。
比如:從CDN引入Vue
<!-- index.html -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.3/vue.min.js"></script>
// webpack.config.js
module.exports = {
externals: {
vue: 'vue'
}
}
用於控制如何優化產物包體積,內建 Dead Code Elimination、Scope Hoisting、程式碼混淆、程式碼壓縮等功能
從 webpack 4 開始,會根據你選擇的
mode
來執行不同的優化, 不過所有的優化還是可以手動設定和重寫。
module.exports = {
//...
optimization: {
chunkIds: 'named',
},
};
用於設定編譯產物的目標執行環境,支援 web、node、electron 等值,不同值最終產物會有所差異
比如:target設定為node,webpack將在node環境下進行編譯
module.exports = {
target: 'node'
}
提供
mode
設定選項,告知 webpack 使用相應模式的內建優化。
string = 'production': 'none' | 'development' | 'production'
module.exports = {
mode: 'development',
};
或者從cli--mode
引數進行傳遞
webpack --mode development
啟用 Watch 模式。這意味著在初始構建之後,webpack 將繼續監聽任何已解析檔案的更改。
module.exports = {
watch: true
}
⚠️注意:webpack-dev-server
和webpack-dev-middleware
預設是開啟watch模式的
此選項控制是否生成,以及如何生成 source map。
string = 'eval' | false
選擇一種 source map 風格來增強偵錯過程。不同的值會明顯影響到構建(build)和重新構建(rebuild)的速度。
用於設定與 HMR 強相關的開發伺服器功能
通過 webpack-dev-server 的這些設定,能夠以多種方式改變其行為,這裡比較常見的設定有:port
、host
、proxy
等
module.exports = {
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
}
}
Webpack 5 之後,該項用於控制如何快取編譯過程資訊與編譯結果
快取生成的 webpack 模組和 chunk,來改善構建速度。cache
會在開發
模式被設定成 type: 'memory'
而且在 生產
模式 中被禁用。 cache: true
與 cache: { type: 'memory' }
設定作用一致。 傳入 false
會禁用快取:
module.exports = {
cache: false
}
瞭解完上面這些webpack核心概念,我們可以嘗試來手動設定好一個Vue開發環境
首先npm init -y
初始化package.json
檔案
接著安裝好我們的webpack
、webpack-cli
npm i webpack webpack-cli -D
⚠️注意: 我這裡的webpack是5版本的
"webpack": "^5.85.1",
"webpack-cli": "^4.7.2",
原生 Webpack 並不能處理這種內容格式的檔案,為此我們需要引入專用於 Vue SFC 的載入器:vue-loader
npm i vue-loader
// webpack.config.js
const Webpack = require('webpack')
const {VueLoaderPlugin} = require('vue-loader')
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.[hash:6].js',
path: __dirname + '/dist',
},
module: {
rules:[
{test: /.vue$/, use: 'vue-loader'},
]
},
plugins:[
new Webpack.ProgressPlugin(),
new VueLoaderPlugin(),
],
}
提示:vue-loader
庫同時提供用於處理 SFC 程式碼轉譯的 Loader 元件,與用於處理上下文相容性的 Plugin 元件,兩者需要同時設定才能正常執行。
此時我們的檔案結構是這樣的,大致與Vue專案結構一致
嘗試啟動看一下:
// package.json
"dev": "webpack --mode development",
npm run dev
由於我們的vue檔案中有css內容,而webpack預設是不理解css內容的,所以導致報錯了
這裡需要安裝style-loader
、css-loader
來進行處理。
修改webpack設定
// webpack.config.js
const Webpack = require('webpack')
const {VueLoaderPlugin} = require('vue-loader')
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.[hash:6].js',
path: __dirname + '/dist',
},
module: {
rules:[
{test: /.vue$/, use: 'vue-loader'},
{
test: /.css$/,
use: ['style-loader', 'css-loader']
}
]
},
plugins:[
new Webpack.ProgressPlugin(),
new VueLoaderPlugin(),
],
}
此時再跑起來,發現沒有報錯了。
我們平時在開發中肯定會用到ES6
語法,這裡我們也需要設定對應的loader
來進行處理
安裝babel-loader
npm i babel-loader @babel/preset-env @babel/core
設定
module.exports = {
module: {
rules: [
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules/
}
]
}
}
當然這裡的options設定你也可以在.babelrc
或babel.config.js
中單獨設定。
與CSS一樣,webpack也是預設不理解圖片的,所以這裡也需要設定loader進行處理。
webpack4
在webpack4中,我們常用的處理圖片的loader有:file-loader
、url-loader
file-loader
將檔案傳送到輸出目錄// webpack.config.js
module.exports = {
// ...
module: {
rules: [{
test: /.(png|jpg|gif|jpeg)$/,
use: ['file-loader']
}],
},
};
經過 file-loader
處理後,原始圖片會被重新命名並複製到產物資料夾,同時在程式碼中插入圖片 URL 地址
url-loader
將檔案作為 data URI 內聯到 bundle 中,它有兩種表現,對於小於閾值 limit
的影象直接轉化為 base64 編碼;大於閾值的影象則呼叫 file-loader
進行載入module.exports = {
// ...
module: {
rules: [{
test: /.(png|jpg|gif|jpeg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 1024
}
}]
}],
},
};
經過 url-loader
處理後,小於 limit
引數即 1024B 的圖片會被轉譯為 Base64 編碼,對於超過 limit
值的圖片則直接呼叫 file-loader
完成載入。
webpack5
file-loader
、url-loader
並不侷限於處理圖片,它們還可以被用於載入任意型別的多媒體或文字檔案,使用頻率極高,幾乎已經成為標配元件!所以 Webpack5 直接內建了這些能力,開箱即可使用。
用法上,原本需要安裝、匯入 Loader,Webpack5 之後只需要通過 module.rules.type
屬性指定資源型別即可
比如:
module.exports = {
// ...
module: {
rules: [{
test: /.(png|jpg|gif|jpeg)$/,
type: 'asset/resource'
}],
},
};
設定了這麼多內容,我們卻還不能看到頁面的內容,心裡肯定不樂意,上面這幾步操作其實就相當於翻譯 Vue SFC 檔案的內容,接下來我們還需要讓頁面真正執行起來。
有一種快速驗證我們的打包設定是否正確:我們只需要新建一個html檔案,將打包產物引入進去,並建立好掛載節點就可以
<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="../dist/bundle.42603d.js"></script>
</body>
</html>
我們再把這個html檔案在瀏覽器開啟,就能看到我們vue專案能夠正常開啟了。
這種方案有一種弊端就是:我們打包出來的檔案一般都會帶有hash
,那就需要我們每次在打包完後去html
檔案修改引入的檔案,這樣是不是有點太費勁了,你們能忍嗎?
上面那種方案在日常開發中顯然是不能接受的,身為程式設計師能偷懶的地方必須得偷懶!
我們可以利用下面兩個工具讓這個過程變得更加智慧化、自動化。
html-webpack-plugin: 自動生成 HTML 頁面
HtmlWebpackPlugin
簡化了 HTML 檔案的建立,以便為你的 webpack 包提供服務。這對於那些檔名中包含雜湊值,並且雜湊值會隨著每次編譯而改變的 webpack 包特別有用。
webpack-dev-server :讓頁面真正執行起來,並具備熱更新能力。
webpack-dev-server
主要提供兩種功能:
安裝
npm i html-webpack-plugin webpack-dev-server
修改設定
const Webpack = require('webpack')
const {VueLoaderPlugin} = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/main.js',
output: {
filename: 'bundle.[hash:6].js',
path: __dirname + '/dist',
},
module: {
rules:[
{test: /.vue$/, use: 'vue-loader'},
{
test: /.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /.js$/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
exclude: /node_modules/
},
{
test: /.(png|jpg|gif|jpeg)$/,
type: 'asset/resource',
}
]
},
plugins:[
new Webpack.ProgressPlugin(),
new VueLoaderPlugin(),
new HtmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html'
})
],
devServer: {
hot: true,
open: true
}
}
修改啟動指令碼
"dev": "webpack serve --mode development"
執行
npm run dev
這時webpack就能自動幫我們開啟瀏覽器執行頁面了
vue檔案內容如下:
<template>
<div class="title">webpack + vue -- {{ name }}</div>
<img src="../asset/1.png" class="top_bg" />
</template>
<script setup>
import { ref } from 'vue'
const name = ref('前端南玖')
</script>
<style>
.title {
font-size: 16px;
font-weight: bold;
color: salmon;
}
.top_bg {
width: 100%;
height: auto;
}
</style>
如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公眾號首發,關注 前端南玖
第一時間獲取最新文章~
-------------------------------------------
如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,文章公眾號首發,關注 前端南玖 第一時間獲取最新的文章~
掃描下方二維條碼關注公眾號,回覆進群,拉你進前端學習交流群(WX),這裡有一群志同道合的前端小夥伴,交流技術、生活、內推、面經、摸魚,這裡都有哈,快來加入我們吧~ 回覆資料,獲取前端大量精選前端電子書及學習視訊~