Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

lavas-project/lavas-template-vue-mpa

Open more actions menu

Repository files navigation

Lavas MPA 模版

这是一个支持多页应用的 Vue 模版,解决了一些多页应用中遇到的常见问题

安装,开发及调试

# 安装依赖
npm install

# 更新
npm update

# 启动开发服务器,默认打开localhost:8082/home
npm run dev

# 检查您的代码是否规范
npm run lint

# 生产环境构建
npm run build

# 生产环境构建并展示 bundle 信息
npm run build --report

文件结构

绝大部分结构和 Lavas Appshell模版一致,只是pages/下存放各个页面文件夹而不是路由组件。 每个页面文件夹中包含该单页所需的各个文件。

lavas-template-vue-mpa
    |---src
        |---pages 页面存放目录
            |---detail 详情页模块
                |--- Detail.skeleton.vue 构建时渲染的skeleton组件
                |--- Detail.vue 路由组件
                |--- entry-skeleton.js skeleton入口
                |--- entry.js entry入口
                |--- index.html 页面模版,供htmlWebpackPlugin使用
                |--- router.js 单页面使用的路由
            |---home 主页模块
            |---search 搜索页模块
        |---...省略其他目录

基本实现方式

与 Appshell 单页模版不同的是,使用 multipage 插件生成多个页面,同时在构建时预渲染各个页面对应的 skeleton 组件,将渲染结果插入最终页面 HTML 中。

如果您还不了解 skeleton 骨架屏组件,可以参考这篇文章

多页应用中特有问题

在多页应用中,有两个问题需要我们关注:

  1. 各个单页路由跳转问题。
  2. 单页应用中,Service Worker 查找当前路由对应的 HTML 页面很简单。多页中则不是。

各个单页间跳转

在单页应用中我们使用 vue-router 进行前端路由跳转,而多页应用可以看成多个单页应用,每个单页都可以有各自独立的路由,那么如何做到在各个单页之间进行跳转呢?

例如想从A页面跳转到B页面,发现目标路由规则并不在A页面的规则集中,此时肯定不能展示404页面,需要识别出这是一个有效的路由规则,通过window.location.href而非 vue-router 进行跳转。

这就要求我们在构建时收集所有页面使用的路由规则(由router-loader完成),形成一个项目中有效的路由规则全集。各个页面遇到不匹配的路由时,都需要去这个全集中查看,匹配了其中的某条规则才进行跳转,否则依然展示404页面。

具体实现如下:

// src/router.js

// 各个页面的路由对象都通过这种方式创建
const router = new Router({
    mode: 'history',
    base: '/',
    routes: [
        ...routes,
        {
            path: '*',
            component: NotFound,
            beforeEnter(to, from, next) {
                if (validateRoute(to.fullPath)) { // 跳转到有效路由
                    window.location.href = to.fullPath;
                    return;
                }
                next(); // 继续展示404页面
            }
        }
    ]
});

关于 router-loader 的实现原理,可以参考这篇文档

下面让我们看看在服务端要做哪些配置。

服务端配置

和使用 HTML5 History 模式的单页应用一样,需要在服务端配置路由规则。 服务端只需要关心页面级别的重定向,以nginx为例:

// nginx.conf

server {
    # 省略其他配置

    location /home {
        try_files $uri $uri/ /home.html;
    }

    location /detail {
        try_files $uri $uri/ /detail.html;
    }

    location /search {
        try_files $uri $uri/ /search.html;
    }
}

其实在开发服务器 express 中,我们也做了一些简单的配置:

// build/dev-server.js

var rewrites = Object.keys(utils.getEntries('./src/pages', 'entry.js'))
    .map(function (entry) {
        return {
            from: new RegExp(`/${entry}`),
            to: `/${entry}/index.html`
        };
});
app.use(require('connect-history-api-fallback')({
    htmlAcceptHeaders: ['text/html'],
    rewrites
}));

我们为什么不将 404 放在服务端配置,例如在 nginx 配置中最后写一条规则呢? 如果我们这么做,那么需要将前端所有路由规则在 nginx 中复制一份,这样才能保证不在路由规则全集中的请求落到 404 规则中。这样一来,每次前端路由发生变化,都需要在服务端同步修改。这也是我们将 404 放在前端判断的原因,这样服务端的配置将简单很多,只有新增页面级别的路由才需要修改。

缓存查找

我们需要对使用 sw-precache 插件生成的 Service Worker 文件进行一点修改。

默认在缓存中查找请求结果时,遵循以下规则按顺序查找:

  1. 忽略参数,hash
  2. 尝试拼上index.html
  3. 使用缺省页面路径,通常传入index.html

这在单页应用中没有问题,只有一个页面嘛,缺省路径总是可以生效。但多页中就不行了。 我们需要在第三步之前增加一个判断,根据路径判断当前路由属于哪个页面。例如/home/user应该匹配到缓存中的home.html,当然这是根据默认的打包路径规则确定的。

// config/sw.tmpl.js
var url = new URL(originalUrl);
// /home/user => home
var entryName = url.pathname.split('/')[1];
if (entryName) {
    url.pathname = '/' + entryName + '.html';
}

这样就能保证多页的离线可用了。

About

Lavas Template with Multiple Page App

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  
Morty Proxy This is a proxified and sanitized view of the page, visit original site.