From 6f9f535d7cd27dc0aee22826f8df0e364a563dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sat, 5 Jul 2025 17:46:00 +0200 Subject: [PATCH 1/7] feat: allow slot prop vars as components --- .../src/transforms/transformElement.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 1dca0c514c1..c84dada2bdb 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -298,6 +298,34 @@ export function resolveComponentType( } } } + if (!__BROWSER__) { + const getName = (name: string) => { + const camelName = camelize(name) + const PascalName = capitalize(camelName) + + if (context.identifiers[name]) { + return name + } + if (context.identifiers[camelName]) { + return camelName + } + if (context.identifiers[PascalName]) { + return PascalName + } + } + + const fromSetup = getName(tag) + if (fromSetup) { + return fromSetup + } + const dotIndex = tag.indexOf('.') + if (dotIndex > 0) { + const ns = getName(tag.slice(0, dotIndex)) + if (ns) { + return ns + tag.slice(dotIndex) + } + } + } // 4. Self referencing component (inferred from filename) if ( From be6e5e22754ef0876b637d80214b2a8b0d386229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sat, 5 Jul 2025 20:11:48 +0200 Subject: [PATCH 2/7] chore: simplify resolution --- .../src/transforms/transformElement.ts | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index c84dada2bdb..6781506a6e5 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -298,36 +298,21 @@ export function resolveComponentType( } } } - if (!__BROWSER__) { - const getName = (name: string) => { - const camelName = camelize(name) - const PascalName = capitalize(camelName) - if (context.identifiers[name]) { - return name - } - if (context.identifiers[camelName]) { - return camelName - } - if (context.identifiers[PascalName]) { - return PascalName - } - } + // 4. component from slot props / other identifiers + if (context.identifiers[tag]) { + return tag + } - const fromSetup = getName(tag) - if (fromSetup) { - return fromSetup - } - const dotIndex = tag.indexOf('.') - if (dotIndex > 0) { - const ns = getName(tag.slice(0, dotIndex)) - if (ns) { - return ns + tag.slice(dotIndex) - } + const dotIndex = tag.indexOf('.') + if (dotIndex > 0) { + const ns = tag.slice(0, dotIndex) + if (context.identifiers[ns]) { + return ns + tag.slice(dotIndex) } } - // 4. Self referencing component (inferred from filename) + // 5. Self referencing component (inferred from filename) if ( !__BROWSER__ && context.selfName && @@ -341,7 +326,7 @@ export function resolveComponentType( return toValidAssetId(tag, `component`) } - // 5. user component (resolve) + // 6. user component (resolve) context.helper(RESOLVE_COMPONENT) context.components.add(tag) return toValidAssetId(tag, `component`) From 50f23f99d76d5f6ead3c3f25f4070c23c420434a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sat, 5 Jul 2025 22:37:14 +0200 Subject: [PATCH 3/7] fix: resolve from slot props before from setup --- .../src/transforms/transformElement.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 6781506a6e5..9f4b42b11c7 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -282,7 +282,20 @@ export function resolveComponentType( return builtIn } - // 3. user component (from setup bindings) + // 3. component from slot props + if (context.identifiers[tag]) { + return tag + } + + const dotIndex = tag.indexOf('.') + if (dotIndex > 0) { + const ns = tag.slice(0, dotIndex) + if (context.identifiers[ns]) { + return ns + tag.slice(dotIndex) + } + } + + // 4. user component (from setup bindings) // this is skipped in browser build since browser builds do not perform // binding analysis. if (!__BROWSER__) { From d3e25b9cfc8d01ef33e1616816924ebf9f809a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sat, 5 Jul 2025 22:43:49 +0200 Subject: [PATCH 4/7] fix: saveguard browser --- .../src/transforms/transformElement.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 9f4b42b11c7..29e7531af5e 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -283,15 +283,19 @@ export function resolveComponentType( } // 3. component from slot props - if (context.identifiers[tag]) { - return tag - } + // this is skipped in browser build since browser builds do not perform + // identifier tracking. + if (!__BROWSER__) { + if (context.identifiers[tag]) { + return tag + } - const dotIndex = tag.indexOf('.') - if (dotIndex > 0) { - const ns = tag.slice(0, dotIndex) - if (context.identifiers[ns]) { - return ns + tag.slice(dotIndex) + const dotIndex = tag.indexOf('.') + if (dotIndex > 0) { + const ns = tag.slice(0, dotIndex) + if (context.identifiers[ns]) { + return ns + tag.slice(dotIndex) + } } } From eb8be2865d2f3dae51c8238d0d828fc55c56f50d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sun, 6 Jul 2025 15:14:52 +0200 Subject: [PATCH 5/7] chore: cleanup and tests --- .../transforms/transformElement.spec.ts | 40 +++++++++++++++++++ packages/compiler-core/src/codegen.ts | 5 ++- packages/compiler-core/src/options.ts | 2 + packages/compiler-core/src/transform.ts | 3 +- .../src/transforms/transformElement.ts | 18 +++------ 5 files changed, 53 insertions(+), 15 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index bf3510a052d..ac7ed51cd12 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -121,6 +121,25 @@ describe('compiler: element transform', () => { expect(node.tag).toBe(`Example`) }) + test('resolve component from scoped slot bindings', () => { + const { root, node } = parseWithElementTransform( + ``, + { + inline: true, + bindingMetadata: { + Example: BindingTypes.SETUP_CONST, + }, + identifiers: { + Foo: 1, + }, + }, + ) + + expect(root.helpers).not.toContain(RESOLVE_COMPONENT) + expect(root.components).not.toContain('Foo') + expect(node.tag).toBe(`Example`) + }) + test('resolve namespaced component from setup bindings', () => { const { root, node } = parseWithElementTransform(``, { bindingMetadata: { @@ -175,6 +194,27 @@ describe('compiler: element transform', () => { expect(node.tag).toBe('_unref($props["Foo"]).Example') }) + test('resolve namespaced component from scoped slot bindings', () => { + const { root, node } = parseWithElementTransform( + ``, + { + inline: true, + bindingMetadata: { + Example: BindingTypes.SETUP_CONST, + }, + identifiers: { + SlotProps: 1, + }, + }, + ) + + console.log(root) + + expect(root.helpers).not.toContain(RESOLVE_COMPONENT) + expect(root.components).not.toContain('SlotProps') + expect(node.tag).toBe(`Example`) + }) + test('do not resolve component from non-script-setup bindings', () => { const bindingMetadata = { Example: BindingTypes.SETUP_MAYBE_REF, diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 6b4559fabb2..be577d26d7c 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -120,7 +120,10 @@ enum NewlineType { } export interface CodegenContext - extends Omit, 'bindingMetadata' | 'inline'> { + extends Omit< + Required, + 'bindingMetadata' | 'inline' | 'identifiers' + > { source: string code: string line: number diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts index 1de865f42eb..1cf7917076b 100644 --- a/packages/compiler-core/src/options.ts +++ b/packages/compiler-core/src/options.ts @@ -199,6 +199,8 @@ interface SharedTransformCodegenOptions { * binding access when `prefixIdentifiers` is enabled. */ bindingMetadata?: BindingMetadata + + identifiers?: { [name: string]: number | undefined } /** * Compile the function for inlining inside setup(). * This allows the function to directly access setup() local bindings. diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 9d8fd842935..a677d9fd14d 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -143,6 +143,7 @@ export function createTransformContext( inSSR = false, ssrCssVars = ``, bindingMetadata = EMPTY_OBJ, + identifiers = Object.create(null), inline = false, isTS = false, onError = defaultOnError, @@ -187,7 +188,7 @@ export function createTransformContext( cached: [], constantCache: new WeakMap(), temps: 0, - identifiers: Object.create(null), + identifiers, scopes: { vFor: 0, vSlot: 0, diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 29e7531af5e..b49a60227db 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -316,19 +316,6 @@ export function resolveComponentType( } } - // 4. component from slot props / other identifiers - if (context.identifiers[tag]) { - return tag - } - - const dotIndex = tag.indexOf('.') - if (dotIndex > 0) { - const ns = tag.slice(0, dotIndex) - if (context.identifiers[ns]) { - return ns + tag.slice(dotIndex) - } - } - // 5. Self referencing component (inferred from filename) if ( !__BROWSER__ && @@ -397,6 +384,11 @@ function resolveSetupReference(name: string, context: TransformContext) { context.inline ? '__props' : '$props' }[${JSON.stringify(fromProps)}])` } + + // const fromSlotScope = checkType(BindingTypes.SLOT_SCOPE) + // if (fromSlotScope) { + // return fromSlotScope + // } } export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode From 23ae7554bab775ea3b99b00cf7ccb0bb9b959b83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Sun, 6 Jul 2025 20:43:13 +0200 Subject: [PATCH 6/7] chore: remove console.log --- .../compiler-core/__tests__/transforms/transformElement.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index ac7ed51cd12..fdda72e6448 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -208,8 +208,6 @@ describe('compiler: element transform', () => { }, ) - console.log(root) - expect(root.helpers).not.toContain(RESOLVE_COMPONENT) expect(root.components).not.toContain('SlotProps') expect(node.tag).toBe(`Example`) From 08e9cf219c5371a3e21ce0ac8513e1198894d67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich-Matthias=20Sch=C3=A4fer?= Date: Mon, 7 Jul 2025 15:11:06 +0200 Subject: [PATCH 7/7] chore: cleanup comments --- packages/compiler-core/src/transforms/transformElement.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index b49a60227db..89365e45ef2 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -384,11 +384,6 @@ function resolveSetupReference(name: string, context: TransformContext) { context.inline ? '__props' : '$props' }[${JSON.stringify(fromProps)}])` } - - // const fromSlotScope = checkType(BindingTypes.SLOT_SCOPE) - // if (fromSlotScope) { - // return fromSlotScope - // } } export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode