静态页面自动化生成

一、业务需求

需要动态生成相关的一些简单交互的静态页面,比如协议页面,书单页面。

二、方案调研

类似于静态站点生成(SSG)

  • 优点:安全性比较高,因为提供的攻击选项比较少,也不会有服务器的压力
  • 缺点:因为它是预加载的,包含了大量不定期更改的内容,但是我们的业务出发,是需要定期进行更改的,如果采取SSG这种方案,我们的每次更改都会使得Web项目的静态页面再次预加载,这种构建随着项目越大,花费的时间就会越多。

三、方案确认

但是万变不离其中,核心原理我们得知的,那么就考虑如何去进行动态的生成,因为你预加载是在node层面的编译时,那我们动态生成就可以放在为node层面的运行时。

四、框架搭建

根据上面的思路,我们就开始了整体框架的搭建:

  1. 后台管理系统: vue + koa + mongodb
    • 项目管理: 根据项目可以生成不同的模版,不同的页面
    • 静态文档: 添加不同的页面内容,选择对应的模版,添加相关的文档内容或者说明
  2. 预览平台: vue + nuxt
    nuxt为底层基建,根据后台提供的API生成 /_project/_id的预览页面
  3. 中间层(BFF): koa
    node层 基于预览平台的框架,利用node层调用nuxt的generator生 成/_project/_id的静态HTML页面

后台管理系统主要由同事李盼中开发,这里不过多赘述。

五、实现原理

我们接下来主要介绍下生成的逻辑,预览平台的其实就可以把它当做一个独立的系统,核心的目录如下:

├── components               # 组件库
├── pages                    # 路径页面
│   ├── _project             # 动态项目
│   ├── _id.vue              # 动态ID

_id.vue文件内容如下:

<template>
    <component :is="template" :content="content"></component>
</template>
<script>
export default {
  data() {
    return {}
  },
  async asyncData({ $axios, error, store, params }) {
    const _rest = await $axios.get(`api地址);
    if (_rest.data.code == 200) {
      return {
          template: 'qm-common', // 默认配置(调取组件库的组件名)
          ..._rest.data.data
      };
    } else {
      error({
        statusCode: 500,
        message: '内部服务器错误'
      });
    }
  },
}
</script>

根据上面一套配置过后,我们就可以把相关路径植入到后台管理系统中,就实现了一个简单预览平台

预览完成过后我们就得考虑如何进行动态生成页面,扩展上面的文件目录:

├── components               # 组件库
├── pages                    # 路径页面
│   ├── _project             # 动态项目
│   ├── _id.vue              # 动态ID
├── services                 # BFF
│   ├── service.js           # 生成服务

核心代码如下:就是调用了nuxt实例抛出的generator函数进行build

router.post('/generate', async (ctx, next) => {
    const { id, project } = ctx.request.body
    try {
        // 创建一个 Nuxt.js 构建器实例
        const config = require('./nuxt.config.js')
        config.dev = false;
        config.generate = {
            routes: [`/${project}/${id}`]
        }
        const nuxt = new Nuxt(config)
        const generator = new Generator(nuxt)
        await generator.generate({ build: false, init: true })
        // moveFile();
        ctx.body = { success: true, message: "成功" };
    } catch (err) {
        ctx.body = { success: false, message: "失败" };
        console.log(err);
    }
})

六、实际展示成果

上述的2个步骤就实现了简单的动态生成,我们具体来看下效果:

  1. 后台配置
    1111-1

  2. 点击预览
    111-1
    preview2

    上图红线处就可以看出是动态路径/_project/_id.

  3. 点击发布后会调用publish接口,内部其实调用的是BFF服务generate,发布成功后可以查看正式链接
    generat3

上述后续的流水线部署就不多介绍了,一共2个系统,1个服务。
Tips:
在部署nginx过后,如果需要进行二次代理,nginx proxy_pass的时候需要注意路径匹配,如果二次代理的路径不匹配的话,会进行客户端渲染,此处需要注意。

七、总结

话不多说,附上整体架构图
------1

展示评论