Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
}"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -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
}"
`;
8 changes: 8 additions & 0 deletions packages/compiler-vapor/__tests__/transforms/vHtml.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,14 @@ describe('v-html', () => {
expect(code).matchSnapshot()
})

test('work with dynamic component', () => {
const { code } = compileWithVHtml(
`<component :is="'button'" v-html="foo"/>`,
)
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(
Expand Down
10 changes: 10 additions & 0 deletions packages/compiler-vapor/__tests__/transforms/vText.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ describe('v-text', () => {
expect(code).matchSnapshot()
})

test('work with dynamic component', () => {
const { code } = compileWithVText(
`<component :is="'button'" v-text="foo"/>`,
)
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(`<div v-text="test">hello</div>`, {
Expand Down
5 changes: 4 additions & 1 deletion packages/compiler-vapor/src/generators/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
15 changes: 13 additions & 2 deletions packages/compiler-vapor/src/generators/html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
),
]
}
38 changes: 33 additions & 5 deletions packages/compiler-vapor/src/generators/text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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})`,
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/ir/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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[]
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-vapor/src/transforms/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export const newBlock = (node: BlockIRNode['node']): BlockIRNode => ({
type: IRNodeTypes.BLOCK,
node,
dynamic: newDynamic(),
dynamicComponents: [],
effect: [],
operation: [],
returns: [],
Expand Down
7 changes: 5 additions & 2 deletions packages/runtime-vapor/src/dom/prop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-vapor/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export {
setProp,
setDOMProp,
setDynamicProps,
setElementText,
} from './dom/prop'
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
export { createIf } from './apiCreateIf'
Expand Down