Skip to content

Conversation

@y-l-g
Copy link

@y-l-g y-l-g commented Nov 6, 2025

πŸ”— Linked issue

Resolves #5254

❓ Type of change

  • πŸ“– Documentation (updates to the documentation or readme)
  • 🐞 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

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

@y-l-g y-l-g requested a review from benjamincanac as a code owner November 6, 2025 20:41
@github-actions github-actions bot added the v4 #4488 label Nov 6, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 6, 2025

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

commit: 68db4eb

@y-l-g
Copy link
Author

y-l-g commented Nov 8, 2025

#5347 (comment)
@Barbapapazes

@Barbapapazes
Copy link
Contributor

#5347 (comment)

@Barbapapazes

Nice! I'll have a look.

@Barbapapazes
Copy link
Contributor

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)

ui-inertia-ssr-fouc.mp4

source: nuxt-ui-templates/starter-laravel#23

@y-l-g
Copy link
Author

y-l-g commented Nov 9, 2025

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(laravel/vue-starter-kit#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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v4 #4488

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incompatibility with Inertia SSR Server

2 participants