你如何在 Nuxt JS (SSR) 中使用无头 CMS 的路由?

Rya*_*ley 9 umbraco url-routing server-side-rendering nuxt.js headless-cms

问题

我正在尝试使用 CMS 定义的路由来获取内容,这些内容用于确定在我们的 Nuxt 前端加载哪个页面。那么,您如何实现自己的逻辑来将路由连接到内容,将内容连接到页面,同时保持 Nuxt 页面的所有出色功能?

任何帮助将不胜感激!

上下文

Headless CMS 正在兴起,我们希望在通用模式 (SSR) 下将我们的 CMS 与 Nuxt 一起使用。

我们一直在使用 Umbraco(一种免费托管的 CMS),它具有灵活的路由系统,我们无法在没有大量用户强烈反对的情况下对其进行限制。

注意:Umbraco 不是无头的,我们自己在 GitHub 上Umbraco Headrest 项目中添加了该功能

注意:每条内容都有一个包含其内容类型名称的字段

例如,以下内容结构是有效的。

.
home
??? events
|   ??? event-one
|   ??? event-two
|       ??? event-special-offer
|       ??? some-other-content
??? special-offer
??? other-special-offer
Run Code Online (Sandbox Code Playgroud)

因此,如果我们想用 nuxt 呈现这些特价商品,我们将需要使用 Pages/SpecialOffer.vue。

问题

问题是这些特价商品的默认路径是:

  • /special-offer
  • /other-special-offer
  • /events/event-two/event-special-offer

编辑器还可以创建自定义路径,例如:

  • /holiday2020/special(可以指向event-special-offer

编辑器还可以重命名内容,因此other-special-offer可以变成new-special-offer. 然后一把umbraco将返回new-special-offer两个/other-special-offer/new-special-offer

尝试的解决方案

以下方法很有希望,但要么不起作用,要么只是部分成功。

  1. 使用中间件将 URL 请求转发到 Umbraco 并从结果中确定要加载的组件(失败
  2. 使用插件将 URL 请求转发到 Umbraco 并从结果中确定要加载的组件(失败
  3. 从内容映射路线(部分
  4. 使用使用响应数据加载动态组件的单个页面(部分

1)中间件方式

我们尝试创建对 CMS 的 API 的异步调用,然后使用响应来确定要加载的页面。

中间件.js

.
home
??? events
|   ??? event-one
|   ??? event-two
|       ??? event-special-offer
|       ??? some-other-content
??? special-offer
??? other-special-offer
Run Code Online (Sandbox Code Playgroud)

问题

在服务器上运行时,中间件好像在路由解析运行,导致如下错误:

vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.
Run Code Online (Sandbox Code Playgroud)

注意:第一次访问时,中间件只运行在服务器端,后续访问时,中间件只运行在客户端。

2)插件方式

由于插件在生命周期的早期运行,我们认为我们会在那里尝试相同的方法并尝试调用 CMS 的 API 并根据结果确定要加载的组件。

插件.js

export default function (context) {
  return new Promise((resolve, reject) => {
  /** 
   * Prepend the cms provided url's path with /content,
   * which the API knows is for CMS content
   */
    context.app.$axios.$get(`/content${context.route.path}`)
      .then((content) => {
        // Save the resulting content to vuex
        context.store.commit('umbraco/load', content)

        const { routes } = context.app.router.options

        /**
         * The content has a contentType property which is a string
         * containing the name of the component we want to load
         * 
         * This finds the corresponding route 
         */
        const wantedRoute = routes.find(x => x.name === content.contentType)

        // Sets the component to load as /Pages/[componentName].vue
        context.route.matched[0].components = {
          default: wantedRoute.component
        }

        resolve()
      })
  })
Run Code Online (Sandbox Code Playgroud)

注意:插件在第一次访问时在服务器和客户端上运行。在后续访问中,它们仅在客户端上运行。

问题

不幸的是,这也不起作用,因为app.router.beforeEach()不允许异步代码。因此,API 请求从未得到解决。

3) 路由映射方法

生成路线图列表工作正常,除非您在构建后更改路线。这里的问题是您无法在运行时更新路由,因此在 CMS 中重命名或添加新内容不会在 Nuxt 中镜像。

4)动态组件方法

这种方法似乎是我们问题的默认解决方案,涉及在 Nuxt 中使用单个 Page 调用 API 然后动态加载组件。不幸的是,这种方法删除了 Nuxt 的大部分页面特定功能(例如页面转换)。

失去这些功能真的很不幸,因为 Nuxt 非常好,我们希望尽可能多地使用它!

Nuxt JS GitHub 问题

  • 我在 nuxt.js GitHub 上提出了失败的异步问题作为这个错误
  • 评论这个 GitHub 问题,这是针对同一问题的功能请求,但围绕该问题进行了一些很好的对话

Tim*_*Yao 2

我们尝试的是使用一个通用页面模板来处理所有可能的路线,代码可以在以下位置找到: https: //github.com/dpc-sdp/ripple/blob/v1.23.1/packages/ripple-nuxt-tide/ lib/module.js#L208

该单页模板将匹配*用户要求的路线。但是,如果您愿意,您可以为多个路由规则定义多个模板。

Nuxt应用程序和CMS API之间的通信如下:

NuxtCMS您好,用户想要路径的数据/about-us

CMS明白了。让我检查 CMS 数据库,并找到相同的 url。如果有的话,我会把数据发回给你,否则我会给你一个404

这样您就不会失去页面转换功能。在该 Nuxt 页面模板中,您可以向 CMS 发送请求并获取页面数据。这可以在 Nuxt 路由器中间件或页面异步数据中完成,现在也许fetchhook 是最好的地方。我不确定哪个是最好的,我们正在使用异步数据,这可能不是最佳实践。