nuxt / rfcs

RFCs for changes to Nuxt.js
96 stars 2 forks source link

Full static generated mode #22

Closed manniL closed 3 years ago

manniL commented 5 years ago

Current state

Nuxt's Static Site Generator (nuxt generate) is growing! I love the static mode when it comes to portfolio pages (or generally, pages that don't include a lot of dynamic data).

Problem

Usually, you use statically generated pages together with a Headless CMS or another external API.

Currently, you can generate the HTML (with static + universal mode) but asyncData calls are still made during client-side navigation, which means that an external API will likely be called on such a static page.

While it's worth here and there to make these calls even after static generation, it's absolutely not needed (from my POV) for the majority of the pages. Instead, the author/developer could simply issue another build (eg. through Netlify) to update the content.

Also you might encounter different content as asyncData is not called on the entry route of you static app. (Going from /b to /a can lead to different content than directly accessing /a)

Proposal

As announced by @Atinux on Vue Toronto (see his talk at 26:18), I want to propose the full static generation option for nuxt generate.

Instead of relying on the API calls, we should inline the response of the asyncData method(s) inside a .json file (per page) when the generate.fullStatic flag is enabled in the nuxt.config.js (the flag name is debatable). Then we can use the .json file as data source without issues.

Related issues

https://github.com/nuxt/nuxt.js/issues/4607

3rd party modules that apply this approach

https://github.com/DreaMinder/nuxt-payload-extractor https://github.com/stursby/nuxt-static/

Andras1000 commented 4 years ago

In case this helps anyone, I've had a Vue.js app (without Nuxt.js) and used the following solution.

bdadam commented 4 years ago

I think this issue would still be very important to solve. I miss the possibility of "fully static" generated code. I just wanted to make sure that everyone has seen what the main competitor (Next.js) is doing now.

In Next.js from components we can now export two new async functions: getStaticProps and getStaticPaths. These functions are only called during static generation/on the server side. Please check them out, maybe it would be a viable way to go for Nuxt as well.

dswmedia commented 4 years ago

I'd like to see this implemented too. Fully static generated first response would help with speed

locopati commented 4 years ago

I am looking for a solution to this for an app that uses vue-apollo to pull data from Strapi CMS. The app is deployed as a static site. What I'm noticing is that the first request to display the page fails but the a reload works because the data is in the page.

My temporary ugly solution is to force that reload in an error handler...

error: function(error, vm) {
          let loc = vm?.$el?.ownerDocument?.location;
          if(loc?.hostname !== "localhost") {
            loc?.reload();
          }
        }

However, I also noticed that if I simply remove id="__nuxt" from the main container div, the page just renders with all the data the generate placed in the page instead of trying to use vue-apollo to setup the data, failing, and rendering no data. I suspect if I understand better how these components interact and the order of events, I could see how it would be possible to use vue-apollo locally to populate the page and use nuxt/vue-clientside to load the page in a way that ignores the dynamism and just uses the data already in the page.

Is it possible via some hook to not emit that id in the generated pages and thus populate the page while allowing it to render statically? Or some other approach I'm not seeing (that doesn't involve storing json locally)? If anyone has any ideas, I'd love to hear them - I don't know enough about nuxt/vue/apollo to understand exactly how to accomplish what I want.

kfrederix commented 4 years ago

Not sure if this is the right place to ask, but I was wondering. What about images (or assets in general) which are stored in a headless CMS? I think it would be interesting if we had an option to automatically dowload and store files which are referred to from the output of nuxt generate. So that not only api calls, but also targetted files would become fully static and we would really eliminate all dependencies to the CMS once the site is generated. Any thoughts on this? Or is this already possible maybe with another module I'm not aware of?

robertpiosik commented 4 years ago

@kfrederix from my experience, with such ideas as yours its good to think about the problem in scale. Imagine you're doing what you've explained having hundreads or thousands of pages. You would basically end up moving a lot of data from one place to another over and over again - and that data wouldn't change from deploy to deploy what obviously makes this approach rather unfortunate.

mornir commented 4 years ago

I think it can make sense in some situations. There's a plugin like that for Gatsby with the headless CMS Sanity: https://www.gatsbyjs.org/packages/gatsby-source-sanity-transform-images/

emiliobondioli commented 4 years ago

@kfrederix I am experimenting with nuxt static generation to allow something like what you describe, a static website generated from an headless CMS without the need of API calls or remote resources from the cms. To save the cms assets (only images right now) I've written a small build-only module which runs on the generate:page hook to scan the page's html through a regex, download and store all image assets coming from the cms in the dist folder and replace the remote paths with local ones.

I'm not sure it's the correct way to do things in nuxt and as @robertpiosik said it's not really a scalable approach but for a small website without frequent updates it seems to be working fine! To reduce moving data one could avoid downloading some images if these are already present locally.

kfrederix commented 4 years ago

@robertpiosik you are certainly right, but that's why I mentioned "having an option". I guess in some situations this won't make sense while in other situations it can make a lot of sense... I'm definitely not advocating to have this behaviour by default but I think this could be a very useful option for certain situations. Anyway, this might be out of scope for the full static feature... @emiliobondioli would you mind sharing your build-only module?

robertpiosik commented 4 years ago

@emiliobondioli is your work available somewhere? I would like to look into it.

@kfrederix The more I think about this idea, the more I like it! Completely independent static app build is a key point here. Very useful for pull request previews, where a CMS, the app is build upon runs locally (and is fulfilled by locally managed dummy assets). Even for proper production deployments I can see now this idea being fully reasonable.

emiliobondioli commented 4 years ago

Sure! since the repo where I'm using this is private, I've put it in a gist: https://gist.github.com/emiliobondioli/5ce8ece783e7256fc7530738a2968ea9

It's still quite raw and I'd like to make it work better together with nuxt, but as a proof of concept it seems to be working :)

Atinux commented 4 years ago

Thank you for your comments and idea. I do believe this is related to a component support the full static mode to export external resources as well :)

jmheretik commented 4 years ago

hey @robertpiosik. I also attempted to do something similar if you want to look into it. i scrape all the html of pages in my routes to look for img tags, download them, and modify the img srcs to point to the locally downloaded copies

https://github.com/jmheretik/kirby-vue-starterkit/blob/master/vue-nuxt/modules/kirby-scraper.js#L23

and here is the generated demo hosted in gh-pages to confirm it works :) https://jmheretik.github.io/kirby-vue-starterkit/

Atinux commented 4 years ago

Thank you @jmheretik, we are doing a system with @pi0 to make it easier to have a static assets folder. BTW the demo is beautiful!

manniL commented 4 years ago

Full static mode landed on nuxt-edge.

https://github.com/nuxt/nuxt.js/pull/6159

noname202 commented 4 years ago

Have you thought about implementing more granular data fetching simmilar to what the Next.js project recently intorduced with the getStaticProps and getServerSideProbs functions. In my opinion it would be very benificial to allow mixing static and dynamic pages. Furthermore I really like the idea of being able to only fetch data on the server side as this would allow for a whole range of new use cases such as the use of internal headless CMS systems not accessible to the public.