https://github.com/dinerojs/dinerojs.com
nuxt generate
or yarn generate
._nuxt
directory and see the generated JavaScript files.When pre-rendering my website with nuxt generate
, I would expect my HTML to be pre-rendered and for all the JavaScript that's used for this purpose not to be in the final build.
In fewer words, I would expect the only JavaScript that ends up in the final build to be the one that's necessary for runtime, nothing else.
Pre-rendering the website fills the _nuxt
directory with unnecessary and heavy JavaScript. The HTML files are appropriately rendered, but the built JavaScript contains unnecessary things like the Markdown parser, Highlight.js, Nuxt store, etc.
Another side effect of getting all that development JavaScript in the production build is that it tries to apply build-time logic at runtime (e.g., determining what sidebar item is active to open the right parent, doesn't work because trying to determine this from this.$route
).
I'm not sure how to tell Nuxt how to differentiate what I'll need in my final bundle (e.g., code to handle collapsing menus) and what is only there for generation of HTML. I couldn't find it in the documentation.
There are some closed tickets on these topics (e.g., https://github.com/nuxt/nuxt.js/issues/2822) but they only offer hacky and incomplete workarounds. Using Cheerio to strip out unwanted generated code doesn't address the real issue (code that shouldn't be there in the first place), adds CI time, and doesn't account for the JavaScript that you do need to keep.
Thanks a lot in advance for your help! Been enjoying using Nuxt and this is likely the final hurdle before I can push my project live. 馃檪
client side scripts need to be there because on client vue need to do rehydration of your data.
Also look here https://github.com/nuxt/rfcs/issues/22
@aldarund Sorry but I'm not sure I understand. I fetch the data upon generation of the build (which is precisely why Nuxt needs me to expose the dynamic ones in nuxt.config.js
) and it ends up being hardcoded in the HTML files (as expected). Why would Vue need to rehydrate?
When I serve the built website and disable JavaScript, it works as expected (apart from the JavaScript that I need at runtime of course). I understand that these scripts are needed for SPA mode and SSR mode, but not for pre-rendering mode, which goal is to render everything beforehand, at build time, and not rely on JavaScript to do so.
Hi. You can try https://github.com/maoberlehner/vue-lazy-hydration and pass ssr-only prop. For rendering only on server side, without hydration and loading component on client side.
It helps me ;)
@dschewchenko Hi and thanks for the suggestion! However this seems to be for SSR, and I'm not using it (I'm pre-rendering with the intent of serving pre-generated, purely static files).
Also, it seems odd that this doesn't come included with Nuxt 馃 The Nuxt documentation has a dedicated "Static Generated (Pre Rendering)" section which says "When building your application, it will generate the HTML for every one of your routes and store it in a file." This is why I've decided to go with Nuxt, because static site generation is exactly what I need.
It also has an ad to this VueSchool course that says "Prerendering or static site generation is an invaluable technique that every front-end developer should know. Compiling your application into static HTML files is a process that improves both performance and SEO." or again "Prerendering is not the same as server-side rendering." When watching the first video "What is Prerendering?", it clearly states "pre-rendering, as the term implies, means that an application is rendered or generated upfront [...] What happens, is that the application is rendered in static HTML files [...] This way you can eliminate the hosting costs, and benefit from SEO and super fast page load." so it seems clear that my vision of pre-rendering is aligned with what Nuxt advertises. This is why I'm confused.
Is the pre-rendering mode unfinished? Is what's advertised different from the final product? Is it a bug? Or do I totally get what's being said wrong? No problem in any case, but it would be awesome to get an answer so I can move forward with my own project and make the appropriate technical choices. 馃檪
Generate is already SSR , but only once. It works. You can PR to nuxt.js to add same option for components
Hey @sarahdayan :wave:
I'm using nuxt generate
in a bunch of projects, so let me try to clear up the situation :relaxed:
https://twitter.com/nuxt_js/status/1098358432984375296
(as @dschewchenko said)
When you use nuxt generate
together with the universal
mode (default) you will receive static HTML files as planned. Of course you still have javascript included because your static Nuxt/Vue app will still behave like an SPA after the initial request to get the "best of both worlds". That's what the extra JS is for, similar to the (dynamic) SSR/universal mode.
nuxt generate
works as expected. There is only one larger caveat which will be resolved through https://github.com/nuxt/rfcs/issues/22
Hope that helps :relaxed:
Hey @manniL, thanks for the reply.
About the link between SSR and SSG, yes, I agree and it's clear to me. The reason why I insisted against it was that Nuxt has them as two separate modes, and it sounded odd to me to use a module for behavior A so I can achieve something with behavior B that (I think) it should handle on its own. But let's not dwell on semantics 馃槄
From your explanation, I understand that my understanding of static site generation is different from what Nuxt implies (at least for now). My experience comes from static website generators like Jekyll or Middleman, which outputs fully static websites, meaning that the data fetching is fully taken care of at build time and any data updates requires another build. If I'm not mistaken, I think that's also how Gatsby works.
I think making nuxt generate
fully static (or creating a new mode as #22 seems to be implying) would be awesome, but in the meantime, it would be really great to clarify the documentation. From what I've seen I'm not the only one who got confused. If Nuxt doesn't (yet) behave as most static website generators, this is something you want to know as soon as possible.
Thanks again for clarifying this, and good luck! Can't wait to see full static mode come to life 馃檪
@manniL Do you have recommendations to circumvent the issue in the meantime?
@sarahdayan No problem!
Yes, https://github.com/nuxt/rfcs/issues/22 is how every other static site generator works/should work and will be tightly coupled to nuxt generate
(through a feature flag I'd guess) and likely default for nuxt generate
in Nuxt 3.
You can use https://github.com/DreaMinder/nuxt-payload-extractor in the meantime to achieve a similar result (as mentioned in the RFC too) :+1:
Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:
Issues that are labeled as 馃晲Pending
will not be automatically marked as stale.
@manniL Thanks for this. I've tried https://github.com/DreaMinder/nuxt-payload-extractor, unfortunately this only applies to asyncData
, therefore only partly solves the issue. A lot of JavaScript still gets shipped to the final build, because content still needs to be fetched from these JSON files.
What I'm looking for is to use JavaScript for content generation, and get rid of as much as possible upon build. I only need light runtime scripts, such as event handlers for clicks on accordion menus. I do not need highlight.js, since my code snippets are already tokenized in the HTML. I do not need JavaScript-powered routing, I'm fine with traditional, web-server powered routing. I do not need asyncData
to exist at all, since my HTML pages are here and well already.
I don't know if nuxt/rfcs#22 is going this route. I've read the thread but it seems that the purpose is mostly to move the content that asyncData
requests to static files, and read from those with JavaScript. Am I reading this incorrectly?
Thanks again for the conversation, trying to dig as deep as I can on this issue to make sure I understand everything 馃檪
@sarahdayan Unfortunately it is not possible to partially extract and include some javascript functionalities like an accordion. We have to possibilities:
highlight.js
to be running on SSR only. Can be a little tricky and variable based on plugin and usage.@pi0 I hear you. Curious though, why isn't it possible to extract runtime scripts?
I guess an alternative could be to have a place where to write runtime JavaScript (vanilla or else), then entirely disable client-side JavaScript after SSR/generate except for this runtime part.
Why isn't it possible to extract runtime scripts?
Vue.js, Highlight.js and also all of the codes inside .vue
files are a part of the same runtime that is being compiled as a single bundle. Only excluding some from client bundle would be possible.
I guess an alternative could be to have a place where to write runtime JavaScript
Yep. Can be a solution. A tiny lib like bootstrap.js for supporting dropdowns and disabling nuxt client js. But I highly suggest not bothering to do this approach. It needs a custom compile step for second js bundle and can be difficult to handle in complex scenarios when combined with SSR.
Some logic like highlighted code generation can be moved to the server (API or SSR-only) side. Combining this with full-static generate (as @manniL mentioned) we can have a reasonable small runtime (without heavy sized libraries in client bundle) and also no dependency to the API after deployment (full generate)
Nuxt (and almost all SSR compatible frameworks) compile the same code-base twice. Once for Browser and once for Node.js. These two bundles should be able to produce the same content so client-side routing works. If we _omit_ the need for client-side routing by only using <a>
links, we can _assume_ only SSR side is required for page generation. Nuxt provides various ways to make different bundles from the same code-base. So we can only include heavy sized libraries like highlight.js
in server bundle. An alternative approach would be moving it to the API side.
@pi0 Thanks for explaining. Moving the highlighting part to the server is easy enough, and should considerably reduce the build.
Combining this with full-static generate (as @manniL mentioned) we can have a reasonable small runtime (without heavy sized libraries in client bundle) and also no dependency to the API after deployment (full generate)
Sure, but there would still be calls to static files that hold the data, instead of letting the browser navigate to the right HTML page. At least that's what https://github.com/DreaMinder/nuxt-payload-extractor does, and this is what, from what I've understood, nuxt/rfcs#22 is about. Is it being considered to let users disable this entirely so asyncData
calls are remove altogether, and there's no JavaScript navigation?
@sarahdayan With nuxt/rfcs#22, the goal is removing the need for API after static deployment.
It means still client-routing can work so when the user is navigating in the website does not need to fully download .html
files of each page. The state (vuex + asyncData) will be stored as static chunks which are deployable to any static hosting.
@pi0 Got you, I understood it well then :)
Would there ever be a possibility of a 100% static, no JS option?
@sarahdayan So "no SPA", just a static site?
It probably is already You can use Nuxt's hooks to remove all the JS from the HTML output
Yes, it is possible using hooks, writing regex and remove <script>
tags. example. It has little performance penalty but does the job.
As it has some use cases (Search engine and AMP), I may open a PR for adding an option for this.
@pi0 does it still have a perf penalty when using nuxt generate
? 馃
@manniL for nuxt generate
it is once. But for SSR purposes it should apply that regex on each request so has perf penalty.
@manniL @pi0 Thanks a lot for your help and input! I think I will end up fully stripping the generated JavaScript and handle the client-side stuff with some custom JS instead of using Vue for it (so removing all the @click
). My goal is to ship something really small and performant, so if I can avoid non essential client-side JavaScript, that's better.
Thanks again and good luck with the full generate option!
@sarahdayan it sounds like you'd better use something like svelte instead of vue (and sapper instead of nuxt) in your case. But sadly it is not so mature as nuxt.
Closing here as the issue was resolved/talked through :relaxed:
@manniL
I am trying to build nuxt generate
but after I deploy to surge and gitlab, the result is still same
it was not work properly, it likes my css not working, and my pics can't be load
I have put router.base
thought but still not change
I ran into the same issues as @sarahdayan.
I picked nuxt because i wanted to fully pre-render my blog then ship the generated static html. However when navigating routes, it attempts to call the api again. I understand it's trying to maintain the spa behaviour, but the issue here is that my source is on my machine(local ghost-cms instance).
So this completely falls through for my use-case unless i host my cms on a publicly accessible server(defeating the whole purpose of my experiment).
Would this mean Nuxt is not appropriate for such use case and I should look more towards something like Hugo ?
@MrSunshyne https://github.com/nuxt/rfcs/issues/22 should be the thing you want :relaxed:
Most helpful comment
@aldarund Sorry but I'm not sure I understand. I fetch the data upon generation of the build (which is precisely why Nuxt needs me to expose the dynamic ones in
nuxt.config.js
) and it ends up being hardcoded in the HTML files (as expected). Why would Vue need to rehydrate?When I serve the built website and disable JavaScript, it works as expected (apart from the JavaScript that I need at runtime of course). I understand that these scripts are needed for SPA mode and SSR mode, but not for pre-rendering mode, which goal is to render everything beforehand, at build time, and not rely on JavaScript to do so.