前不久從零開始寫了一個webpack多頁面打包boilerplate(webpack4-boilerplate),方便之後工做能夠開箱即用,特此記錄下開發過程當中的要點。javascript
注意:本文不會詳細介紹webpack的基礎知識,若是徹底不會,建議看下我以前寫過的基礎文章css
首先發出一個直擊靈魂的拷問:爲何要多頁面打包?html
習慣了React,Vue全家桶的同窗,可能以爲寫代碼不就是:npm run dev
npm run build
一把梭嗎?前端
然而現實是骨感的,不少場景下,單頁應用的開發模式並不適用。好比公司常常開發一些活動頁: https://www.demo.com/activity/activity1.html
https://www.demo.com/activity/activity2.html
https://www.demo.com/activity/activity3.html
vue
上述三個頁面是徹底不相干的活動頁,頁面之間並無共享的數據。然而每一個頁面都使用了React框架,而且三個頁面都使用了通用的彈框組件。在這種場景下,就須要使用webpack多頁面打包的方案了:java
所以,咱們能夠把多頁應用當作是乞丐版的前端微服務。node
首先咱們約定: src/pages
目錄下,每一個文件夾爲單獨的一個頁面。每一個頁面至少有兩個文件配置:react
app.js
: 頁面的邏輯入口webpack
index.html
: 頁面的html打包模板git
src/pages
├── page1
│ ├── app.js
│ ├── index.html
│ ├── index.scss
└── page2
├── app.js
├── index.html
└── index.scss
複製代碼
前面咱們說過:每一個頁面能夠當作是個獨立的單頁應用。
單頁應用怎麼打包的?單頁應用是經過配置webpack的的entry
module.exports = {
entry: './src/main.js', // 項目的入口文件,webpack會從main.js開始,把全部依賴的js都加載打包
output: {
path: path.resolve(__dirname, './dist'), // 項目的打包文件路徑
filename: 'build.js' // 打包後的文件名
}
};
複製代碼
所以,多頁應用只需配置多個entry便可
module.exports = {
entry: {
'page1': './src/pages/page1/app.js', // 頁面1
'page2': './src/pages/page2/app.js', // 頁面2
},
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name]/[name]-bundle.js', // filename不能寫死,只能經過[name]獲取bundle的名字
}
}
複製代碼
同時,由於多頁面的index.html模板各不相同,因此須要配置多個HtmlWebpackPlugin。
注意:HtmlWebpackPlugin
必定要配chunks
,不然全部頁面的js都會被注入到當前html裏
module.exports = {
plugins: [
new HtmlWebpackPlugin(
{
template: './src/pages/page1/index.html',
chunks: ['page1'],
}
),
new HtmlWebpackPlugin(
{
template: './src/pages/page2/index.html',
chunks: ['page2'],
}
),
]
}
複製代碼
多頁面打包的原理就是:配置多個entry
和多個HtmlWebpackPlugin
vendor.js
common.js
和common.css
manifest.js
page1.js
和page1.css
前3項是每一個頁面都會引入的公共文件,第4項纔是每一個頁面本身單獨的文件。
實現方式也很簡單,配置optimization
便可:
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
// 打包業務中公共代碼
common: {
name: "common",
chunks: "initial",
minSize: 1,
priority: 0,
minChunks: 2, // 同時引用了2次纔打包
},
// 打包第三方庫的文件
vendor: {
name: "vendor",
test: /[\\/]node_modules[\\/]/,
chunks: "initial",
priority: 10,
minChunks: 2, // 同時引用了2次纔打包
}
}
},
runtimeChunk: { name: 'manifest' } // 運行時代碼
}
}
複製代碼
最後打包出來的文件,咱們但願帶上hash值,這樣能夠充分利用瀏覽器緩存。webpack中有hash
,chuckhash
,contenthash
:生產環境時,咱們通常使用contenthash
,而開發環境其實能夠不指定hash。
// dev開發環境
module.exports = {
output: {
filename: 'js/[name]/[name]-bundle.js',
chunkFilename: 'js/[name]/[name]-bundle.js',
},
}
// prod生產環境
module.exports = {
output: {
filename: 'js/[name]/[name]-bundle.[contenthash:8].js',
chunkFilename: 'js/[name]/[name]-bundle.[contenthash:8].js',
},
}
複製代碼
開發環境,一般須要mock數據,還須要代理api到服務器。咱們能夠經過devServer
配合mocker-api第三方庫實現。
const apiMocker = require('mocker-api');
// dev開發環境
module.exports = {
devServer: {
before(app) { // 本地mock數據
apiMocker(app, path.resolve(__dirname, '../mock/index.js'))
},
proxy: { // 代理接口
'/api': {
target: 'https://anata.me', // 後端聯調地址
changeOrigin: true,
secure: false,
},
}
},
}
複製代碼
爲了通用配置,把webpack的配置文件分紅3份。
build
├── webpack.base.js // 共用部分
├── webpack.dev.js // dev
└── webpack.prod.js // 生產
複製代碼
dev
和prod
配置的主要區別:
dev
配置devServer
,方便本地調試開發prod
打包壓縮文件,單獨提取css (dev不提取是爲了css熱更新),生成靜態資源清單manifest.json
關於爲何要生成一份manifest.json
,以及打包後的代碼如何部署,我將會在下一篇文章詳細介紹。