Nuxt Generate won't create repeatable type pages

Running the Generate command with nuxt renders all single type pages but blog post style pages aren't being generated. I'm also not getting any errors.

What's odd is that those pages display correctly if you navigate to them via a listing or by navigating to the full URL. I assume that if the router was broken, I wouldn't be able to navigate to the specific page.

I've been following the discussion here: @nuxtjs/prismic generate not working

In my case the routing still works using either my link-resolver.js or the new routes config.

        // linkResolver: '@/plugins/link-resolver',
        apiOptions: {
            routes: [
                { type: 'resource_item', path: '/resources/:uid' }
            ]
        },
        modern: true

Or in the the link-resolver

    if (doc.type === 'resource_item') {
        return '/resources/' + doc.uid
    }

It seems to me that the generate command isn't able to find these dynamic routes but that the SSR inside Nuxt is working correctly.

Since most of the above discussion took place over a year ago I expect that the discussed migration has been completed. Is this not the case?

Is there something else I can try so these pages generate?

Thanks!

Hi Team,

I'll be happy to help you debug this. Can you give me the URL of your repo so I can see if this is activated on your repo?

Thanks.

Oops sorry just saw this. This is the repo in question acrew-financial.prismic.io

No worries. So I checked it out and this should be available on your repository, can you tell me about the version of @nuxtjs/prismic you are using? Do you have the crawler as a separate plugin?

Do you maybe have a link to your GitHub for this project?

Unfortunately, its not a public repo. (I know that makes this harder sorry)

Package versions:

├── @nuxtjs/axios@5.13.6
├── @nuxtjs/prismic@1.3.1
├── core-js@3.16.3
├── fibers@5.0.0
├── nuxt@2.15.8
├── sass-loader@10.2.0
├── sass@1.38.1
└── vue-gtag@1.16.1

nuxt.config.js

export default {
    target: 'static',

    head: {
        title: 'com.birchcove',
        htmlAttrs: {
            lang: 'en'
        },
        meta: [
            { charset: 'utf-8' },
            { name: 'viewport', content: 'width=device-width, initial-scale=1' },
            { hid: 'description', name: 'description', content: '' },
            { name: 'format-detection', content: 'telephone=no' }
        ],
        link: [
            { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' }
        ]
    },

    css: [
        '@/assets/scss/normalize.scss',
        '@/assets/scss/style.scss'
    ],

    plugins: [],

    components: true,

    buildModules: [
        '@nuxtjs/prismic'
    ],
    prismic: {
        endpoint: 'https://acrew-financial.cdn.prismic.io/api/v2',
        linkResolver: '@/plugins/link-resolver',
        htmlSerializer: '@/plugins/html-serializer',
        apiOptions: {
            routes: [
                { type: 'resource_item', path: '/resources/:uid' }
            ]
        },
        modern: true
    },
    modules: [
        '@nuxtjs/axios',
    ],
    axios: {},
    build: {}
}

link-resolver.js

export default function(doc) {

    if (doc.isBroken) {

        return '/not-found'

    }

    if (doc.type === 'home') {

        return '/'

    }

    if (doc.type === 'about') {

        return '/about'

    }

    if (doc.type === 'services') {

        return '/services'

    }

    if (doc.type === 'why_coaching') {

        return '/why-coaching'

    }

    if (doc.type === 'resources_landing') {

        return '/resources/'

    }

    if (doc.type === 'resource_item') {

        return '/resources/' + doc.uid

    }

    return '/not-found'

}

Based on that other thread I assumed that enabling routes in apiOptions would cause those pages to generate and then didn't need the link resolver.

I can remove the link resolver and the site, including resources, can be navigated from the home page but deep linking doesn't work. If I add the link resolver back in deep linking returns. In either case (with or without link resolver) npm generate only builds the base pages and not anything dynamic.

No problem, we'll try and work with the info we have.

You were right in thinking at the start that the plugin should build pages whether the link is in the linkresolver or route resolver. So there's no need to use both.

I see in your config file you're using axios, which makes me wonder what they queries for your dynamic pages look like, can you share this?

Also is would be interesting to see the pages folder structure in your project.

Thanks.

Looks like Axios isn't used anywhere. My guess is we used the Nuxt app creator and checked that box assuming we'd need it.

Here's the directory structure for pages.

├── about.vue
├── get-started.vue
├── index.vue
├── privacy.vue
├── resources
│   ├── _uid.vue
│   └── index.vue
├── services.vue
└── why-coaching.vue

Here's the _uid.vue page (what's not getting generated). The most complex part is the Open Graph injection into the header...

<template>
  <div id="resource">
    <section id="top" class="header_dark_bg">
      <HeaderAcrew />
    </section>
    <section id="main">
        <h2 class="blog-title">{{ $prismic.asText(pageContent.headline) }}</h2>
        <prismic-rich-text class="content-prime" :field="pageContent.content" />
    </section>
  </div>
</template>

<script>
import HeaderAcrew from '~/components/HeaderAcrew.vue'
export default {
  name: 'resource_item',
  components: {
    HeaderAcrew,
  },
  head () {
    let pageTitle = 'Birch Cove Financial Coaches - ' + this.pageContent.headline[0].text 
    let headerBlock = {
      title: pageTitle,
      meta: [
        { hid: 'og:title', name: 'og:title', content: pageTitle },
        { hid: 'og:type', name: 'og:type', content: 'article'}
      ]
    }
    if(this.pageContent.seo_description) {
      headerBlock.meta.push(
        { hid: 'description', name: 'description', content: this.pageContent.seo_description },
        { hid: 'og:description', name: 'og:description', content: this.pageContent.seo_description }
      )
    }
    if(this.pageContent.seo_keywords) {
      headerBlock.meta.push(
        { hid: 'keywords', name: 'keywords', content: this.pageContent.seo_keywords }
      )
    }
    if(this.pageContent.preview_image && Object.entries(this.pageContent.preview_image).length > 0) {
      headerBlock.meta.push(
        { hid: 'og:image', name: 'og:image', content: this.pageContent.preview_image.url },
        { hid: 'og:image:secure_url', name: 'og:image:secure_url', content: this.pageContent.preview_image.url },
        { hid: 'og:image:width', name: 'og:image:width', content: this.pageContent.preview_image.dimensions.width +'' },
        { hid: 'og:image:height', name: 'og:image:height', content: this.pageContent.preview_image.dimensions.height+'' },
      )
    }
    return headerBlock
  },
  async asyncData({ $prismic, params, error }) {
    try{
      // Query to get post content
      const pageContent = (await $prismic.api.getByUID('resource_item', params.uid)).data
      return {
        pageContent
      }
    } catch (e) {
      error({ statusCode: 404, message: 'Page not found' })
    }
  },

}
</script>

Here's the page that shows the listing

<template>
    <div id="resources">
      <section id="top" :class="'header_' + pageContent.background_color">
        <div class="inner" :style="'background-image: url(' + bgImage + ');'">
          <HeaderAcrew />
          <h2>{{ $prismic.asText(pageContent.title) }}</h2>
        </div>
      </section>
      <section>
        <prismic-rich-text :field="pageContent.content" />
      </section>
      <section id="resourceList" v-if="resources.length !== 0">
          <resourceList class="resourceItem" v-for="r in resources" :key="r.id" :resource="r"></resourceList>
      </section>
    </div>
</template>

<script>
import HeaderAcrew from '~/components/HeaderAcrew.vue'
import resourceList from '~/components/resourceList.vue'

export default {
  name: 'resources-landing',
  components: {
    HeaderAcrew, resourceList
  },
  data: function() {
    return {
    }
  },
  head () {
   ...
    return headerBlock
  },
  async asyncData({ $prismic, error }) {
    try{
      const pageContent = (await $prismic.api.getSingle('resources_landing')).data

      const resources_list = await $prismic.api.query(
        $prismic.predicates.at("document.type", "resource_item"),
        { orderings : '[document.first_publication_date desc]' }
      )

      return {
        pageContent,
        resources: resources_list.results,
        bgImage: pageContent.header_image.url,
      }
    } catch (e) {
      error({ statusCode: 404, message: 'Page not found' })
    }
  },
  methods: {
    
  }
}
</script>

So looking back at your first message you said you can go directly to the page URL, so it means it's being generated. From reading again it sounds more like your links to these repeatable types are broken. Is this also this case in development mode? i.e. npm run dev

Can you replace what you have in the link resolver with:

  if (doc.type === 'resource_item') {
    return `/resources/${doc.uid}`
  }

Let me know how this goes.

Thanks.

As long as the link resolver is active, I can navigate to any of the /resource/page directly. I can do that in either dev mode or after the site is generated.

However even after updating the link-resolver I still don't seem to be getting the pages to actually generate. I wouldn't care but social media campaigns are going directly to these pages and they generate a 404 to the spiders (I assume they're not loading the main page and then using the link resolver's route)

Here's the output from npm generate

ℹ Full static generation activated                                    11:52:46
ℹ Generating output directory: dist/                                  11:52:46
ℹ Generating pages with full static mode                              11:52:46
✔ Generated route "/preview"                                          11:52:46
✔ Generated route "/why-coaching"                                     11:52:47
✔ Generated route "/"                                                 11:52:47
✔ Generated route "/resources"                                        11:52:47
✔ Generated route "/privacy"                                          11:52:47
✔ Generated route "/services"                                         11:52:47
✔ Generated route "/about"                                            11:52:47
✔ Generated route "/get-started"                                      11:52:47
✔ Client-side fallback created: 200.html                              11:52:47
✔ Static manifest generated                                           11:52:47

I would expect to see the /resource/pages in there. Am I wrong in that assumption?

Here's the dist directory after running generate:

├── 200.html
├── _nuxt
│   ├── 01a38ac.js
│   ├── 2b27654.js
│   ├── 46c21aa.js
│   ├── 4a6c509.js
│   ├── 711c0b3.js
│   ├── 7626921.js
│   ├── 9808ab6.js
│   ├── a58a88c.js
│   ├── b192cb5.js
│   ├── c2d6e26.js
│   ├── c65c502.js
│   ├── ce7d104.js
│   ├── d65136c.js
│   ├── d7f495c.js
│   ├── fcc3679.js
│   └── static
│       └── 1631033566
│           ├── about
│           │   ├── payload.js
│           │   └── state.js
│           ├── get-started
│           │   ├── payload.js
│           │   └── state.js
│           ├── manifest.js
│           ├── payload.js
│           ├── preview
│           │   ├── payload.js
│           │   └── state.js
│           ├── privacy
│           │   ├── payload.js
│           │   └── state.js
│           ├── resources
│           │   ├── payload.js
│           │   └── state.js
│           ├── services
│           │   ├── payload.js
│           │   └── state.js
│           ├── state.js
│           └── why-coaching
│               ├── payload.js
│               └── state.js
├── about
│   └── index.html
├── favicon-16x16.png
├── favicon-32x32.png
├── favicon.ico
├── get-started
│   └── index.html
├── images
│   └── social_preview.png
├── index.html
├── preview
│   └── index.html
├── privacy
│   └── index.html
├── resources
│   └── index.html
├── services
│   └── index.html
├── site.webmanifest
└── why-coaching
    └── index.html

Am I correct in assuming that setting Prismic.apiOptions.routes in the Nuxt.config.js is supposed to replace the Nuxt dynamic routes setup defined here: The generate Property - NuxtJS ?

Should I try rewriting the api call directly in the Nuxt Generate config?

I finally solved the problem. Setting "modern" to true seemed like a good idea but it was breaking the Nuxt crawler...

prismic: {
        endpoint: 'https://acrew-financial.cdn.prismic.io/api/v2',
        linkResolver: '@/plugins/link-resolver',
        htmlSerializer: '@/plugins/html-serializer',
        apiOptions: {
            routes: [
                { type: 'resource_item', path: '/resources/:uid' }
            ]
        }
        // modern: true
    },

This is what lead me there in the first place Configuration - @nuxtjs/prismic

Cool, I'm glad you figured this out. I had never seen this modern attribute before.

For future reference, the Prismic route resolver is an advanced link resolver used for building 2 level nested URLS using Content Relationships.

Thanks for all the help @Phil! According to the documentation modern = true disables the Prismic link crawler in favor of the one that ships with Nuxt. However... the Nuxt crawler doesn't handle dynamic content unless explicitly told to do so.

This might be a good point for the Prismic documentation.

1 Like

Yeah, I think so. I'll add it to our backlog.

1 Like

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.