diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap index ecf886d7c..f78e395a7 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vHtml.spec.ts.snap @@ -32,3 +32,13 @@ export function render(_ctx) { return n0 }" `; + +exports[`v-html > work with dynamic component 1`] = ` +"import { createDynamicComponent as _createDynamicComponent, setHtml as _setHtml, renderEffect as _renderEffect } from 'vue'; + +export function render(_ctx) { + const n0 = _createDynamicComponent(() => ('button'), null, null, true) + _renderEffect(() => _setHtml(n0.nodes, _ctx.foo)) + return n0 +}" +`; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap index 9a3b88acb..b17692a98 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vText.spec.ts.snap @@ -33,3 +33,13 @@ export function render(_ctx) { return n0 }" `; + +exports[`v-text > work with dynamic component 1`] = ` +"import { createDynamicComponent as _createDynamicComponent, toDisplayString as _toDisplayString, setElementText as _setElementText, renderEffect as _renderEffect } from 'vue'; + +export function render(_ctx) { + const n0 = _createDynamicComponent(() => ('button'), null, null, true) + _renderEffect(() => _setElementText(n0.nodes, _toDisplayString(_ctx.foo), true)) + return n0 +}" +`; diff --git a/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts b/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts index 0de0b6abc..0fcff932c 100644 --- a/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts @@ -54,6 +54,14 @@ describe('v-html', () => { expect(code).matchSnapshot() }) + test('work with dynamic component', () => { + const { code } = compileWithVHtml( + ``, + ) + expect(code).matchSnapshot() + expect(code).contains('setHtml(n0.nodes, _ctx.foo))') + }) + test('should raise error and ignore children when v-html is present', () => { const onError = vi.fn() const { code, ir, helpers } = compileWithVHtml( diff --git a/packages/compiler-vapor/__tests__/transforms/vText.spec.ts b/packages/compiler-vapor/__tests__/transforms/vText.spec.ts index 4f074fee8..e596062a7 100644 --- a/packages/compiler-vapor/__tests__/transforms/vText.spec.ts +++ b/packages/compiler-vapor/__tests__/transforms/vText.spec.ts @@ -58,6 +58,16 @@ describe('v-text', () => { expect(code).matchSnapshot() }) + test('work with dynamic component', () => { + const { code } = compileWithVText( + ``, + ) + expect(code).matchSnapshot() + expect(code).contains( + 'setElementText(n0.nodes, _toDisplayString(_ctx.foo), true)', + ) + }) + test('should raise error and ignore children when v-text is present', () => { const onError = vi.fn() const { code, ir } = compileWithVText(`
hello
`, { diff --git a/packages/compiler-vapor/src/generators/component.ts b/packages/compiler-vapor/src/generators/component.ts index 7c232db75..fdbc3415f 100644 --- a/packages/compiler-vapor/src/generators/component.ts +++ b/packages/compiler-vapor/src/generators/component.ts @@ -60,12 +60,15 @@ export function genCreateComponent( [], ) + const isDynamicComponent = operation.dynamic && !operation.dynamic.isStatic + if (isDynamicComponent) context.block.dynamicComponents.push(operation.id) + return [ NEWLINE, ...inlineHandlers, `const n${operation.id} = `, ...genCall( - operation.dynamic && !operation.dynamic.isStatic + isDynamicComponent ? helper('createDynamicComponent') : operation.asset ? helper('createComponentWithFallback') diff --git a/packages/compiler-vapor/src/generators/html.ts b/packages/compiler-vapor/src/generators/html.ts index 72af699dd..8fc6d07a4 100644 --- a/packages/compiler-vapor/src/generators/html.ts +++ b/packages/compiler-vapor/src/generators/html.ts @@ -7,10 +7,21 @@ export function genSetHtml( oper: SetHtmlIRNode, context: CodegenContext, ): CodeFragment[] { - const { helper } = context + const { + helper, + block: { dynamicComponents }, + } = context + + const isDynamicComponent = dynamicComponents.includes(oper.element) const { value, element } = oper return [ NEWLINE, - ...genCall(helper('setHtml'), `n${element}`, genExpression(value, context)), + ...genCall( + helper('setHtml'), + // if the element is a dynamic component (VaporFragment) + // it should set html to the VaporFragment's nodes + `n${element}${isDynamicComponent ? '.nodes' : ''}`, + genExpression(value, context), + ), ] } diff --git a/packages/compiler-vapor/src/generators/text.ts b/packages/compiler-vapor/src/generators/text.ts index 89e3167c6..1f706ebd1 100644 --- a/packages/compiler-vapor/src/generators/text.ts +++ b/packages/compiler-vapor/src/generators/text.ts @@ -9,13 +9,33 @@ export function genSetText( oper: SetTextIRNode, context: CodegenContext, ): CodeFragment[] { - const { helper } = context + const { + helper, + block: { dynamicComponents }, + } = context const { element, values, generated, jsx } = oper const texts = combineValues(values, context, jsx) - return [ - NEWLINE, - ...genCall(helper('setText'), `${generated ? 'x' : 'n'}${element}`, texts), - ] + + // if the element is a dynamic component, we need to use `setElementText` + // to set the textContent of the VaporFragment's nodes. + return dynamicComponents.includes(oper.element) + ? [ + NEWLINE, + ...genCall( + helper('setElementText'), + `n${element}.nodes`, + texts, + 'true', // isConverted + ), + ] + : [ + NEWLINE, + ...genCall( + helper('setText'), + `${generated ? 'x' : 'n'}${element}`, + texts, + ), + ] } function combineValues( @@ -40,6 +60,14 @@ export function genGetTextChild( oper: GetTextChildIRNode, context: CodegenContext, ): CodeFragment[] { + const { + block: { dynamicComponents }, + } = context + + // if the parent is a dynamic component, don't need to generate a child + // because it will use the `setElementText` helper directly. + if (dynamicComponents.includes(oper.parent)) return [] + return [ NEWLINE, `const x${oper.parent} = ${context.helper('child')}(n${oper.parent})`, diff --git a/packages/compiler-vapor/src/ir/index.ts b/packages/compiler-vapor/src/ir/index.ts index da6361132..dd105b08d 100644 --- a/packages/compiler-vapor/src/ir/index.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -49,6 +49,7 @@ export interface BlockIRNode extends BaseIRNode { type: IRNodeTypes.BLOCK node: RootNode | TemplateChildNode dynamic: IRDynamicInfo + dynamicComponents: number[] tempId: number effect: IREffect[] operation: OperationNode[] diff --git a/packages/compiler-vapor/src/transforms/utils.ts b/packages/compiler-vapor/src/transforms/utils.ts index b8e7adc60..222449fe4 100644 --- a/packages/compiler-vapor/src/transforms/utils.ts +++ b/packages/compiler-vapor/src/transforms/utils.ts @@ -26,6 +26,7 @@ export const newBlock = (node: BlockIRNode['node']): BlockIRNode => ({ type: IRNodeTypes.BLOCK, node, dynamic: newDynamic(), + dynamicComponents: [], effect: [], operation: [], returns: [], diff --git a/packages/runtime-vapor/src/dom/prop.ts b/packages/runtime-vapor/src/dom/prop.ts index 8c42ad766..04e576761 100644 --- a/packages/runtime-vapor/src/dom/prop.ts +++ b/packages/runtime-vapor/src/dom/prop.ts @@ -185,13 +185,16 @@ export function setText(el: Text & { $txt?: string }, value: string): void { } /** - * Used by setDynamicProps only, so need to guard with `toDisplayString` + * Used by + * - setDynamicProps, need to guard with `toDisplayString` + * - v-text on dynamic component, value passed here is already converted */ export function setElementText( el: Node & { $txt?: string }, value: unknown, + isConverted: boolean = false, ): void { - if (el.$txt !== (value = toDisplayString(value))) { + if (el.$txt !== (value = isConverted ? value : toDisplayString(value))) { el.textContent = el.$txt = value as string } } diff --git a/packages/runtime-vapor/src/index.ts b/packages/runtime-vapor/src/index.ts index 682532fa4..da060e7eb 100644 --- a/packages/runtime-vapor/src/index.ts +++ b/packages/runtime-vapor/src/index.ts @@ -22,6 +22,7 @@ export { setProp, setDOMProp, setDynamicProps, + setElementText, } from './dom/prop' export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event' export { createIf } from './apiCreateIf'