ui icon indicating copy to clipboard operation
ui copied to clipboard

fix(inertia): set serverRendered dynamically to prevent SSR crash

Open y-l-g opened this issue 3 months ago โ€ข 5 comments

๐Ÿ”— Linked issue

Resolves #5254

โ“ Type of change

  • [ ] ๐Ÿ“– Documentation (updates to the documentation or readme)
  • [x] ๐Ÿž Bug fix (a non-breaking change that fixes an issue)
  • [ ] ๐Ÿ‘Œ Enhancement (improving an existing functionality)
  • [ ] โœจ New feature (a non-breaking change that adds functionality)
  • [ ] ๐Ÿงน Chore (updates to the build process or auxiliary tools and libraries)
  • [ ] โš ๏ธ Breaking change (fix or feature that would cause existing functionality to change)

๐Ÿ“š Description

The Inertia stub currently hardcodes the payload.serverRendered value to false. This causes the application to crash during Server-Side Rendering (SSR). This change replaces the hardcoded value with a dynamic check (typeof window === "undefined") to accurately determine if the code is running on the server.

This solve SSR crashing with ReferenceError: document is not defined

๐Ÿ“ Checklist

  • [x] I have linked an issue or discussion.
  • [ ] I have updated the documentation accordingly.

y-l-g avatar Nov 06 '25 20:11 y-l-g

npm i https://pkg.pr.new/@nuxt/ui@5396

commit: 68db4eb

pkg-pr-new[bot] avatar Nov 06 '25 20:11 pkg-pr-new[bot]

https://github.com/nuxt/ui/pull/5347#issuecomment-3506599510 @Barbapapazes

y-l-g avatar Nov 08 '25 15:11 y-l-g

https://github.com/nuxt/ui/pull/5347#issuecomment-3506599510

@Barbapapazes

Nice! I'll have a look.

Barbapapazes avatar Nov 08 '25 15:11 Barbapapazes

Even with this fix, how do you manage the FOUC? (unhead does not inject the styles and I'm not understanding why, could be related to the head management of Inertia)

https://github.com/user-attachments/assets/1563829f-69aa-4ee4-8914-a436d88f8b67

source: https://github.com/nuxt-ui-templates/starter-laravel/pull/23

Barbapapazes avatar Nov 09 '25 09:11 Barbapapazes

Hi,

The issue is that Inertia handles its own head management, so it doesn't pick up the tags generated by Nuxt UI's internal unhead instance during the SSR pass.

The fix is to create a dedicated unhead instance, let Nuxt UI populate it during the setup, and then asynchronously push its rendered tags into Inertia's head array just before the response is sent. This ensures Nuxt UI's styles are present in the initial HTML.

Here's my createServer in resources/js/ssr.ts:

createServer(
  (page) => {
    const head = createHead();
    return createInertiaApp({
      page,
      render: renderToString,
      resolve: (name) =>
        resolvePageComponent(
          `./pages/${name}.vue`,
          import.meta.glob<DefineComponent>("./pages/**/*.vue")
        ),
      setup: ({ App, props, plugin }) =>
        createSSRApp({ render: () => h(App, props) })
          .use(plugin)
          .use(head)
          .use(ui),
    }).then(async (app) => {
      const payload = await renderSSRHead(head);
      app.head.push(payload.headTags);
      return app;
    });
  },
  { cluster: true }
);

To prevent the theme from flashing on hydration, i use a small script in app.blade.php:

<script>
    try {
        const theme = localStorage.getItem('vueuse-color-scheme');
        if (theme === 'dark' || (theme === null && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
            document.documentElement.classList.add('dark');
        } else {
            document.documentElement.classList.remove('dark');
        }
    } catch (e) { /* ignore */ }
</script>

On a related note, I saw the Laravel starter kit still uses Ziggy, while the official Laravel kits have moved on to Wayfinder(https://github.com/laravel/vue-starter-kit/pull/178). I'd be happy to open a separate PR to update it and include these SSR fixes. I've already implemented this in my own starter kit if you want to take a look: https://github.com/y-l-g/saasterkit. By the way https://saasterkit.com is server rendered.

Let me know if this approach works for you.

y-l-g avatar Nov 09 '25 13:11 y-l-g

Thanks @y-l-g ๐Ÿ˜Š A PR on https://github.com/nuxt-ui-templates/starter-laravel would be greatly appreciated, I made this template based on the Laravel Kit back then but in all honesty I know nothing about Laravel ๐Ÿ˜ฌ

benjamincanac avatar Nov 17 '25 10:11 benjamincanac

@benjamincanac do you think a new documentation page called SSR for the Vue.js version would be good? In the "Integrations" section

miguilimzero avatar Nov 21 '25 23:11 miguilimzero

@miguilimzero If it's short enough it could go in the Vue installation page otherwise we can add an Integration page yes!

benjamincanac avatar Nov 22 '25 13:11 benjamincanac