多页面应用(MPA)
每次页面跳转的时候,后台服务器都会返回一个新的 HTML 文档,这种类型的网站也就是多页网站,也叫多页应用。多页面跳转时会刷新所有资源,每个公共资源 (js、css 等) 会选择性地重新加载。
为什么要多页面打包
在某些场景下,单页应用的开发模式并不适用。比如电商网站的一些活动页:
https://www.shopping.com/activity/activity1.html
https://www.shopping.com/activity/activity2.html
https://www.shopping.com/activity/activity3.html
如上述的三个页面是完全不相干的活动页,页面之间并没有共享的数据,在这种场景下,就可以使用 webpack 多页面打包的方案
多页面打包的原理
原理:要实现多页面打包,需要配置多个入口、多个 ( 出口依赖的 ) 模板文件
例如在 src 目录下有 detail、index、list、login 目录,在各自的目录下都有 index.js 和 index.html 文件,我们在 webpack.config.js 文件中配置以 index.js 为入口,index.html 为模板文件的多页面打包配置。
多页面打包的方案
底层实现:借助 glob 模块拿到多个入口文件,遍历后得到多个模板文件,最后将入口文件和模板文件都暴露出去,在 webpack.config.js 中使用。
const path = require('path');
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const setMpa = () => {
// 多页面打包的入口集合
const entry = {};
// 多页面打包的模板集合
const htmlWebpackPlugins = []
// 借助 glob 获取 src 目录下的所有入口文件
const entryFiles = glob.sync(path.resolve(__dirname, "./src/*/index.js"));
// 遍历文件集合,生成所需要的 entry、htmlWebpackPlugins 集合
entryFiles.map((item, index) => {
const match = item.match(/src\/(.*)\/index\.js$/);
const pageName = match?.[1];
entry[pageName] = item;
// 多页面所需要的模板集合
htmlWebpackPlugins.push(
new HtmlWebpackPlugin({
title: pageName,
filename: `${pageName}.html`,
template: path.join(__dirname, `src/${pageName}/index.html`),
chunks: [pageName]
})
)
})
// 对外输出页面打包需要的 入口集合
return { entry, htmlWebpackPlugins }
}
module.exports = setMpa()
在 webpack.config.js 文件中导入该文件模块,并添加配置:
const path = require("path");
const htmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
// 导入多页面应用打包方案
const { entry, htmlwebpackplugins } = setMpa();
module.exports = {
// 添加 entry 配置
entry,
output: {
path: path.resolve(__dirname, "./mpa"),
filename: "[name].js",
},
mode: "development",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"postcss-loader",
"less-loader",
],
},
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name].[ext]",
outputPath: "images/",
publicPath: "../images",
limit: 1024 * 3, //阈值 超过阈值的图片会独立文件,没有超过会处理成base64
},
},
},
{
test: /\.(eot|woff|woff2)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
publicPath: "../",
},
},
},
],
},
plugins: [
// 添加 htmlwebpackplugins
...htmlwebpackplugins,
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
new CleanWebpackPlugin(),
],
};
在 package.json 中配置命令 "mpa" : "webpack --config ./webpack.mpa.config.js" (命令仅用于测试)
"scripts": {
"dev": "webpack",
"serve": "webpack-dev-server",
"mpa" : "webpack --config ./webpack.mpa.config.js"
},
在终端中执行 npm run mpa 打包,最后打包出来的结果如下:
多入口打包出来的文件如上图,每个文件我们都可以单独访问。