-
-
Notifications
You must be signed in to change notification settings - Fork 5.4k
fix(nuxt): correctly handle island rendering error #33302
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
|
WalkthroughThe island handler catch block now uses Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1)**/*.{ts,tsx}📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Files:
🧬 Code graph analysis (1)packages/nuxt/src/app/components/nuxt-island.ts (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
🔇 Additional comments (4)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🧪 Early access (Sonnet 4.5): enabledWe are currently testing the Sonnet 4.5 model, which is expected to improve code review quality. However, this model may lead to increased noise levels in the review comments. Please disable the early access features if the noise level causes any inconvenience. Note:
Comment |
@nuxt/kit
nuxt
@nuxt/rspack-builder
@nuxt/schema
@nuxt/vite-builder
@nuxt/webpack-builder
commit: |
|
do you think we could add a regression test? |
CodSpeed Performance ReportMerging #33302 will not alter performanceComparing Summary
|
|
yes, i always forget to open as draft 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/nuxt/src/app/components/nuxt-island.ts (1)
209-231: Prevent ReferenceError when handling non-OK island responsesIf the fetch returns a non-OK status we now throw
createErrorfrom inside the.thenbeforerhas been initialised. Control then drops into thecatch, wherer.statusimmediately raisesReferenceError: Cannot access 'r' before initialization, turning the intended 404 into a 500 and breaking the regression you're aiming to add. Please ensure the response variable is initialised before thetry/catch, or guard thecatchbefore touchingr, so that we rethrow the original Nuxt error cleanly.- const r = await eventFetch(withQuery(((import.meta.dev && import.meta.client) || props.source) ? url : joinURL(config.app.baseURL ?? '', url), { - ...props.context, - props: props.props ? JSON.stringify(props.props) : undefined, - })).then((response) => { - if (!response.ok) { - throw createError({ statusCode: response.status, statusMessage: response.statusText }) - } - return response - }) - try { - const result = import.meta.server || !import.meta.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data + let r: FetchResponse<NuxtIslandResponse> | Response | undefined + try { + r = await eventFetch(withQuery(((import.meta.dev && import.meta.client) || props.source) ? url : joinURL(config.app.baseURL ?? '', url), { + ...props.context, + props: props.props ? JSON.stringify(props.props) : undefined, + })).then((response) => { + if (!response.ok) { + throw createError({ statusCode: response.status, statusMessage: response.statusText }) + } + return response + }) + const result = import.meta.server || !import.meta.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data setPayload(key, result) return result - } catch (e: any) { - if (r.status !== 200) { + } catch (e: any) { + if (!r) { + throw e + } + if (r.status !== 200) { throw new Error(e.toString(), { cause: r }) } throw e }
🧹 Nitpick comments (1)
test/nuxt/nuxt-island.test.ts (1)
85-122: Ensure test servers close on failureIf one of the assertions throws, the
close()call is skipped and the srvx listener can bleed into later tests. Wrapping the mount/expect block in atry/finally(here and in the base-URL variant just below) keeps the suite robust.- const { server, port } = await createServer(handler) - const wrapper = await mountSuspended(NuxtIsland, { - props: { - name: 'Test', - source: `http://localhost:${port}`, - }, - }) - expect(wrapper.html()).toMatchInlineSnapshot('"<div>hello world from another server</div>"') - await server.close() + const { server, port } = await createServer(handler) + try { + const wrapper = await mountSuspended(NuxtIsland, { + props: { + name: 'Test', + source: `http://localhost:${port}`, + }, + }) + expect(wrapper.html()).toMatchInlineSnapshot('"<div>hello world from another server</div>"') + } finally { + await server.close() + } @@ - const { server, port } = await createServer(handler) - const wrapper = await mountSuspended(NuxtIsland, { - props: { - name: 'Test', - source: `http://localhost:${port}/app`, - }, - }) - expect(wrapper.html()).toMatchInlineSnapshot('"<div>hello world from another server</div>"') - expect(url!.startsWith(`http://localhost:${port}/app/__nuxt_island`)).toBe(true) - await server.close() + const { server, port } = await createServer(handler) + try { + const wrapper = await mountSuspended(NuxtIsland, { + props: { + name: 'Test', + source: `http://localhost:${port}/app`, + }, + }) + expect(wrapper.html()).toMatchInlineSnapshot('"<div>hello world from another server</div>"') + expect(url!.startsWith(`http://localhost:${port}/app/__nuxt_island`)).toBe(true) + } finally { + await server.close() + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/nuxt/src/app/components/nuxt-island.ts(2 hunks)test/basic.test.ts(1 hunks)test/bundle.test.ts(1 hunks)test/fixtures/basic/app/pages/index.vue(1 hunks)test/fixtures/basic/app/pages/server-components/lost-page.server.vue(1 hunks)test/nuxt/nuxt-island.test.ts(12 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.vue
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
<script setup lang="ts">and the composition API when creating Vue components
Files:
test/fixtures/basic/app/pages/server-components/lost-page.server.vuetest/fixtures/basic/app/pages/index.vue
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
test/basic.test.tstest/bundle.test.tspackages/nuxt/src/app/components/nuxt-island.tstest/nuxt/nuxt-island.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Write unit tests for core functionality using
vitest
Files:
test/basic.test.tstest/bundle.test.tstest/nuxt/nuxt-island.test.ts
🧠 Learnings (1)
📚 Learning: 2025-07-18T16:46:07.446Z
Learnt from: CR
PR: nuxt/nuxt#0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-07-18T16:46:07.446Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : Write unit tests for core functionality using `vitest`
Applied to files:
test/nuxt/nuxt-island.test.ts
🧬 Code graph analysis (2)
test/basic.test.ts (1)
test/utils.ts (1)
renderPage(11-50)
packages/nuxt/src/app/components/nuxt-island.ts (3)
packages/nuxt/src/app/composables/error.ts (1)
createError(64-79)packages/nuxt/src/app/index.ts (1)
createError(6-6)packages/nuxt/src/app/composables/index.ts (1)
createError(7-7)
🔇 Additional comments (1)
test/nuxt/nuxt-island.test.ts (1)
10-23: Helper centralises server setupConsolidating the srvx bootstrapping into
createServerkeeps these tests much tidier and easier to follow.
| await page.locator('#server-page').waitFor() | ||
| }) | ||
|
|
||
| it('should show error on 404 error for server pages during client navigation', async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currently the 'lost page' renders differently on client-side navigation vs hard reload. (the message is different, for example)
ideally we'd make it the same - do you have any ideas for that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just removed the usage of $fetch.raw . We had 503 http issues 2 years ago, seems to be fixed now;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/nuxt/src/app/components/nuxt-island.ts (1)
210-212: Preserve response context and align error shape with catch pathThrowing
createErroron non‑OK is correct. To aid debugging and keep a consistent NuxtError on all failure paths, include the response as the error cause (and optionally the URL), and mirror this in the catch branch that currently throws a plainError.Apply this diff to enrich the thrown error on non‑OK:
- if (!r.ok) { - throw createError({ statusCode: r.status, statusMessage: r.statusText }) - } + if (!r.ok) { + throw createError({ + statusCode: r.status, + statusMessage: r.statusText, + cause: r, + data: { url: (r as Response).url } + }) + }And update the catch branch below to use
createErroras well (outside the changed hunk, shown for clarity):} catch (e: any) { if (r.status !== 200) { throw createError({ statusCode: r.status, statusMessage: r.statusText, cause: r, data: { url: (r as Response).url } }) } throw e }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/nuxt/src/app/components/nuxt-island.ts(2 hunks)test/basic.test.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- test/basic.test.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Follow standard TypeScript conventions and best practices
Files:
packages/nuxt/src/app/components/nuxt-island.ts
🧬 Code graph analysis (1)
packages/nuxt/src/app/components/nuxt-island.ts (1)
packages/nuxt/src/app/composables/error.ts (1)
createError(64-79)
🔇 Additional comments (1)
packages/nuxt/src/app/components/nuxt-island.ts (1)
13-13: Import looks goodImporting
createErrorlocally keeps error construction consistent with server/runtime handling.
| import type { ActiveHeadEntry, SerializableHead } from '@unhead/vue' | ||
| import { randomUUID } from 'uncrypto' | ||
| import { joinURL, withQuery } from 'ufo' | ||
| import type { FetchResponse } from 'ofetch' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
danielroe
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great! ❤️
🔗 Linked issue
fix #33237
📚 Description
This PR fixes an issue in Nuxt island renderer not correctly handling errors