From: daiwei Date: Fri, 25 Jul 2025 08:10:29 +0000 (+0800) Subject: feat(runtime-vapor): support svg and MathML X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=40b1e1e5deecdebc986304090f981063e842f80b;p=thirdparty%2Fvuejs%2Fcore.git feat(runtime-vapor): support svg and MathML --- diff --git a/packages/compiler-vapor/src/generators/template.ts b/packages/compiler-vapor/src/generators/template.ts index 5a066b09e9..3b8886d8b9 100644 --- a/packages/compiler-vapor/src/generators/template.ts +++ b/packages/compiler-vapor/src/generators/template.ts @@ -7,15 +7,15 @@ import { type CodeFragment, NEWLINE, buildCodeFragment, genCall } from './utils' export function genTemplates( templates: string[], rootIndex: number | undefined, - { helper }: CodegenContext, + { helper, ir: { templateNS } }: CodegenContext, ): string { return templates - .map( - (template, i) => - `const t${i} = ${helper('template')}(${JSON.stringify( - template, - )}${i === rootIndex ? ', true' : ''})\n`, - ) + .map((template, i) => { + const ns = templateNS.get(template) + return `const t${i} = ${helper('template')}(${JSON.stringify( + template, + )}${i === rootIndex ? ', true' : ns ? ', false' : ''}${ns ? `, ${ns}` : ''})\n` + }) .join('') } diff --git a/packages/compiler-vapor/src/ir/index.ts b/packages/compiler-vapor/src/ir/index.ts index 18f0139ab5..b53c2ae6ad 100644 --- a/packages/compiler-vapor/src/ir/index.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -60,6 +60,7 @@ export interface RootIRNode { node: RootNode source: string template: string[] + templateNS: Map rootTemplateIndex?: number component: Set directive: Set diff --git a/packages/compiler-vapor/src/transform.ts b/packages/compiler-vapor/src/transform.ts index 946c89b734..bce40a46c3 100644 --- a/packages/compiler-vapor/src/transform.ts +++ b/packages/compiler-vapor/src/transform.ts @@ -6,6 +6,7 @@ import { type ElementNode, ElementTypes, NodeTypes, + type PlainElementNode, type RootNode, type SimpleExpressionNode, type TemplateChildNode, @@ -73,6 +74,7 @@ export class TransformContext { > template: string = '' + templateNS: Map = new Map() childrenTemplate: (string | null)[] = [] dynamic: IRDynamicInfo = this.ir.block.dynamic @@ -98,10 +100,12 @@ export class TransformContext { } enterBlock(ir: BlockIRNode, isVFor: boolean = false): () => void { - const { block, template, dynamic, childrenTemplate, slots } = this + const { block, template, templateNS, dynamic, childrenTemplate, slots } = + this this.block = ir this.dynamic = ir.dynamic this.template = '' + this.templateNS = new Map() this.childrenTemplate = [] this.slots = [] isVFor && this.inVFor++ @@ -110,6 +114,7 @@ export class TransformContext { this.registerTemplate() this.block = block this.template = template + this.templateNS = templateNS this.dynamic = dynamic this.childrenTemplate = childrenTemplate this.slots = slots @@ -130,6 +135,7 @@ export class TransformContext { ) if (existing !== -1) return existing this.ir.template.push(content) + this.ir.templateNS.set(content, (this.node as PlainElementNode).ns) return this.ir.template.length - 1 } registerTemplate(): number { @@ -215,6 +221,7 @@ export function transform( node, source: node.source, template: [], + templateNS: new Map(), component: new Set(), directive: new Set(), block: newBlock(node), diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index b241458dba..4c43efd4e7 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -348,3 +348,7 @@ export { vModelSelectInit, vModelSetSelected, } from './directives/vModel' +/** + * @internal + */ +export { svgNS, mathmlNS } from './nodeOps' diff --git a/packages/runtime-vapor/src/dom/template.ts b/packages/runtime-vapor/src/dom/template.ts index b78ca4e52c..684626a1aa 100644 --- a/packages/runtime-vapor/src/dom/template.ts +++ b/packages/runtime-vapor/src/dom/template.ts @@ -1,10 +1,13 @@ +import { mathmlNS, svgNS } from '@vue/runtime-dom' import { adoptTemplate, currentHydrationNode, isHydrating } from './hydration' import { child, createTextNode } from './node' let t: HTMLTemplateElement +let st: HTMLTemplateElement +let mt: HTMLTemplateElement /*! #__NO_SIDE_EFFECTS__ */ -export function template(html: string, root?: boolean) { +export function template(html: string, root?: boolean, ns?: number) { let node: Node return (): Node & { $root?: true } => { if (isHydrating) { @@ -19,9 +22,19 @@ export function template(html: string, root?: boolean) { return createTextNode(html) } if (!node) { - t = t || document.createElement('template') - t.innerHTML = html - node = child(t.content) + if (!ns) { + t = t || document.createElement('template') + t.innerHTML = html + node = child(t.content) + } else if (ns === 1) { + st = st || document.createElementNS(svgNS, 'template') + st.innerHTML = html + node = child(st) + } else { + mt = mt || document.createElementNS(mathmlNS, 'template') + mt.innerHTML = html + node = child(mt) + } } const ret = node.cloneNode(true) if (root) (ret as any).$root = true