Skip to content
本页索引

SPA 静态化

SPA 静态化部分是为前端开发同学准备的,如果您是后端(服务端)开发,可能想了解 API 静态化,如果您不是开发人员,建议您了解基本静态化概念即可。

开发模式调整

SPA 静态化方案并不限制具体的前端技术栈,但为了实现最终静态化效果需要对开发模式做一些约定:

  1. 生产环境的路由需要是 history 模式

    这是最终静态化形态要求的,需要在路由模式中采用 history 模式以实现 URL 地址的变化。通常在开发模式中这种方式是不方便的,为了兼容开发和生产环境,建议在 index.html 中注入编译模式变量(以 webpack 编译模板为例):

    html
    <html>
        <head>
            <title>SPA</title>
            <script>
                window.$buildMode = "<%= BUILD_MODE %>";
            </script>
        </head>
        <body>
            <div id="app">
                ...
            </div>
        </body>
    </html>

    然后在路由初始化时,根据环境模式切换路由模式:

    js
    const router = new Router({
      mode: window.$buildMode === "dev" ? "hash" : "history",
      routes,
    });
  2. 资源基础路径需要是绝对路径

    由于同一份 SPA 文件会静态化多份放在不同的目录中,这就要求 SPA 中引用的静态资源的路径跟 html 文件位置无关,也就是要求使用绝对路径。比如 /static/page/assets/, 而这个基础资源路径的配置在各个主流前端开发框架下都是支持的。同时,这个基础路径也需要同步到路由配置中。

    可以将资源基础路径注入到模板:

    html
    <html>
        <head>
            <title>SPA</title>
            <script>
                window.$buildMode = "<%= BUILD_MODE %>";
                window.$basePath = "<%= ASSETS_BASE_PATH %>";
            </script>
        </head>
        <body>
            <div id="app">
                ...
            </div>
        </body>
    </html>

    然后在路由创建时将基础路径传递给路由:

    js
    const router = new Router({
      base: window.$basePath || "",
      mode: window.$buildMode === "dev" ? "hash" : "history",
      routes,
    });

创建模板

打开 KMS 模板中心,创建一个新的模板:

提示

如果看不到模板中心入口(在页面最顶部模块导航中),则需要联系管理员进行配置后方可启用。

  1. 填写模板标题,可选分组

  2. 勾选部署目标,即页面最终要部署的域名

  3. 输入部署路径,比如 /website-test/[url]

  4. 编写 数据函数 准备静态化需要的填充数据,查看更多数据函数细节

    js
    async function main(getConfigData, request, utils) {
        // 通过 getConfigData 可以直接获取 KMS 配置中心的数据
        // 第一个参数是数据 Key 或者 别名
        // 第二个参数是数据过滤配置,等同于数据API的参数
        // 也可以使用 request 工具从其他地方获取数据
        const list = await getConfigData("key-or-alias", {
            pure: "items",
            f: "data,sn",
        })
        // 获取数据后,需要整理为对象或者数组以供填充模板
        // 如果返回对象,则最终只会静态化生成一个文件
        // 如果返回数组,则数组中每个元素都会生成一个文件
        // !!请注意,文件生成的位置要跟代码中的路由规则完全匹配 !!
        return [
            {
                // 字段用于填充部署路径中的 [url] 内容
                url: "home/index.html",
            },
            ...list.map(item => {
                return {
                    url: "news/" + item.sn + ".html"
                }
            })
        ]
    }

    注意

    生成的文件路径,一定 要跟代码中实现的路由规则 完全一致,否则会出现刷新后无法访问的情况。

    采用命名路由

    建议代码中的任何路由跳转要使用 命名router 方式跳转,比如 router.push({ name: "news", params: { id: "xxxx" } }) 以实现最大的兼容性。

  5. 将 SPA 页面内容复制到 主模板

  6. 保存模板

此时,模板中心将立即启动静态化过程:按照 数据函数 的结果填充 主模板 并推送静态化内容到部署目标上。

注入初始化数据和关联链接

通过上述两步操作后,SPA 文件已经被按照路由规则复制到不同目录下了,此时访问页面从功能上来说是完整的。如果项目对 SEO 没有特殊要求,就可以跳过这一步了。对 SEO 有要求的,还得继续为 SEO 优化,为 SPA 页面注入动态数据和关联链接。

  1. 注入初始化数据

    通常 SPA 页面在加载后需要请求后端 API 获取初始化的数据后才可以显示页面,比如新闻页面。这种情况下可以将新闻页的初始化数据直接输出到 SPA 模板中。

    先修改 数据函数 增加 content 内容:

    js
    async function main(getConfigData, request, utils) {
    	...
        
        return [
            {
                url: "home/index.html",
                content: "",
            },
            ...list.map(item => {
                return {
                    url: "news/" + item.sn + ".html",
                    content: item.data.content || ""
                }
            })
        ]
    }

    然后在 主模板 中注入初始化数据:

    html
    <html>
        <head>
            <title>SPA</title>
            <script>
                window.$initData = <%- JSON.stringify(content) %>
            </script>
        </head>
    </html>

    然后修改页面脚本,调整初始化数据获取逻辑(示意代码):

    js
    async loadData() {
        const initData = window.$initData;
        if(initData) {
            // 使用后要立即删除全局注入的数据,防止 SPA 路由跳转后其他页面读取
            delete window.$initData;
            return initData
        }
        return await loadInitDataFromRemoteAPI()
    }

    经过此步改造之后,SPA 副本将具有不同的内容,并且已经静态化了初始化数据,页面渲染速度将进一步提高,并且对搜索引擎也是友好的。

    当然,对 SEO 更友好的方式,是直接注入一段 html 代码而不是一个 script 的变量:

    html
    <html>
        <head>
            <title>SPA</title>
        </head>
        <body>
            <div id="initData">
                <%= content %>
            </div>
            <div id="app">
                ...
            </div>
        </body>
    </html>

    对应的代码加载逻辑也需要做相应修改,此略。

  2. 注入关联链接

    SEO 除了要求页面内容有相关性之外,页面之间的互联也是重要的信息。为了更好的 SEO 效果,可以参照上述类似的步骤,将链接作为 html 注入到 SPA 模板中即可。

本地开发联动

在 SPA 开发中,为了预览效果,可能需要反复修改模板配置中的 主模板 内容,为了简化操作步骤,KMS 提供了基于前端工作流的自动化工具,请 移步内网 gitLab 查看。