]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(runtime-vapor): support svg and MathML
authordaiwei <daiwei521@126.com>
Fri, 25 Jul 2025 08:10:29 +0000 (16:10 +0800)
committerdaiwei <daiwei521@126.com>
Fri, 25 Jul 2025 08:10:29 +0000 (16:10 +0800)
packages/compiler-vapor/src/generators/template.ts
packages/compiler-vapor/src/ir/index.ts
packages/compiler-vapor/src/transform.ts
packages/runtime-dom/src/index.ts
packages/runtime-vapor/src/dom/template.ts

index 5a066b09e9a622435465988ab2af5cb4736222e6..3b8886d8b926aba209a530d022a7a4fcabf668ae 100644 (file)
@@ -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('')
 }
 
index 18f0139ab568e4f082c88241bca7f6a87b53bb98..b53c2ae6adba2299cf8cb48ca92ca73cb30d31cb 100644 (file)
@@ -60,6 +60,7 @@ export interface RootIRNode {
   node: RootNode
   source: string
   template: string[]
+  templateNS: Map<string, number>
   rootTemplateIndex?: number
   component: Set<string>
   directive: Set<string>
index 946c89b734afecb32ebdc9a0c2a7c39a9f51f597..bce40a46c398ed65644c826e6c21e764a94914c8 100644 (file)
@@ -6,6 +6,7 @@ import {
   type ElementNode,
   ElementTypes,
   NodeTypes,
+  type PlainElementNode,
   type RootNode,
   type SimpleExpressionNode,
   type TemplateChildNode,
@@ -73,6 +74,7 @@ export class TransformContext<T extends AllNode = AllNode> {
   >
 
   template: string = ''
+  templateNS: Map<string, number> = new Map<string, number>()
   childrenTemplate: (string | null)[] = []
   dynamic: IRDynamicInfo = this.ir.block.dynamic
 
@@ -98,10 +100,12 @@ export class TransformContext<T extends AllNode = AllNode> {
   }
 
   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<string, number>()
     this.childrenTemplate = []
     this.slots = []
     isVFor && this.inVFor++
@@ -110,6 +114,7 @@ export class TransformContext<T extends AllNode = AllNode> {
       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<T extends AllNode = AllNode> {
     )
     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<string, number>(),
     component: new Set(),
     directive: new Set(),
     block: newBlock(node),
index b241458dba798cc31280d7b2f9fd981de42f979d..4c43efd4e7f45eea8f6e92842773a7e11375ed05 100644 (file)
@@ -348,3 +348,7 @@ export {
   vModelSelectInit,
   vModelSetSelected,
 } from './directives/vModel'
+/**
+ * @internal
+ */
+export { svgNS, mathmlNS } from './nodeOps'
index b78ca4e52cfb8fa988d1de60ad7879a00f8f3566..684626a1aabad41b0bdf0ca338a0aedb9e7cdb49 100644 (file)
@@ -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