Nuxt.js: Add an option to nuxt generate to generate a single route

Created on 26 Jul 2019  ยท  43Comments  ยท  Source: nuxt/nuxt.js

What problem does this feature solve?

Example use case:
A static generated app with thousands of routes, like an e-commerce having a route for each product.
Apart from scheduling nuxt generate to run periodically and generate all static and dynamic routes, it would be nice to have the possibility to generate the static files for a single route, for example in a hook when the related backend item is updated.

In a situation where there's a high frequency of updates, re-generating all the dynamic routes every time there's an update to a single one is not really efficient. This way, for every update, just the interested route is re-generated and replaces the previous one (if present).

What does the proposed changes look like?

Update the nuxt generate command to accept a -r or --routes option, for example:
nuxt generate --no-build -r /products/42

This feature request is available on Nuxt community (#c9562)
feature-request good first issue

Most helpful comment

Much easier to just manage your dist folder a bit, no need to change anything in nuxt for that:

$ yarn generate
$ rsync -auv dist/* production-build/
$ yarn generate --no-build -r /single/route
$ rsync -auv dist/* production-build/

and to start over:

$ rm production-build/* -Rf

All 43 comments

You could already implement this yourself in nuxt.config.js as follows:

  generate: {
    routes() {
      const rIdx = process.argv.indexOf('-r')
      if (rIdx) { // it will never be 0 as that would be the node/nuxt command
        return [
          process.argv[rIdx + 1]
        ]
      }
      // return default / all routes
    }
}

Nice solution, thanks! But I tried it now and even using the --no-build flag this still removes all the other generated pages, leaving only the new one.

Looking around, it looks like I'd need a way to set the init option in cli-generate to false, would this cause any issue if it was false only when generating single routes?

Hi ! I'm also facing this issue right now while making a blog. I will have a growing number of pages and doing the nuxt generate will take more and more time. Hope to find a solution as soon as possible !

Much easier to just manage your dist folder a bit, no need to change anything in nuxt for that:

$ yarn generate
$ rsync -auv dist/* production-build/
$ yarn generate --no-build -r /single/route
$ rsync -auv dist/* production-build/

and to start over:

$ rm production-build/* -Rf

Ok that seems like a good workaround! so you think having this built into nuxt would be useless/out of scope?

I think it'd be a good fit for static generation :relaxed:

About full static mode, re-generating a single route might be difficult for the payload hash @manniL ๐Ÿค”

@Atinux damn, thats right :see_no_evil:

@Atinux @manniL did you ever find a way of handling the payload hash? ๐Ÿค”

Yes, you want to look at the target PR :)

Would love this as well. It doesn't work quite well now, as when people edit one page in the CMS whole site has to be regenerated which takes around 2000 seconds.

Having the same trouble with my project, I have a products page and a details page which is dynamic, If I access it by products page and then refresh, it throws 404 in production. I've done the process with npm run generate.

We are looking to archive the same goal for our full static project when generating dynamic routes. We want to avoid regenerating the whole website for specific changes / addition made in the content.

Next.js offer a very interesting incremental static generation :

https://reactions-demo.now.sh/
https://nextjs.org/docs/basic-features/data-fetching#incremental-static-regeneration

How could we archive the same ?

This could be done with some code in your config. With Nuxt full static the site won't be rebuilt, and you can turn off the crawler and just specify a smaller set of URLs in the generate options.

This could be done with some code in your config. With Nuxt full static the site won't be rebuilt, and you can turn off the crawler and just specify a smaller set of URLs in the generate options.

Thanks for your reply. Unfortunately, when generating a smaller subset of routes. The other routes are removed from the /dist folder, thus when syncing to my external static storage, they are deleted too. I tried using the generate.exclude property for excluding the pages that have not been modified, although their payload and html are still generated.

Still looking for a way to customize which pages are generated or not depending on payload of dynamic routes.

Just to be sure. The "good way" would be to yarn generate --no-build -r /single/route? (using target: 'static') and compare it with ou current static gen website?

@f3ltron without knowing @wlarch exact scenario, I would say yes, but even then, I wouldn't worry about the comparison, just the build/generate part.

A use case would be a CMS, where a content editor would "publish" a piece of content, and then trigger a webhook that would generate that specific route.

Got the very same problem: What if you have a site with about 5.000 posts but you change only the content of one of them?

Therefore, it would be useful to have an option, just as @hesselberg has described.

@hesselberg This is exactly what we have though. We maintain a CMS that allow the creation and modification of content. Any action on the content would trigger a webhook for generating a specific single page or set of pages. The generate files would then be uploaded to the static hosting.

I've found this approach: https://github.com/hanbyul-here/nuxt-incremental-build-exp

In local dev mode it works fine, however if I use it on Netlify, deploying fails.

yarn generate --no-build -r /single/about.vue is not really working no ?

no matter what I am doing it just generate everything

yarn run v1.22.4
$ nuxt generate --no-build -r pages/about.vue
โœ” Skipping webpack build as no changes detected                                                                                                                                                                                                                                                                                                                   
โ„น Generating output directory: dist/                                                                                                                                                                                                                                                                                                                              
โ„น Generating pages with full static mode                                                                                                                                                                                                                                                                                                                          
โœ” Generated route "/"                                                                                                                                                                                                                                                                                                                                             
โœ” Generated route "/about"                                                                                                                                                                                                                                                                                                                                        
โœ” Generated route "/test"                                                                                                                                                                                                                                                                                                                                         
โœ” Client-side fallback created: 200.html

As we know static gen cache node_modules. Base on that: https://nuxtjs.org/blog/nuxt-static-improvements#introduction

  • we should have something when the code is push on github then cache again node modules. with the build.json infos nuxt generate will generate only files who changed.
  • when cms or whatever update a page send a webhook that just nuxt generate only [pages]

I am trying things

I think I understood what you wanted no?

Hi there,

Sharing my progress in this investigation has nuxt generate -r <route> doesn't seem to work for me.

It seems to be at Node level but I'm not experiencing that error with any other command than generate with -r.

For demonstration purpose, I've tried running it on nuxt/nuxtjs.org repo.

Reproduction tests:

โฏ git clone [email protected]:nuxt/nuxtjs.org.git
โฏ npm i
โฏ npm run generate
โฏ npm run generate --no-build -r /blog/seed-round

npm run generate works smoothly. However, trying to apply it to a specific route (_ie. /blog/seed-round_) leads to this error:

โฏ npm run generate -r /blog/seed-round
> [email protected] generate /Users/XXX/projects/nuxtjs.org
> nuxt generate "/blog/seed-round"
 FATAL  EROFS: read-only file system, mkdir '/blog'                                                        

   โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
   โ”‚                                                        โ”‚
   โ”‚   โœ– Nuxt Fatal Error                                   โ”‚
   โ”‚                                                        โ”‚
   โ”‚   Error: EROFS: read-only file system, mkdir '/blog'   โ”‚
   โ”‚                                                        โ”‚
   โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] generate: `nuxt generate "/blog/seed-round"`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] generate script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/XXX/.npm/_logs/2020-09-15T13_34_26_002Z-debug.log

I've also tried deleting dist folder, omitting --no-build arg on generate in vain.

Last, using yarn, I'm getting the same issue as @f3ltron.

When I fire yarn generate --no-build -r /georg-jensen-diamonds-and-gold-halo-earhoops-23-mm it seems to generate all the other routes too. Even the routes inside /pages/About.vue, etc.

Also the specific route I've set to generate (.e.g georg-jensen-diamonds-and-gold-halo-earhoops-23-mm) does not get generated.

What am I missing?

@griable, @simplenotezy and @f3ltron, did you edit your nuxt config? AFAIK the option to generate a single route hasn't been added yet, but you can get a similar behavior with some edits to your nuxt.config and build scripts, I'll just add below the full process as described by @pimlie :

You can get the -r arg and use it in the generate section of your nuxt.config.js:

generate: {
  routes() {
    const rIdx = process.argv.indexOf('-r')
    if (rIdx > -1) { // it will never be 0 as that would be the node/nuxt command
      return [
        process.argv[rIdx + 1]
      ]
    }
    // return default / all routes
  }
}

This will allow the generation of a single route like this nuxt generate --no-build -r /posts/12, but as said above the generate command empties the dist folder before generation so you'll end up with just the single generated route file. What I did in my setup was using 2 different folders for build and deploy and syncing the contents of the two using rsync:

In my package.json i have a generate script:

$ nuxt generate
$ rsync -auv dist/* public/
````
and a `generate:single` script:

$ nuxt generate --no-build -r
$ rsync -auv dist/* public/
``` Which i can call like this:npm run generate:single /posts/12`
So that files are generated in the dist folder and then moved to the public folder, which I can then deploy.

@emiliobondioli thats cool! Thanks for sharing. How would we go about to add multiple routes to -R? Is that supported?

Also this leads me into thinking; we could simply send a GET request to backend to determine what routes have changed and only generate those routes, EXCEPT, If Nuxt had to rebuild config (eg after JavaScript/component has changed). Is there a parameter to check if JS has changed / or if the rebuild was triggered during Nuxt generate?

It doesn't break the hash on other files ? For old files @emiliobondioli

@f3ltron I guess not, as long as nuxt haven't been rebuilt (yarn nuxt build), as that is the script setting file hashes.

Oh yeah you right I will try it soon thanks for your work

Thank @emiliobondioli ;) Also; I still need to figure out some what to check if build was rebuilt or not, because, if build was rebuilt, you'd have to do a complete deploy with all routes.

@emiliobondioli thats cool! Thanks for sharing. How would we go about to add multiple routes to -R? Is that supported?

As a simple workaround you could call it like this:

npm run generate:single "/route/1 /route/2"

And edit the generate section of your nuxt config to split the incoming string on every space character (or on every comma if you prefer):

  routes() {
    const rIdx = process.argv.indexOf('-r')
    if (rIdx) { // it will never be 0 as that would be the node/nuxt command
      return process.argv[rIdx + 1].trim().split(' ') // splits the incoming string to get the single routes
    }
    // return default / all routes
  }

Also this leads me into thinking; we could simply send a GET request to backend to determine what routes have changed and only generate those routes, EXCEPT, If Nuxt had to rebuild config (eg after JavaScript/component has changed). Is there a parameter to check if JS has changed / or if the rebuild was triggered during Nuxt generate?

The way I'm using it is kind of the opposite: I have a headless Wordpress backend with some hooks set up when new posts are created or updated which run the generate:single script to generate the route for the new/updated post.
This doesn't really require any rebuilding of nuxt core files and static routes. Whenever I deploy a new version of the frontend, I just empty the public folder and run a full generate.

I think it would've possible to make it as a module here

@emiliobondioli that's interesting. Can you elaborate a bit on how you do the "generate:single"?

generate:single is just another script in my package.json which I use as an alias to nuxt generate --no-build -r.
I have a deploy_single.sh file which I call through php on wordpress hooks which contains the full generate and update logic:

npm run generate:single "$1"
rsync -auv dist/* public/

thanks @emiliobondioli

Just wanted to update and say that I have made an awesome build process using @emiliobondioli's suggestion in Jenkins.

Site can now be deployed incrementally or "fully", as well as running end-to-end tests using Cypress. If doing an incremental build, instead of passing the routes to generate, an API call will be made to query the backend for any changes that has happen since a given date, and then return those routes along with their payload.

A little update/question. Perhaps you know the answer @emiliobondioli. Is it possible to set the "exclude" property inside the generate.routes function? E.g. if I am running an incremental build, then exclude all routes, except the ones coming from the generate.routes array?

I am asking because when having to build just a single route, or two, it's pointless to generate all the other default routes in my app, such as /my-account/ etc.

I tried with:

const sinceParam = process.argv.indexOf('-after');
if (sinceParam && sinceParam > -1) {
this.default.generate.exclude = ['*']; 
}

But that doesn't seem to get respect that far into the process. Any ideas?

Good night ;)

@simplenotezy I don't think it's possible to exclude the static routes inside generate.routes, but you can do it using the generate:extendRoutes hook documented here.

  this.nuxt.hook('generate:extendRoutes', routes => {
    const routesArg = process.argv.indexOf('-r');
    if (routesArg > -1) routes.length = 0
  })

note that in this hook you have to actually modify the routes array, you can't just return [], that's why I'm emptying it by setting its length to 0

Thanks @emiliobondioli and where would I go an run the extendRoutes? Missing the whole picture here ๐Ÿ˜Š

I have implemented @emiliobondioli solution to modify the routes array using the generate:extendRoutes hook this way in nux.config :

 hooks: {
    generate: {
      extendRoutes(routes) {
        const routesArg = process.argv.indexOf('-r')
        if (routesArg > -1) routes.length = 0
      }
    }
  }

Although I realize this completely empties the routes array and does not only exclude the static ones.
I am trying a few things and I will update this thread after a few tests.

EDIT : (removed my previous question as it was irrelevant, I made a mistake in my payload)

It seems I found a problem regarding the process explained in this thread. The timestamp generated on an incremental build causes a problem when directly loading a page that was generated in a subsequent build.

Exemple :

  1. yarn generate
  2. rsync -avzr dist/* public/
  3. yarn generate:single /fr/demo/api
  4. rsync -avzr dist/* public/

The second generation will create static assets in a different timestamps (version) of the app in the dist/ _nuxt/_nuxt/static/ folder. When loading a page from the first build all payloads are loading correctly. When loading /fr/demo/api page all payloads from the first build are not loaded correctly and the app needs to make an API call instead.

Changing the following parameter in nuxt.config.js seems to resolve the issue :

generate: {
    staticAssets: {
      version: 'prod' // Will overwrite the timestamp used in static asset versionnioning
    }
  }

What is your though on this ?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

mattdharmon picture mattdharmon  ยท  3Comments

msudgh picture msudgh  ยท  3Comments

vadimsg picture vadimsg  ยท  3Comments

maicong picture maicong  ยท  3Comments

bimohxh picture bimohxh  ยท  3Comments