N
Nuxtβ€’3mo ago
Elvin code

Nuxt Fullstack Linear Clone – SSR/Auth Help

Hi everyone πŸ‘‹, I'm working on a fullstack Nuxt app (Linear clone) and I have two major issues: First visit: The login page loads with broken styles. I have to refresh the page to see the correct UI. Home page: When I refresh the home page, I get a 500 error, while refreshing other pages works fine. Here's some context: I use a Pinia store auth with a checkAuth function:
const checkAuth = async () => {
try {
const { user: authUser } = await $fetch('/api/auth/me')
user.value = authUser
return authUser
} catch {
user.value = null
return null
}
}

//And a global middleware auth.global.ts:

export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore()
const publicRoutes = ['/login', '/signup']
if (publicRoutes.includes(to.path)) return

if (!authStore.user) {
try {
const user = await authStore.checkAuth()
if (!user) return navigateTo('/login')
} catch {
return navigateTo('/login')
}
}
})
const checkAuth = async () => {
try {
const { user: authUser } = await $fetch('/api/auth/me')
user.value = authUser
return authUser
} catch {
user.value = null
return null
}
}

//And a global middleware auth.global.ts:

export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore()
const publicRoutes = ['/login', '/signup']
if (publicRoutes.includes(to.path)) return

if (!authStore.user) {
try {
const user = await authStore.checkAuth()
if (!user) return navigateTo('/login')
} catch {
return navigateTo('/login')
}
}
})
It feels like an SSR / hydration issue with the store and middleware, but I’m not sure how to fix it. Does anyone have suggestions for handling first-visit login styles and preventing 500 on refresh for protected pages? Repo link : https://github.com/ElvinKyungu/linear-nuxt-fullstack/ Preview link: https://linear-ehn.pages.dev/login Thanks a lot! πŸ™
GitHub
GitHub - ElvinKyungu/linear-nuxt-fullstack: A sleek and efficient p...
A sleek and efficient project management interface inspired by Linear. Built with Nuxt.js, GSAP, Tailwindcss and and Nuxt UI, it enables seamless issue tracking, project management, and team collab...
2 Replies
kapa.ai
kapa.aiβ€’3mo ago
Hi @Elvin code. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- You're encountering two common issues in Nuxt fullstack apps with SSR and authentication: 1. Login Page Loads with Broken Styles on First Visit This is often a hydration mismatch issue. Common causes include: - Using browser-only APIs (like localStorage) during SSR - Inconsistent data between server and client - Conditional rendering based on client-only state How to fix: - Ensure you do not use browser-only APIs in your setup code. If you need to access things like localStorage, wrap them in if (import.meta.client) or use Nuxt composables like useCookie which work on both server and client. - Make sure your state (especially authentication state) is initialized in an SSR-friendly way, e.g., using useState or Pinia with proper SSR support. - Avoid side effects or DOM manipulations in your setup code; move them to onMounted if needed. See the Nuxt hydration best practices for more details and examples. 2. 500 Error on Home Page Refresh (Protected Route) This is likely due to how your authentication check is handled in SSR. If your checkAuth function or Pinia store is not SSR-friendly, or if you try to access client-only state on the server, it can cause errors. Key points: - In Nuxt, middleware runs on both server and client. If your store or composables are not SSR-safe, you may get errors on server-side navigation. - Your auth.global.ts middleware is async and calls checkAuth, which uses $fetch. If this fails (e.g., due to missing cookies or headers on the server), it can throw and cause a 500 error. How to fix: - Make sure your authentication logic is SSR-compatible. Use Nuxt's useState or Pinia with SSR support for your user state (see docs). - In your middleware, handle errors gracefully and avoid throwing unhandled exceptions. Always return a redirect or undefined (to continue navigation). - For server-side redirects, ensure you use navigateTo and not router methods like router.push (see example). Example of SSR-friendly auth middleware:
export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore()
const publicRoutes = ['/login', '/signup']
if (publicRoutes.includes(to.path)) return

// SSR-friendly check
if (!authStore.user) {
const user = await authStore.checkAuth()
if (!user) return navigateTo('/login')
}
})
export default defineNuxtRouteMiddleware(async (to) => {
const authStore = useAuthStore()
const publicRoutes = ['/login', '/signup']
if (publicRoutes.includes(to.path)) return

// SSR-friendly check
if (!authStore.user) {
const user = await authStore.checkAuth()
if (!user) return navigateTo('/login')
}
})
Make sure checkAuth works both server- and client-side, and does not rely on browser-only APIs. Reference:
- Nuxt SSR state management and Pinia usage - Hydration mismatch causes and solutions - Middleware best practices --- If you still see broken styles, check for CSS loading issues or client-only code in your layout/components. For the 500 error, add error logging in your middleware and API routes to pinpoint the exact cause. If you need more targeted help, please provide the error stack trace from the 500 error and check your browser console/network tab for failed requests. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiβ€’3mo ago
<@1078666833550389288> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?