From 14e586cc77570b08afae5eeef605e978fec287d8 Mon Sep 17 00:00:00 2001 From: Justinas Delinda <8914032+minht11@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:44:02 +0200 Subject: [PATCH] fix(vue): vue regular script block exports not being recognized inside editor (#8998) Co-authored-by: Erika <3019731+Princesseuh@users.noreply.github.com> --- .changeset/two-oranges-knock.md | 5 ++++ packages/integrations/vue/package.json | 1 + packages/integrations/vue/src/editor.cts | 28 +++++++++++++------ .../vue/test/app-entrypoint.test.js | 22 +++++++++++---- .../src/components/Generics.vue | 13 +++++++++ .../src/components/GenericsAndBlocks.vue | 18 ++++++++++++ .../src/components/MultipleScriptBlocks.vue | 18 ++++++++++++ .../app-entrypoint/src/pages/index.astro | 11 ++++++++ pnpm-lock.yaml | 3 ++ 9 files changed, 105 insertions(+), 14 deletions(-) create mode 100644 .changeset/two-oranges-knock.md create mode 100644 packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue create mode 100644 packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue create mode 100644 packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue diff --git a/.changeset/two-oranges-knock.md b/.changeset/two-oranges-knock.md new file mode 100644 index 000000000000..4bf6e8938540 --- /dev/null +++ b/.changeset/two-oranges-knock.md @@ -0,0 +1,5 @@ +--- +'@astrojs/vue': patch +--- + +Adds editor support for Vue non setup script blocks and Vue 3.3 generics. diff --git a/packages/integrations/vue/package.json b/packages/integrations/vue/package.json index 836d4cb91d94..2e0d0a2f6628 100644 --- a/packages/integrations/vue/package.json +++ b/packages/integrations/vue/package.json @@ -51,6 +51,7 @@ "astro-scripts": "workspace:*", "chai": "^4.3.7", "linkedom": "^0.15.1", + "cheerio": "1.0.0-rc.12", "mocha": "^10.2.0", "vite": "^4.4.9", "vue": "^3.3.4" diff --git a/packages/integrations/vue/src/editor.cts b/packages/integrations/vue/src/editor.cts index 29adaa09cad6..0b62e899eed3 100644 --- a/packages/integrations/vue/src/editor.cts +++ b/packages/integrations/vue/src/editor.cts @@ -6,7 +6,7 @@ export function toTSX(code: string, className: string): string { // NOTE: As you can expect, using regexes for this is not exactly the most reliable way of doing things // However, I couldn't figure out a way to do it using Vue's compiler, I tried looking at how Volar does it, but I // didn't really understand everything happening there and it seemed to be pretty Volar-specific. I do believe - // someone more knowledgable on Vue's internals could figure it out, but since this solution is good enough for most + // someone more knowledgeable on Vue's internals could figure it out, but since this solution is good enough for most // Vue components (and it's an improvement over, well, nothing), it's alright, I think try { const parsedResult = parse(code); @@ -18,29 +18,39 @@ export function toTSX(code: string, className: string): string { `; } - if (parsedResult.descriptor.scriptSetup) { - const definePropsType = - parsedResult.descriptor.scriptSetup.content.match(/defineProps<([\s\S]+)>/m); + // Vue supports 2 type of script blocks: setup and non-setup + const regularScriptBlockContent = parsedResult.descriptor.script?.content ?? ''; + const { scriptSetup } = parsedResult.descriptor; + + if (scriptSetup) { + const definePropsType = scriptSetup.content.match(/defineProps<([\S\s]+?)>\s?\(\)/m); + const propsGeneric = scriptSetup.attrs.generic; + const propsGenericType = propsGeneric ? `<${propsGeneric}>` : ''; if (definePropsType) { result = ` - ${parsedResult.descriptor.scriptSetup.content} + ${regularScriptBlockContent} + ${scriptSetup.content} - export default function ${className}__AstroComponent_(_props: ${definePropsType[1]}): any { + export default function ${className}__AstroComponent_${propsGenericType}(_props: ${definePropsType[1]}): any {
} `; } else { - const defineProps = - parsedResult.descriptor.scriptSetup.content.match(/defineProps\([\s\S]+\)/m); + // TODO. Find a way to support generics when using defineProps without passing explicit types. + // Right now something like this `defineProps({ prop: { type: Array as PropType } })` + // won't be correctly typed in Astro. + const defineProps = scriptSetup.content.match(/defineProps\([\s\S]+\)/m); if (defineProps) { result = ` import { defineProps } from '@vue/runtime-core'; + ${regularScriptBlockContent} + const Props = ${defineProps[0]} - export default function ${className}__AstroComponent_(_props: typeof Props): any { + export default function ${className}__AstroComponent_${propsGenericType}(_props: typeof Props): any {
} `; diff --git a/packages/integrations/vue/test/app-entrypoint.test.js b/packages/integrations/vue/test/app-entrypoint.test.js index 4f4f389d1b3c..b20e7be7e33c 100644 --- a/packages/integrations/vue/test/app-entrypoint.test.js +++ b/packages/integrations/vue/test/app-entrypoint.test.js @@ -1,6 +1,8 @@ import { loadFixture } from './test-utils.js'; import { expect } from 'chai'; +import { load as cheerioLoad } from 'cheerio'; import { parseHTML } from 'linkedom'; + describe('App Entrypoint', () => { /** @type {import('./test-utils').Fixture} */ let fixture; @@ -13,11 +15,21 @@ describe('App Entrypoint', () => { }); it('loads during SSR', async () => { - const data = await fixture.readFile('/index.html'); - const { document } = parseHTML(data); - const bar = document.querySelector('#foo > #bar'); - expect(bar).not.to.be.undefined; - expect(bar.textContent).to.eq('works'); + const html = await fixture.readFile('/index.html'); + const $ = cheerioLoad(html); + + // test 1: basic component renders + expect($('#foo > #bar').text()).to.eq('works'); + + // test 2: component with multiple script blocks renders and exports + // values from non setup block correctly + expect($('#multiple-script-blocks').text()).to.equal('2 4'); + + // test 3: component using generics renders + expect($('#generics').text()).to.equal('generic'); + + // test 4: component using generics and multiple script blocks renders + expect($('#generics-and-blocks').text()).to.equal('1 3!!!'); }); it('setup included in renderer bundle', async () => { diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue new file mode 100644 index 000000000000..00ceea09e480 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/Generics.vue @@ -0,0 +1,13 @@ + + + diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue new file mode 100644 index 000000000000..7ecfdc7a06b2 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/GenericsAndBlocks.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue new file mode 100644 index 000000000000..ac2ec0a3c271 --- /dev/null +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/components/MultipleScriptBlocks.vue @@ -0,0 +1,18 @@ + + + + + diff --git a/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro index 3240cbe0fd73..a517f8a979cc 100644 --- a/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro +++ b/packages/integrations/vue/test/fixtures/app-entrypoint/src/pages/index.astro @@ -1,5 +1,8 @@ --- import Foo from '../components/Foo.vue'; +import MultipleScriptBlocks, { doubleNumber } from '../components/MultipleScriptBlocks.vue'; +import GenericComponent from '../components/Generics.vue'; +import GenericsAndBlocks, { customFormatter } from '../components/GenericsAndBlocks.vue'; --- @@ -8,5 +11,13 @@ import Foo from '../components/Foo.vue'; + + + {doubleNumber(2)} + + + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 525adb49ac9a..d47b4e5f8c90 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4803,6 +4803,9 @@ importers: chai: specifier: ^4.3.7 version: 4.3.10 + cheerio: + specifier: 1.0.0-rc.12 + version: 1.0.0-rc.12 linkedom: specifier: ^0.15.1 version: 0.15.6