diff --git a/src/codegen/generateRouteRecords.ts b/src/codegen/generateRouteRecords.ts index 2b064d3a1..86f89086d 100644 --- a/src/codegen/generateRouteRecords.ts +++ b/src/codegen/generateRouteRecords.ts @@ -1,3 +1,4 @@ +import { getLang } from '@vue-macros/common' import type { TreeNode } from '../core/tree' import { ImportsMap } from '../core/utils' import { type ResolvedOptions } from '../options' @@ -80,9 +81,11 @@ ${startIndent}}` for (const [name, filePath] of node.value.components) { const pageDataImport = `_definePage_${name}_${importsMap.size}` definePageDataList.push(pageDataImport) + const lang = getLang(filePath) importsMap.addDefault( // TODO: apply the language used in the sfc - `${filePath}?definePage&vue&lang.tsx`, + `${filePath}?definePage&` + + (lang === 'vue' ? 'vue&lang.tsx' : `lang.${lang}`), pageDataImport ) } diff --git a/src/core/__snapshots__/definePage.spec.ts.snap b/src/core/__snapshots__/definePage.spec.ts.snap index a2a483a2f..0d160ad0b 100644 --- a/src/core/__snapshots__/definePage.spec.ts.snap +++ b/src/core/__snapshots__/definePage.spec.ts.snap @@ -72,3 +72,10 @@ const b = 1 " `; + +exports[`definePage > works with jsx 1`] = ` +"export default { + name: 'custom', + path: '/custom', + }" +`; diff --git a/src/core/definePage.spec.ts b/src/core/definePage.spec.ts index 22f604178..07d92d4f8 100644 --- a/src/core/definePage.spec.ts +++ b/src/core/definePage.spec.ts @@ -135,7 +135,7 @@ definePage({ }) }) - it.todo('works with jsx', async () => { + it('works with jsx', async () => { const code = ` const a = 1 definePage({ @@ -146,11 +146,11 @@ definePage({ `, result = (await definePageTransform({ code, - id: 'src/pages/basic.vue?definePage&jsx', + id: 'src/pages/basic.jsx?definePage&lang.jsx', })) as Exclude expect(result).toBeDefined() expect(result).toHaveProperty('code') - expect(result?.code).toMatchInlineSnapshot() + expect(result?.code).toMatchSnapshot() }) it('throws if definePage uses a variable from the setup', async () => { diff --git a/src/core/definePage.ts b/src/core/definePage.ts index aa0240dd0..ebe969ca0 100644 --- a/src/core/definePage.ts +++ b/src/core/definePage.ts @@ -4,12 +4,15 @@ import { parseSFC, MagicString, checkInvalidScopeReference, + babelParse, + getLang, } from '@vue-macros/common' import type { Thenable, TransformResult } from 'unplugin' import type { CallExpression, Node, ObjectProperty, + Program, Statement, StringLiteral, } from '@babel/types' @@ -25,6 +28,25 @@ function isStringLiteral(node: Node | null | undefined): node is StringLiteral { return node?.type === 'StringLiteral' } +function getAst(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 + } + } else if (/[jt]sx?$/.test(lang)) { + ast = babelParse(code, lang) + } + return { ast, offset } +} + export function definePageTransform({ code, id, @@ -41,15 +63,10 @@ export function definePageTransform({ return isExtractingDefinePage ? 'export default {}' : undefined } - // TODO: handle also non SFC - - const sfc = parseSFC(code, id) - if (!sfc.scriptSetup) return + const { ast, offset } = getAst(code, id) + if (!ast) return - const { scriptSetup, getSetupAst } = sfc - const setupAst = getSetupAst() - - const definePageNodes = (setupAst?.body || ([] as Node[])) + const definePageNodes = ((ast.body || []) as Node[]) .map((node) => { if (node.type === 'ExpressionStatement') node = node.expression return isCallOf(node, MACRO_DEFINE_PAGE) ? node : null @@ -67,7 +84,6 @@ export function definePageTransform({ } const definePageNode = definePageNodes[0]! - const setupOffset = scriptSetup.loc.start.offset // we only want the page info if (isExtractingDefinePage) { @@ -82,13 +98,13 @@ export function definePageTransform({ ) } - const scriptBindings = setupAst?.body ? getIdentifiers(setupAst.body) : [] + const scriptBindings = ast.body ? getIdentifiers(ast.body) : [] // this will throw if a property from the script setup is used in definePage checkInvalidScopeReference(routeRecord, MACRO_DEFINE_PAGE, scriptBindings) - s.remove(setupOffset + routeRecord.end!, code.length) - s.remove(0, setupOffset + routeRecord.start!) + s.remove(offset + routeRecord.end!, code.length) + s.remove(0, offset + routeRecord.start!) s.prepend(`export default `) // find all static imports and filter out the ones that are not used @@ -156,11 +172,8 @@ export function definePageTransform({ const s = new MagicString(code) - // s.removeNode(definePageNode, { offset: setupOffset }) - s.remove( - setupOffset + definePageNode.start!, - setupOffset + definePageNode.end! - ) + // s.removeNode(definePageNode, { offset }) + s.remove(offset + definePageNode.start!, offset + definePageNode.end!) return generateTransform(s, id) } @@ -172,14 +185,10 @@ export function extractDefinePageNameAndPath( ): { name?: string; path?: string } | null | undefined { if (!sfcCode.includes(MACRO_DEFINE_PAGE)) return - const sfc = parseSFC(sfcCode, id) - - if (!sfc.scriptSetup) return - - const { getSetupAst } = sfc - const setupAst = getSetupAst() + const { ast } = getAst(sfcCode, id) + if (!ast) return - const definePageNodes = (setupAst?.body ?? ([] as Node[])) + const definePageNodes = ((ast.body ?? []) as Node[]) .map((node) => { if (node.type === 'ExpressionStatement') node = node.expression return isCallOf(node, MACRO_DEFINE_PAGE) ? node : null