使用webpack搭建單頁面程式十分常見,但在實際開發中我們可能還會有開發多頁面程式的需求,因此我研究了一下如何使用webpack搭建多頁面程式。
原理
將每個頁面所在的資料夾都看作是一個單獨的單頁面程式目錄,配置多個entry
以及html-webpack-plugin
即可實現多頁面打包。
下面為本專案目錄結構
.
├─ src
│ └─ pages
│ ├─ about
│ │ ├─ index.css
│ │ ├─ index.html
│ │ └─ index.js
│ └─ index
│ ├─ index.css
│ ├─ index.html
│ └─ index.js
└─ webpack.config.js
單頁面打包基礎配置
首先我們來看一下單頁面程式的 webpack 基礎配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
}),
],
output: {
path: path.resolve(__dirname, './dist'),
filename: 'bundle.js',
},
};
要想將其改為多頁面程式,就要將它的單入口和單 HTML 模板改為多入口和多 HTML 模板
多頁面打包基礎配置
改造入口
傳統的多入口寫法可以寫成鍵值對的形式
module.exports = {
entry: {
index: './src/pages/index/index.js',
about: './src/pages/about/index.js',
},
...
}
這樣寫的話,每增加一個頁面就需要手動新增一個入口,比較麻煩,因此我們可以定義一個根據目錄生成入口的函式來簡化我們的操作
const glob = require('glob');
function getEntry() {
const entry = {};
glob.sync('./src/pages/**/index.js').forEach((file) => {
const name = file.match(/\/pages\/(.+)\/index.js/)[1];
entry[name] = file;
});
return entry;
}
module.exports = {
entry: getEntry(),
...
}
改造輸出
在輸出的配置項中,再將輸出的檔名寫死顯示已經不合適了,因此我們要將名字改為與原始檔相匹配的名字
module.exports = {
...
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name].[contenthash].js',
},
...
}
配置多個 html-webpack-plugin
與入口相同,可以將不同的 html 模板直接寫入外掛配置中,這裡我們需要為每個外掛配置不同的chunks
,防止 js 注入到錯誤的 html 中
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: './src/pages/index/index.html',
chunks: ['index'],
filename: 'index.html',
}),
new HtmlWebpackPlugin({
template: './src/pages/about/index.html',
chunks: ['about'],
filename: 'about.html',
}),
],
...
};
這樣的做法與入口有著同樣的毛病,因此我們再定義一個函式來生成這個配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
const glob = require('glob');
function getHtmlTemplate() {
return glob
.sync('./src/pages/**/index.html')
.map((file) => {
return { name: file.match(/\/pages\/(.+)\/index.html/)[1], path: file };
})
.map(
(template) =>
new HtmlWebpackPlugin({
template: template.path,
chunks: [template.name.toString()],
filename: `${template.name}.html`,
})
);
}
module.exports = {
...
plugins: [...getHtmlTemplate()],
...
};
這樣一個簡單的多頁面專案就配置完成了,我們還可以在此基礎上新增熱更新、程式碼分割等功能,有興趣的可以自己嘗試一下
完整配置
專案地址:xmy6364/webpack-multipage
// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const glob = require('glob');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
// 多頁入口
function getEntry() {
const entry = {};
glob.sync('./src/pages/**/index.js').forEach((file) => {
const name = file.match(/\/pages\/(.+)\/index.js/)[1];
entry[name] = file;
});
return entry;
}
// 多頁模板
function getHtmlTemplate() {
return glob
.sync('./src/pages/**/index.html')
.map((file) => {
return { name: file.match(/\/pages\/(.+)\/index.html/)[1], path: file };
})
.map(
(template) =>
new HtmlWebpackPlugin({
template: template.path,
chunks: [template.name.toString()],
filename: `${template.name}.html`,
})
);
}
const config = {
mode: 'production',
entry: getEntry(),
output: {
path: path.resolve(__dirname, './dist'),
filename: 'js/[name].[contenthash].js',
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [new CleanWebpackPlugin(), ...getHtmlTemplate()],
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 3000,
hot: true,
open: true,
},
};
module.exports = config;