fix(vue): properly cache runtime compilation
This commit is contained in:
parent
559fa27185
commit
d3d4fe84cd
@ -12,5 +12,10 @@ export {
|
|||||||
SFCScriptBlock,
|
SFCScriptBlock,
|
||||||
SFCStyleBlock
|
SFCStyleBlock
|
||||||
} from './parse'
|
} from './parse'
|
||||||
|
export {
|
||||||
|
TemplateCompiler,
|
||||||
|
TemplateCompileOptions,
|
||||||
|
TemplateCompileResults
|
||||||
|
} from './compileTemplate'
|
||||||
export { StyleCompileOptions, StyleCompileResults } from './compileStyle'
|
export { StyleCompileOptions, StyleCompileResults } from './compileStyle'
|
||||||
|
export { CompilerOptions } from '@vue/compiler-core'
|
||||||
|
@ -55,7 +55,7 @@ export interface ComponentOptionsBase<
|
|||||||
ctx: SetupContext
|
ctx: SetupContext
|
||||||
) => RawBindings | RenderFunction | void
|
) => RawBindings | RenderFunction | void
|
||||||
name?: string
|
name?: string
|
||||||
template?: string
|
template?: string | object // can be a direct DOM node
|
||||||
// Note: we are intentionally using the signature-less `Function` type here
|
// Note: we are intentionally using the signature-less `Function` type here
|
||||||
// since any type with signature will cause the whole inference to fail when
|
// since any type with signature will cause the whole inference to fail when
|
||||||
// the return expression contains reference to `this`.
|
// the return expression contains reference to `this`.
|
||||||
|
@ -4,7 +4,7 @@ import { mockWarn } from '@vue/runtime-test'
|
|||||||
describe('compiler + runtime integration', () => {
|
describe('compiler + runtime integration', () => {
|
||||||
mockWarn()
|
mockWarn()
|
||||||
|
|
||||||
it('should support on-the-fly template compilation', () => {
|
it('should support runtime template compilation', () => {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
const App = {
|
const App = {
|
||||||
template: `{{ count }}`,
|
template: `{{ count }}`,
|
||||||
@ -18,6 +18,43 @@ describe('compiler + runtime integration', () => {
|
|||||||
expect(container.innerHTML).toBe(`0`)
|
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', () => {
|
it('should warn template compilation errors with codeframe', () => {
|
||||||
const container = document.createElement('div')
|
const container = document.createElement('div')
|
||||||
const App = {
|
const App = {
|
||||||
|
@ -5,32 +5,36 @@ import { registerRuntimeCompiler, RenderFunction, warn } from '@vue/runtime-dom'
|
|||||||
import * as runtimeDom from '@vue/runtime-dom'
|
import * as runtimeDom from '@vue/runtime-dom'
|
||||||
import { isString, NOOP } from '@vue/shared'
|
import { isString, NOOP } from '@vue/shared'
|
||||||
|
|
||||||
const idToTemplateCache = Object.create(null)
|
const compileCache: Record<string, RenderFunction> = Object.create(null)
|
||||||
|
|
||||||
function compileToFunction(
|
function compileToFunction(
|
||||||
template: string | HTMLElement,
|
template: string | HTMLElement,
|
||||||
options?: CompilerOptions
|
options?: CompilerOptions
|
||||||
): RenderFunction {
|
): RenderFunction {
|
||||||
if (isString(template)) {
|
if (!isString(template)) {
|
||||||
if (template[0] === '#') {
|
if (template.nodeType) {
|
||||||
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 : ``
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (template.nodeType) {
|
|
||||||
template = template.innerHTML
|
template = template.innerHTML
|
||||||
} else {
|
} else {
|
||||||
__DEV__ && warn(`invalid template option: `, template)
|
__DEV__ && warn(`invalid template option: `, template)
|
||||||
return NOOP
|
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,
|
hoistStatic: true,
|
||||||
cacheHandlers: true,
|
cacheHandlers: true,
|
||||||
...options
|
...options
|
||||||
@ -38,7 +42,7 @@ function compileToFunction(
|
|||||||
|
|
||||||
const render = new Function('Vue', code)(runtimeDom) as RenderFunction
|
const render = new Function('Vue', code)(runtimeDom) as RenderFunction
|
||||||
render.isRuntimeCompiled = true
|
render.isRuntimeCompiled = true
|
||||||
return render
|
return (compileCache[key] = render)
|
||||||
}
|
}
|
||||||
|
|
||||||
registerRuntimeCompiler(compileToFunction)
|
registerRuntimeCompiler(compileToFunction)
|
||||||
|
Loading…
Reference in New Issue
Block a user