How Pages Work in Nuxt.js

Follow

We believe that Editors  (you know, the folks actually creating content) should have full control over their website pages and not rely on a developer.

The @agility/agilitycms-nuxt-module makes it easy to source content, but it also assists with generating your Pages for you based on your sitemap in Agility CMS.

This means that editors in the CMS control what pages are available, what their URLs are, and exactly what UI components (we call these Page Modules) make up each page.

The Secret Sauce...

Each Agility CMS page is composed and generated dynamically at build-time using an AgilityPage template that you define in your nuxt.config.js file via the agilitycms config object.

Page Generation

The following example is based on the Blog Template instance. Don't have one? Sign up for one!

Screen_Shot_2021-04-20_at_10.05.16_AM.png

The above figure represents a sitemap of Pages as well as the UI Components (Page Modules) that are on each page - all are managed in the CMS. 

This means that when a build occurs in your Nuxt site, the following pages will be auto-generated for you:

  • /
  • /blog
  • /blog-posts/* - your dynamic page route for all of your blog posts (i.e. /blog/my-first-post)
  • /about

Page Rendering

When a Page is being generated, the final step is rendering the page to HTML. The agilitycms-nuxtjs-starter does this by using the AgilityPage.vue component that is configured in the nuxt.config.js file. This component takes care of generating pages based on your Sitemap in Agility, determines which Page Template to render, and handles your SEO properties.

Nuxt.config.js:

export default {
  target: "static",
  components: true,
  generate: { fallback: "404.html" },
  modules: [
    "@nuxtjs/tailwindcss",
    "@agility/agilitycms-nuxt-module",
  ],
  agilitycms: {
    channelName: "website",
    languages: ["en-us"],
    includeLanguageCodeInUrl: false,
    pageComponentPath: "src/AgilityPage.vue",
  },
  ...
};

AgilityPage.vue:

<template>
  <div
    v-if="statusCode !== 200"
    class="max-w-screen-xl mx-auto p-4 sm:p-6 lg:p-6"
  >
    <div class="my-6 max-w-full">
      <div v-if="message">{{ message }}</div>
      <div v-else>The page could not be found, or an error occurred.</div>
    </div>
  </div>
  <div v-else>
    <component
      :is="componentToRender"
      :page="page"
      :pageInSitemap="pageInSitemap"
      :dynamicPageItem="dynamicPageItem"
      :moduleData="moduleData"
    />
  </div>
</template>

<script>
import AgilityComponents from "./agility.components";

export default {
  data() {
    return {
      pageInSitemap: { title: "" },
      page: { title: "", seo: { metaDescription: "", keywords: "" } },
      dynamicPageItem: null,
      moduleData: {},
      message: null,
      statusCode: 0,
    };
  },
  computed: {
    componentToRender: function() {
      const component =
        AgilityComponents.pageTemplateComponents[this.page.templateName];
      return component;
    },
  },
  mounted: function() {},
  head() {
    return {
      title: `${this.pageInSitemap.title} | My Travel Blog`,
      meta: [
        {
          hid: "generator",
          name: "generator",
          content: "Agility CMS",
        },
        {
          hid: "agility_timestamp",
          name: "agility_timestamp",
          content: new Date().toLocaleString(),
        },
        {
          hid: "viewport",
          name: "viewport",
          content: "initial-scale=1.0, width=device-width",
        },
        {
          hid: "description",
          name: "description",
          content: this.page.seo.metaDescription,
        },
        {
          hid: "keywords",
          name: "keywords",
          content: this.page.seo.metaKeywords,
        },
      ],
    };
  },

  async asyncData(context) {
    if (process.server) {
      const {
        app,
        store,
        route,
        params,
        query,
        env,
        isDev,
        isHMR,
        redirect,
        error,
        $config,
        $agility,
      } = context;

      try {
        let slug = params.pathMatch;
        if (slug == "/") slug = "";

        if (slug.length > 1 && slug.lastIndexOf("/") == slug.length - 1) {
          slug = slug.substring(0, slug.length - 1);
        }

        let languageCode = $agility.languages[0];

        const sitemap = await $agility.client.getSitemapFlat({
          channelName: $agility.channelName,
          languageCode,
        });

        const path = `${slug}` || Object.keys(sitemap)[0];
        let pageInSitemap = sitemap[path];

        if (!pageInSitemap) {
          const message = `Page not found on sitemap in ${languageCode}.`;
          error({ statusCode: 404, message });
          return { statusCode: 404, message };
        }

        let page =
          (await $agility.client.getPage({
            pageID: pageInSitemap.pageID,
            languageCode: languageCode,
          })) || null;

        if (!page) {
          const message = `Page not found in ${languageCode}.`;
          error({ statusCode: 404, message });
          return { statusCode: 404, message };
        }

        let dynamicPageItem = null;

        if (pageInSitemap.contentID > 0) {
          dynamicPageItem = await $agility.client.getContentItem({
            contentID: pageInSitemap.contentID,
            languageCode: languageCode,
          });
        }

        let moduleData = {};
        //load extra data

        for (let zoneName in page.zones) {
          let zone = page.zones[zoneName];
          for (let moduleIndex = 0; moduleIndex < zone.length; moduleIndex++) {
            let module = zone[moduleIndex];
            const moduleName = module.module;

            //try to find a data accessor for this module name...
            const fetcher = AgilityComponents.dataFetch[moduleName];
            if (fetcher) {
              moduleData[moduleName] = await fetcher({ $agility });
            }
          }
        }

        return {
          pageInSitemap,
          page,
          dynamicPageItem,
          moduleData,
          message: null,
          statusCode: 200,
        };
      } catch (err) {
        console.error(err);
        error({ statusCode: 500, message: `Error occurred on server.` });
        return { statusCode: 500, message: `Error occurred on server.` };
      }
    }
  },
};
</script>
1 out of 1 found this helpful

Comments

0 comments

Please sign in to leave a comment.