一、多页面概念
多页面应用(Multi-Page Application,MPA)是一种传统的 Web 应用程序架构,其特点是每个页面都是一个独立的 HTML 文件,用户的每次请求都会从服务器加载完整的新页面。与单页面应用(SPA)相比,MPA 的页面切换需要重新加载整个页面,但具有更好的 SEO 性能和首屏加载速度。
二、多页面打包思路
Webpack本身是一个模块打包器,主要用于将JavaScript应用程序打包成一个或多个bundle。对于多页面应用(MPA),每个页面有其独立的入口文件和输出文件。多页面打包的策略如下:
1.创建页面入口和模板
(1)按照约定格式创建入口,如下page1、page2:
app
|--xxxx
|-- pages
| |-- page1
| |-- |--entry.page1.js // page1的入口文件
| |-- |--page1.vue // page1的功能页面
| |-- page2
| |-- |--entry.page2.js // page2的入口文件
| |-- |--page2.vue // page2的功能页面
| |-- xxxx
entry.page1.js:
import boot from '$pages/boot.js';
import page1 from './page1.vue';=
boot(page1);
page1.vue:
<template>
<h1>page1</h1>
<div>{{ content }}</div>
</template>
<script setup>
import {ref, onMounted} from 'vue';
import $curl from '$common/curl';
const content = ref('');
});
</script>
<style lang="less" scoped>
</style>
(2)创建公共模板:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{name}}</title>
<link href="/static/normalize.css" rel="stylesheet"/>
<link href="/static/logo.png" rel="icon" type="image/x-icon"/>
<title>{{name}}</title>
</head>
<body style="margin:0">
<div id="root"></div>
// webpack会自动注入js/css
</body>
</html>
3.创建 Webpack 配置
(1)指定打包入口文件
(2) 使用HtmlWebpackPlugin为每个页面生成HTML
plugins: [
new VueLoaderPlugin(),
// 构造最终渲染的页面->page1
new HtmlWebpackPlugin({
// 产物(最终模版)输出路径
filename: path.resolve(process.cwd(), './app/public/dist/', 'entry.page1.tpl'),
// 指定要使用的模版文件
template: path.resolve(process.cwd(), './app/view/entry.tpl'),
// 要注入的代码块
chunks: ['entry.page1']
}),
// 构造最终渲染的页面->page2
new HtmlWebpackPlugin({
// 产物(最终模版)输出路径
filename: path.resolve(process.cwd(), './app/public/dist/', 'entry.page2.tpl'),
// 指定要使用的模版文件
template: path.resolve(process.cwd(), './app/view/entry.tpl'),
// 要注入的代码块
chunks: ['entry.page2']
}),
……
],
运行npm run build命令后,即可生成entry.page1.tpl、entry.page2.tpl以及对应的js文件,并分别将js注入到tpl,实现多页面应用。
多页面实现基本思路:为每个页面创建独立的入口文件和 HTML 模板,并通过 Webpack 配置动态生成多个 HTML 文件。
三、多页面打包通用逻辑
如果有多个页面,可以通过动态生成HtmlWebpackPlugin实例,避免重复代码。
// 动态生成多个入口和 HTML 页面:
const pageEntries = [];
const htmlWebpackPluginList = [];
// 获取app/pages 目录下所有入口文件(entry.xxx.js)
const entryList = path.resolve(process.cwd(), './app/pages/**/entry.*.js');
glob.sync(entryList).forEach(file => {
const entryName = path.basename(file, '.js');
// 构造entry
pageEntries[entryName] = file;
htmlWebpackPluginList.push(
// HtmlWebpackPlugin辅助注入打包后的bundle.js文件到tpl文件中
new HtmlWebpackPlugin({
// 产物(最终模版)输出路径
filename: path.resolve(process.cwd(), './app/public/dist/', `${entryName}.tpl`),
// 指定要使用的模版文件
template: path.resolve(process.cwd(), './app/view/entry.tpl'),
// 要注入的代码块
chunks: [entryName]
})
);
});
module.exports = {
// 入口配置
entry: {
...pageEntries
},
plugins: [
xxx,
// 构造最终渲染的页面
...htmlWebpackPluginList
]
}