]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(vue): properly cache runtime compilation
authorEvan You <yyx990803@gmail.com>
Wed, 11 Dec 2019 14:46:42 +0000 (09:46 -0500)
committerEvan You <yyx990803@gmail.com>
Wed, 11 Dec 2019 14:46:42 +0000 (09:46 -0500)
packages/compiler-sfc/src/index.ts
packages/runtime-core/src/apiOptions.ts
packages/vue/__tests__/index.spec.ts
packages/vue/src/index.ts

index 7c8918bee4a18904768c2e6a36da907011bff759..984fe76ad81987c2203cbe21de24fb6c4e7829ca 100644 (file)
@@ -12,5 +12,10 @@ export {
   SFCScriptBlock,
   SFCStyleBlock
 } from './parse'
-
+export {
+  TemplateCompiler,
+  TemplateCompileOptions,
+  TemplateCompileResults
+} from './compileTemplate'
 export { StyleCompileOptions, StyleCompileResults } from './compileStyle'
+export { CompilerOptions } from '@vue/compiler-core'
index a3aad5df365ac9884d39ba67034c2f37e6286ac6..80e158849f1fc33fd2c0f8402796a0627d0d191e 100644 (file)
@@ -55,7 +55,7 @@ export interface ComponentOptionsBase<
     ctx: SetupContext
   ) => RawBindings | RenderFunction | void
   name?: string
-  template?: string
+  template?: string | object // can be a direct DOM node
   // Note: we are intentionally using the signature-less `Function` type here
   // since any type with signature will cause the whole inference to fail when
   // the return expression contains reference to `this`.
index 58fad59741784dc8f310115f1a0473e3fb90ae44..a8d57b38def83e916acf555a05a01fdf625e97d3 100644 (file)
@@ -4,7 +4,7 @@ import { mockWarn } from '@vue/runtime-test'
 describe('compiler + runtime integration', () => {
   mockWarn()
 
-  it('should support on-the-fly template compilation', () => {
+  it('should support runtime template compilation', () => {
     const container = document.createElement('div')
     const App = {
       template: `{{ count }}`,
@@ -18,6 +18,43 @@ describe('compiler + runtime integration', () => {
     expect(container.innerHTML).toBe(`0`)
   })
 
+  it('should support runtime template via CSS ID selector', () => {
+    const container = document.createElement('div')
+    const template = document.createElement('div')
+    template.id = 'template'
+    template.innerHTML = '{{ count }}'
+    document.body.appendChild(template)
+
+    const App = {
+      template: `#template`,
+      data() {
+        return {
+          count: 0
+        }
+      }
+    }
+    createApp().mount(App, container)
+    expect(container.innerHTML).toBe(`0`)
+  })
+
+  it('should support runtime template via direct DOM node', () => {
+    const container = document.createElement('div')
+    const template = document.createElement('div')
+    template.id = 'template'
+    template.innerHTML = '{{ count }}'
+
+    const App = {
+      template,
+      data() {
+        return {
+          count: 0
+        }
+      }
+    }
+    createApp().mount(App, container)
+    expect(container.innerHTML).toBe(`0`)
+  })
+
   it('should warn template compilation errors with codeframe', () => {
     const container = document.createElement('div')
     const App = {
index 1bdf58c2d07f38f6ae3afe1b7b8f4c9c6dc4a908..17b77dfd2edd971620b39cd5d3afa8872a4c20b9 100644 (file)
@@ -5,32 +5,36 @@ import { registerRuntimeCompiler, RenderFunction, warn } from '@vue/runtime-dom'
 import * as runtimeDom from '@vue/runtime-dom'
 import { isString, NOOP } from '@vue/shared'
 
-const idToTemplateCache = Object.create(null)
+const compileCache: Record<string, RenderFunction> = Object.create(null)
 
 function compileToFunction(
   template: string | HTMLElement,
   options?: CompilerOptions
 ): RenderFunction {
-  if (isString(template)) {
-    if (template[0] === '#') {
-      if (template in idToTemplateCache) {
-        template = idToTemplateCache[template]
-      } else {
-        const el = document.querySelector(template)
-        if (__DEV__ && !el) {
-          warn(`Template element not found or is empty: ${template}`)
-        }
-        template = idToTemplateCache[template] = el ? el.innerHTML : ``
-      }
+  if (!isString(template)) {
+    if (template.nodeType) {
+      template = template.innerHTML
+    } else {
+      __DEV__ && warn(`invalid template option: `, template)
+      return NOOP
     }
-  } else if (template.nodeType) {
-    template = template.innerHTML
-  } else {
-    __DEV__ && warn(`invalid template option: `, template)
-    return NOOP
   }
 
-  const { code } = compile(template as string, {
+  const key = template
+  const cached = compileCache[key]
+  if (cached) {
+    return cached
+  }
+
+  if (template[0] === '#') {
+    const el = document.querySelector(template)
+    if (__DEV__ && !el) {
+      warn(`Template element not found or is empty: ${template}`)
+    }
+    template = el ? el.innerHTML : ``
+  }
+
+  const { code } = compile(template, {
     hoistStatic: true,
     cacheHandlers: true,
     ...options
@@ -38,7 +42,7 @@ function compileToFunction(
 
   const render = new Function('Vue', code)(runtimeDom) as RenderFunction
   render.isRuntimeCompiled = true
-  return render
+  return (compileCache[key] = render)
 }
 
 registerRuntimeCompiler(compileToFunction)