vikejs / vike

🔨 Flexible, lean, community-driven, dependable, fast Vite-based frontend framework.
https://vike.dev
MIT License
4.46k stars 352 forks source link

Prerender programmatically when calling into server route (aka ISR) #713

Open aenachetruebase opened 1 year ago

aenachetruebase commented 1 year ago

Description

Defined a server route like this:

  app.get('/api/revalidate', async (req, res) => {
    try {
      await prerender();
    } catch (e) {
      console.log(e);
      return res.send({ revalidated: false });
    }
    res.send({ revalidated: true });
  });

Calling into that route returns this message:

vite-plugin-ssr v0.4.94 pre-rendering HTML...
[vite-plugin-ssr@0.4.94][Warning] Set config `prerender` to `true`, see https://vite-plugin-ssr.com/prerender-config
Error: [vite-plugin-ssr@0.4.94][Bug] You stumbled upon a bug in vite-plugin-ssr's source code. Reach out at https://github.com/brillout/vite-plugin-ssr/issues/new or https://discord.com/invite/qTq92FQzKb and include this error stack (the error stack is usually enough to fix the problem). A maintainer will fix the bug (usually under 24 hours). Don't hesitate to reach out as it makes vite-plugin-ssr more robust.
    at initGlobalContext (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/globalContext.js:57:28)
    at runPrerender (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/prerender/runPrerender.js:45:49)
    at async prerender (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/prerender.js:6:5)
    at async /projects/packages/webv2/server/index.js:34:7

Error Message + Error Stack

vite-plugin-ssr v0.4.94 pre-rendering HTML...
[vite-plugin-ssr@0.4.94][Warning] Set config `prerender` to `true`, see https://vite-plugin-ssr.com/prerender-config
Error: [vite-plugin-ssr@0.4.94][Bug] You stumbled upon a bug in vite-plugin-ssr's source code. Reach out at https://github.com/brillout/vite-plugin-ssr/issues/new or https://discord.com/invite/qTq92FQzKb and include this error stack (the error stack is usually enough to fix the problem). A maintainer will fix the bug (usually under 24 hours). Don't hesitate to reach out as it makes vite-plugin-ssr more robust.
    at initGlobalContext (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/runtime/globalContext.js:57:28)
    at runPrerender (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/prerender/runPrerender.js:45:49)
    at async prerender (/projects/packages/webv2/node_modules/vite-plugin-ssr/dist/cjs/node/prerender.js:6:5)
    at async /projects/packages/webv2/server/index.js:34:7
brillout commented 1 year ago

Interesting approach.

VPS has a bunch of internal assumptions that don't allow you to do that. That said, you can workaround the issue by spinning off a second/background Node.js process. It's not only a workaround but also a performance improvement: your server shouldn't be slowed down by the pre-rendering job. (Also, the pre-rendering process isn't optimized to be run within a long-running process, e.g. it may have memory leaks.)

Let me know whether that workaround works out for you.

aenachetruebase commented 1 year ago

Thanks for the workaround suggestion! I will look into it and come back with an answer. This is mainly because we're updating our CMS on a weekly(ish) basis but I would like for the content team to be able to start the prerender process when needed / when content changed without needing to re-deploy.

brillout commented 1 year ago

Makes sense.

Btw. I'm considering turning the workaround into an official & well-polished VPS feature.

Also check out vite-plugin-vercel which supports ISR, see https://vite-plugin-ssr.com/vercel#vite-plugin-vercel.

Curious: what made you go for your current deployment strategy instead of only pre-rendering? (I guess you're already familiar with Should I pre-render?)

aenachetruebase commented 1 year ago

That sounds great!

We're using heroku right now so we can't use the vercel plugin sadly.

I thought that it makes most sense to have something that provides SEO but can be revalidated on-demand and without the need to rebuild and redeploy; I also thought of the prerender as an extra performance optimization on top of SSR.

brillout commented 1 year ago

If doing pre-rendering only is an option (i.e. without using SSR) then I'd recommend doing that.

aenachetruebase commented 1 year ago

Right now it's not an option for us, sadly; It would mean having to redeploy whenever something in the CMS changes and that's too complex for our current workflow.

I'll play around with the triggering of the prerender on a child process of the server - it sounds like a great enhancement idea if it would be provided as an option of VPS, for sure.

brillout commented 1 year ago

👍 Keep me updated.

aenachetruebase commented 1 year ago

Back with updates: Tried using exec to spawn a child process to run the prerender function

      exec('node ./server/revalidate.js', (error, stdout, stderr) => {
        if (error) {
          console.log(`error: ${error.message}`);
          return;
        }
        if (stderr) {
          console.log(`stderr: ${stderr}`);
          return;
        }
        console.log(`stdout: ${stdout}`);
      });

revalidate.js

const { prerender } = require('vite-plugin-ssr/prerender');

(async () => {
  try {
    await prerender();
  } catch (e) {
    console.log(e);
    return e;
  }
})();

And everything works as expected!

Great workaround, thank you so much!

brillout commented 1 year ago

👍 I'm glad it worked out. Btw. in case your company is up for it: https://github.com/sponsors/brillout – sponsoring is starting to make a big impact on VPS.