qwik icon indicating copy to clipboard operation
qwik copied to clipboard

Static Site Generation (SSG) / Pre-rendering

Open wtho opened this issue 2 years ago • 7 comments

Is your feature request related to a problem?

no

Describe the solution you'd like

There should be a command, maybe something like vite build --mode ssg to generate the application or website pages as prerendered, resumable html files alongside the client js files.

Describe alternatives you've considered

Additional context

So far I came up with this basic working solution (for a single page), although I am sure it does not work for all options/settings:

// /build-ssg.mjs
const fs = await import('node:fs/promises'); // currently only works with node.js
const server = await import("./server/entry.ssr.js");

const routes = [{url: "/", outFile: 'dist/index.html'}]; // should be derived from router or provided by developer

for (const route of routes) {
  const { html } = await server.render({ url: route.url });
  await fs.writeFile(route.outFile, html);
}

It relies on the client- and sever-build being generated. It would be smoother if in the end the server part was not necessary to be under server/entry.ssr.js, I think most users would not want SSR and SSG eventually.

Maybe something like this can be integrated into qwik directly. @manucorporat any opinions?

wtho avatar Jun 29 '22 06:06 wtho

Yes! We definively need to provide a goto solution in our starters… I think it does not need to be necessary built into the core, but delegate functionality to a third party dep, or some fancy script like the one you implemented.

At Stencil, Adam and I implemented an efficient prerender manager that we were thinking to port, or maybe qwik pre-render is a community driven project.

Any ways, we haven’t got into implementing it yet, it agreed its very important

manucorporat avatar Jun 29 '22 09:06 manucorporat

Also, QwikCity can be a key part of this, since it will be able to provide a map of routes

manucorporat avatar Jun 29 '22 09:06 manucorporat

I think one of the biggest considerations would be deciding on an api for parameterized routes.

If you have a route /shop/product/[[id]], QwikCity would need to know which product ids are valid to generate ahead of time.

You could also have a hybrid where QwikCity does SSG for only non-parameterized routes and everything else is generated a request time.

11ty has some interesting ideas with their Serverless plugin that gives you flexibility to opt in and out of SSG when you want to.

Of course, 11ty is SSG first and the plugin is very tied to Netlify at the moment. But the flexibility is nice.

nnelgxorz avatar Jun 29 '22 19:06 nnelgxorz

@nnelgxorz I agree, this is state-of-the-art pre-rendering! 11ty's Serverless plugin supports three render modes:

  1. Rendering at build time and serving these pre-rendered html files (pre-rendered)
  2. Rendering on-demand at first request and serving these pre-rendered html files, if already rendered (on-demand)
  3. Rendering dynamically, on each request, aka SSR (dynamically)

We basically have to build the SSR server and client bundles at build time via the optimizer/qwikVite. Then we can invoke it during the build to generate html pages at build time. For this we need some smart analysis of all available (static or dynamic) routes from the router or a list of routes the developer wants to pre-render.

At runtime, the server has to handle each request accordingly. The current SSR server only renders each page on each request and serves that html. There we would have to add some logic to:

  • check if the route is pre-rendered/on-demand/dynamically by calling routeRenderMode(...)
  • look for pre-rendered files and load it (pre-rendered / on-demand)
  • render page (on-demand / dynamically)
  • write file to fs (on-demand)
  • serve html (all)

Other features a SSG/Prerender plugin could have:

  • QwikCity router compatibility
  • Configuration which pages are what mode - e. g. a routeRenderMode implemented in src/entry.ssg.tsx
    • Optimally this function call also already includes QwikCity routing information for the current route
    • Possible signature: function routeRenderMode(url: string, routes: QwikCityRouterData): 'pre-rendered' | 'on-demand' | 'dynamic'
  • CLI command to output bundles, assets and pre-rendered html files in output folder, e. g. qwik-ssg build --ssg src/entry.ssg.tsx
    • Output information which page was rendered why in which mode
  • SPA mode (only render root page)

Anyways these are just some ideas.

@manucorporat Is there a way to "ask" QwikCity for the configures routes, including dynamic ones?

wtho avatar Jul 03 '22 07:07 wtho

Perhaps this may help: https://github.com/BuilderIO/qwik/blob/f151f506c578413203a0cf5a571a9014abd3f011/packages/docs/src/pages/qwikcity/routing/overview.mdx#qwik-city-plan

mhevery avatar Jul 12 '22 22:07 mhevery

Great suggestion @wtho and awesome input @nnelgxorz

We discussed it today, this is on the roadmap After the new changes to QwikCity will lang (folder based routes etc) it'll clear more room to implmenet it (all the infra is there, as @adamdbradley designed it with SSG in mind)

shairez avatar Aug 02 '22 23:08 shairez

Everything I wanted and more. Can't wait for what's coming!

nnelgxorz avatar Aug 03 '22 00:08 nnelgxorz

Implemented already!

manucorporat avatar Sep 06 '22 07:09 manucorporat

Shipped in beta https://qwik.builder.io/qwikcity/static-site-generation/overview/

adamdbradley avatar Sep 19 '22 17:09 adamdbradley