From dc1c62c91f302c017e92c489ee64a3e820e53fdf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:18:26 +0000 Subject: [PATCH 1/3] Initial plan From b73e922eaad5b6d165971f424548540dbfabd0a6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:27:14 +0000 Subject: [PATCH 2/3] Add test case for syntax error handling in definePage Co-authored-by: posva <664177+posva@users.noreply.github.com> --- src/core/definePage.spec.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/core/definePage.spec.ts b/src/core/definePage.spec.ts index 07d92d4f8..49ff0d437 100644 --- a/src/core/definePage.spec.ts +++ b/src/core/definePage.spec.ts @@ -254,4 +254,30 @@ export default { path: '/custom', }) }) + + it('handles syntax errors gracefully', async () => { + const invalidCode = ` + + + + ` + + // Should not throw and return undefined for normal transform + const result = await definePageTransform({ + code: invalidCode, + id: 'src/pages/invalid.vue', + }) + expect(result).toBeUndefined() + + // Should return empty object for definePage extraction + const extractResult = await definePageTransform({ + code: invalidCode, + id: 'src/pages/invalid.vue?definePage&vue', + }) + expect(extractResult).toBe('export default {}') + }) }) From cdb584fbb39906e0edba13865ebd88c63a08501a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:34:21 +0000 Subject: [PATCH 3/3] Fix syntax error handling in definePage to prevent Vite crashes Co-authored-by: posva <664177+posva@users.noreply.github.com> --- playground/typed-router.d.ts | 5 +++++ src/core/definePage.spec.ts | 42 ++++++++++++++++++++++++++++++++++++ src/core/definePage.ts | 34 +++++++++++++++++++---------- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/playground/typed-router.d.ts b/playground/typed-router.d.ts index c4b6e56f2..896141e31 100644 --- a/playground/typed-router.d.ts +++ b/playground/typed-router.d.ts @@ -63,6 +63,7 @@ declare module 'vue-router/auto-routes' { '/nested-group/(nested-group-first-level)/nested-group-first-level-child': RouteRecordInfo<'/nested-group/(nested-group-first-level)/nested-group-first-level-child', '/nested-group/nested-group-first-level-child', Record, Record>, '/partial-[name]': RouteRecordInfo<'/partial-[name]', '/partial-:name', { name: ParamValue }, { name: ParamValue }>, '/custom-path': RouteRecordInfo<'/custom-path', '/surprise-:id(\d+)', Record, Record>, + '/syntax-error-test': RouteRecordInfo<'/syntax-error-test', '/syntax-error-test', Record, Record>, '/test-[a-id]': RouteRecordInfo<'/test-[a-id]', '/test-:a-id', { aId: ParamValue }, { aId: ParamValue }>, '/todos/': RouteRecordInfo<'/todos/', '/todos', Record, Record>, '/todos/+layout': RouteRecordInfo<'/todos/+layout', '/todos/+layout', Record, Record>, @@ -283,6 +284,10 @@ declare module 'vue-router/auto-routes' { routes: '/custom-path' views: never } + 'src/pages/syntax-error-test.vue': { + routes: '/syntax-error-test' + views: never + } 'src/pages/test-[a-id].vue': { routes: '/test-[a-id]' views: never diff --git a/src/core/definePage.spec.ts b/src/core/definePage.spec.ts index 49ff0d437..0d70d0b83 100644 --- a/src/core/definePage.spec.ts +++ b/src/core/definePage.spec.ts @@ -279,5 +279,47 @@ definePage({ 2, 3 }) // invalid syntax id: 'src/pages/invalid.vue?definePage&vue', }) expect(extractResult).toBe('export default {}') + + // extractDefinePageNameAndPath should also handle syntax errors gracefully + const nameAndPath = await extractDefinePageNameAndPath(invalidCode, 'src/pages/invalid.vue') + expect(nameAndPath).toBeUndefined() + }) + + it('handles various syntax errors in definePage', async () => { + // Test with missing closing brace + const invalidCode1 = ` + + + + ` + + const result1 = await definePageTransform({ + code: invalidCode1, + id: 'src/pages/invalid1.vue', + }) + expect(result1).toBeUndefined() + + // Test with invalid property syntax + const invalidCode2 = ` + + + + ` + + const result2 = await definePageTransform({ + code: invalidCode2, + id: 'src/pages/invalid2.vue', + }) + expect(result2).toBeUndefined() + + const extractResult2 = await definePageTransform({ + code: invalidCode2, + id: 'src/pages/invalid2.vue?definePage&vue', + }) + expect(extractResult2).toBe('export default {}') }) }) diff --git a/src/core/definePage.ts b/src/core/definePage.ts index ca420eb1e..5e8a38b98 100644 --- a/src/core/definePage.ts +++ b/src/core/definePage.ts @@ -35,17 +35,26 @@ function getCodeAst(code: string, id: string) { let offset = 0 let ast: Program | undefined const lang = getLang(id.split(MACRO_DEFINE_PAGE_QUERY)[0]!) - if (lang === 'vue') { - const sfc = parseSFC(code, id) - if (sfc.scriptSetup) { - ast = sfc.getSetupAst() - offset = sfc.scriptSetup.loc.start.offset - } else if (sfc.script) { - ast = sfc.getScriptAst() - offset = sfc.script.loc.start.offset + + try { + if (lang === 'vue') { + const sfc = parseSFC(code, id) + if (sfc.scriptSetup) { + ast = sfc.getSetupAst() + offset = sfc.scriptSetup.loc.start.offset + } else if (sfc.script) { + ast = sfc.getScriptAst() + offset = sfc.script.loc.start.offset + } + } else if (/[jt]sx?$/.test(lang)) { + ast = babelParse(code, lang) } - } else if (/[jt]sx?$/.test(lang)) { - ast = babelParse(code, lang) + } catch (error) { + // If there's a syntax error in the code, warn and return empty results + // This prevents crashing the dev server when there are syntax errors + const errorMessage = error instanceof Error ? error.message : String(error) + warn(`[${id}]: Failed to parse code due to syntax error: ${errorMessage}`) + return { ast: undefined, offset: 0, definePageNodes: [] } } const definePageNodes: CallExpression[] = (ast?.body || []) @@ -78,7 +87,10 @@ export function definePageTransform({ } const { ast, offset, definePageNodes } = getCodeAst(code, id) - if (!ast) return + if (!ast) { + // If parsing failed but we're extracting definePage, return empty object + return isExtractingDefinePage ? 'export default {}' : undefined + } if (!definePageNodes.length) { return isExtractingDefinePage