前司和现司都会存在这种业务场景:有不少 H5 页面是不相关的,若是使用 SPA 的话,对于不少落地页和活动页不太友好,有一些纯前端页面加载过慢,因此就萌生了建立一个多页面 MPA 的框架。css
起初想着使用 vue-cli3 去建立,由于 vue-cli3 自己带有多页面配置的选项,直接修改 pages 这个选项就能够完成多页面配置,须要的小伙伴能够进行参考,连接:vue-cli3 的 pages。可是由于要兼容安卓 4.4 如下系统(有一些请求库中包含 E6 语法,如:axios,安卓 4.4 如下系统没法识别,因此会致使打开页面是空白的问题),pages 的入口不能配置数组,没办法添加 babel-polyfill,不能兼容低版本原生系统,因此最终采用了 webpack4 来进行多页面打包。html
本项目涉及到的技术栈主要是:webpack4,vue2,vuex3,vue-router,eslint。主要是 webpack4 的配置,其实 vue,vuex,vue-router 使用起来都是同样的。前端
先附上git仓库地址,而后再细说:webpack-vue-multipage。vue
其实原理是 webpack 根据页面入口文件,将一个 SPA 项目分红多个 SPA 进行打包。webpack
安卓 4.4 如下手机的兼容ios
页面 router 和 支持文件夹层级打包git
这两种方式都是为了支持同一个项目下有多个页面,好比咱们作的一个简易版商城也是在这个多页面中,这个时候商城可使用 router 去控制页面路由,也可使用层级的方式去建立多个 html 页面去实现,这个能够根据本身的业务去采用不一样的方案,咱们两种方式都会介绍。es6
有些 js 须要直接在 html 模板中引入,打包直接生成在 html 中,可是有些页面不须要引入其余的 js,好比一些纯静态页面。github
保证一个团队提交代码的统一性,能够参考我以前掘金的文章,手摸手带你实践标准的前端开发规范 web
介绍的差很少了,废话很少说,直接开整:
git clone https://github.com/Shiyanping/webpack-vue-multipage.git
cd webpack-vue-multipage
npm install
npm run dev
# 启动以后在浏览器访问便可,http://localhost:8022/index.html
# eslint
npm run eslint
# 格式化代码
npm run prettier
# build
npm run build
复制代码
多页面和单页面的区别,主要是在 entry 上,因此咱们首先对 entry 进行处理。
多页面和单页面最大的不一样点,就在于入口的不一样。
多页:最终打包生成多个入口( html 页面),通常每一个入口文件除了要引入公共的静态文件( js/css )还要另外引入页面特有的静态资源
单页:只有一个入口( index.html ),页面中须要引入打包后的全部静态文件,全部的页面内容全由 JavaScript 控制
直接看代码吧,在 utils 中有一个 get_entry_config.js 去获取 entry 的配置,其中包括了入口选择性引用模板 html,babel-polyfill 加到入口的配置中。注释其实写的听明白的,各位看官有什么不知道的能够像老哥我咨询。
const fs = require("fs");
const HTMLWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
const config = require("./../../config/page_config"); // 多页面的配置项
const resolve = dir => {
return path.resolve(process.cwd(), dir);
};
let HTMLPlugins = [];
let Entries = {};
config.HTMLDirs.forEach(item => {
let filename = `${item.page}.html`;
/** * 支持多级目录,dir/page.html * 多页面框架中能够采用这种方式增长层级目录,一个目录下有多个页面 * 也可使用 router 进行同级目录下一个html,经过 router 控制路由 */
if (item.dir) {
filename = `${item.dir}/${item.page}.html`;
}
// 每一个页面的文件夹下能够含有一个本身的index.html,若是有会根据这个模板进行build
let pageHtml = `src/pages/${item.page}/index.html`;
// 若是文件夹下没有制定的模板,则采用默认的模板 build
if (!fs.existsSync(pageHtml)) {
pageHtml = "src/template/default.html";
}
const htmlPlugin = new HTMLWebpackPlugin({
title: item.title, // 生成的html页面的标题
filename: filename, // 生成到dist目录下的 html 文件名称
template: resolve(pageHtml), // 模板文件,不一样入口能够根据须要设置不一样模板
chunks: [item.page, "vendor"] // html文件中须要要引入的 js模块,这里的 vendor 是 webpack 默认配置下抽离的公共模块的名称
});
HTMLPlugins.push(htmlPlugin);
// 添加 babel-polyfill 解决安卓 4.4 如下兼容问题
Entries[item.page] = [
"babel-polyfill",
resolve(`src/pages/${item.page}/index.js`)
];
});
module.exports = {
HTMLPlugins,
Entries
};
复制代码
上面的 js 中引用了一个 page_config.js,这个 js 中,主要是多页面的配置信息:
module.exports = {
HTMLDirs: [
{
page: "index",
title: "首页"
},
{
page: "list",
title: "列表页",
dir: "content" // 支持设置多级目录
},
{
page: "detail",
title: "详情页"
}
]
};
复制代码
最后在 webpack.config.js 中引入相关配置:
module.exports = {
entry: entryConfig.Entries,
plugins: [
...entryConfig.HTMLPlugins // 利用 HTMLWebpackPlugin 插件合成最终页面
]
};
复制代码
这些就是咱们多页面的主要设置,也就是多页面的入口。
其实说白了多页面就是将多个小项目汇总到一个大项目,这个是 webpack 帮咱们作的事,只不过这些小项目之间的关联性不大,因此作成了多页面。
在实际开发中,有些页面须要直接在 html 中引入的 js 文件,好比公司的公共 jsbridge,没有封装成 npm 包,只能用下面这种方式引入了:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>
<%= htmlWebpackPlugin.options.title %>
</title>
</head>
<body>
<div id="app"></div>
<script src="http://www.xxx.com/jsbridge.min.js"></script>
</body>
</html>
复制代码
可是有些分享出去的页面,并不须要这个 js,若是咱们都使用同一个 html 模板打包,那至关于打包出去的多页面,每一个页面都有这个 js,这样就会致使页面请求慢一些问题。
这个时候就有必要对不一样的小项目使用不一样的 html 模板了。
其实主要的代码就是下面这几句,很简单:
// 每一个页面的文件夹下能够含有一个本身的index.html,若是有会根据这个模板进行build
let pageHtml = `src/pages/${item.page}/index.html`;
// 若是文件夹下没有制定的模板,则采用默认的模板 build
if(!fs.existsSync(pageHtml)){
pageHtml = 'src/template/default.html';
}
const htmlPlugin = new HTMLWebpackPlugin({
...
template: resolve(pageHtml), // 模板文件,不一样入口能够根据须要设置不一样模板
...
});
复制代码
根据文件夹目录去引用 html 模板,若是当前页面文件夹下有本身的 index.html,那咱们就使用本身的,若是没有就使用默认的。这样在打包生成 html 的时候就能够按照不一样页面引用不一样的 html 模板了,不会形成不想要的 js 被引用的问题存在。
这个问题提及来不少人都不想弄,其实我也不想,可是没办法啊,公司的用户群体中安卓机占了很大一部分,而且安卓 4.4 如下机型占了 20%,这样的状况就必需要对页面作兼容了。
其实单页面作兼容很简单,在 webpack 的 entry 配置一下 babel-polyfill,而后在单页面的 main.js 中,直接引入 babel-polyfill 和 es6-promise 就能够了。以下:
// webpack.config.js
entry = ['babel-polyfill', resolve('src/main.js')];
// main.js
import 'babel-polyfill';
import promise from 'es6-promise';
promise.polyfill();
复制代码
这样SPA就能够解决兼容问题,MPA就有一点麻烦了,触类旁通,咱们要在entry的每个入口增长 babel-polyfill,而后在每一个page下的index.js中引入 babel-polyfill 和 es6-promise。
写文章没点图怎么行,不上代码了,此次上截图:
get_entry_config.js:
感受看着不舒服,算了,仍是上代码吧~
// 添加 babel-polyfill 解决安卓 4.4 如下兼容问题
Entries[item.page] = ['babel-polyfill', resolve(`src/pages/${item.page}/index.js`)]; // 根据配置设置入口js文件
复制代码
而后在每一个文件夹的index.js中都要加入编译的代码。
// src/pages/**/index.js
import Vue from 'vue';
// import '@styles/lib/main.scss';
import Tpl from './index.vue';
import store from '../../store';
import 'babel-polyfill';
import promise from 'es6-promise';
promise.polyfill();
new Vue({
store,
render: (h) => h(Tpl)
}).$mount('#app');
复制代码
这样编译以后就能够解决安卓 4.4 如下的兼容了,亲测有效哦~
每一个小项目中,可能会涉及到一些页面相对来讲比较多的项目,好比一个简易版的商城,包括商品列表页,商品详情页,订单页。
这个时候咱们可使用两种方式:
这个我以为不用多说了吧,在须要使用路由的文件夹下建立一个router.js,而且引入vue-router,必定要在某个文件夹下建立哦,不然几个页面公用一个router,会有意想不到的结果。其实咱们就能够把MPA想象成多个SPA,一个SPA一个路由,他们之间没有关联,纯页面的东西不用路由就不须要建立。
这样就能够实现用路由的方式去控制不一样页面的走向了。
结构以下:
├── components
│ ├── About
│ │ └── Index.vue
│ └── Home
│ └── Index.vue
├── index.js
├── index.vue
└── router.js
复制代码
使用方式和开发其余SPA没区别。
这是另一种方式,就是经过打包成有层级目录的方式控制页面的走向,这个里面没有涉及到路由,只是单纯的打包加一个层级就行。
主要有两点须要控制,一个是页面配置 page_config.js
,另一个是 webpack 处理入口这块 get_entry_config.js
,看代码:
page_config.js:
{
page: 'list',
title: '列表页',
dir: 'content' // 支持设置多级目录
}
复制代码
get_entry_config.js:
let filename = `${item.page}.html`;
/** * 支持多级目录,dir/page.html * 多页面框架中能够采用这种方式增长层级目录,一个目录下有多个页面 * 也可使用 router 进行同级目录下一个html,经过 router 控制路由 */
if (item.dir) {
filename = `${item.dir}/${item.page}.html`;
}
复制代码
这样打包以后的文件就能实现如下层级的关系:
├── list.html
└── list1.html
复制代码
访问的时候就能够不须要依赖路由,直接访问页面便可。
这个我就不细说了,主要是为了保持团队中每一个人提交代码以前进行不合格的校验,确保git仓库中的代码是没问题的,而且格式是同样的,这个还能够搭配prettier使用,能够自行百度。
配置的问题,能够参考我以前的文章,手摸手带你实践标准的前端开发规范 。
有一点须要注意,一开始你clone的是我仓库,若是想实现提交就校验eslint,须要将文件夹中.git删除掉,关联到你的git仓库,而后从新安装husky 包。
基本的功能都实现了,不过还不是很完美,有不少功能都没加进来,好比移动端的样式适配,网络请求库封装,公共方法的提取...,因此说还有不少不足之处,欢迎你们在个人github仓库上进行pr和提issue,我会及时为你们解答。
参考连接:
很是感谢各位花时间阅读完,衷心但愿各位小伙伴能够花少许的时间帮忙作两件事:
动动你的手指,帮忙点个赞吧,你的点赞是对我最大的动力。
有兴趣的能够添加我微信,我邀请你加入前端讨论群,有惊喜哦~