mirror of https://github.com/vuejs/core.git
fix(compiler-sfc): fix ast reuse for ssr
This commit is contained in:
parent
678378afd5
commit
fb619cf9a4
|
|
@ -113,6 +113,7 @@ export interface RootNode extends Node {
|
|||
temps: number
|
||||
ssrHelpers?: symbol[]
|
||||
codegenNode?: TemplateChildNode | JSChildNode | BlockStatement
|
||||
transformed?: boolean
|
||||
|
||||
// v2 compat only
|
||||
filters?: string[]
|
||||
|
|
|
|||
|
|
@ -334,6 +334,7 @@ export function transform(root: RootNode, options: TransformOptions) {
|
|||
root.hoists = context.hoists
|
||||
root.temps = context.temps
|
||||
root.cached = context.cached
|
||||
root.transformed = true
|
||||
|
||||
if (__COMPAT__) {
|
||||
root.filters = [...context.filters!]
|
||||
|
|
|
|||
|
|
@ -156,6 +156,52 @@ test('should work w/ AST from descriptor', () => {
|
|||
expect(
|
||||
consumer.originalPositionFor(getPositionInCode(code, 'foobar'))
|
||||
).toMatchObject(getPositionInCode(source, `foobar`))
|
||||
|
||||
expect(code).toBe(
|
||||
compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content
|
||||
}).code
|
||||
)
|
||||
})
|
||||
|
||||
test('should work w/ AST from descriptor in SSR mode', () => {
|
||||
const source = `
|
||||
<template>
|
||||
<div><p>{{ foobar }}</p></div>
|
||||
</template>
|
||||
`
|
||||
const template = parse(source, {
|
||||
filename: 'example.vue',
|
||||
sourceMap: true
|
||||
}).descriptor.template!
|
||||
|
||||
expect(template.ast!.source).toBe(source)
|
||||
|
||||
const { code, map } = compile({
|
||||
filename: 'example.vue',
|
||||
source: '', // make sure it's actually using the AST instead of source
|
||||
ast: template.ast,
|
||||
ssr: true
|
||||
})
|
||||
|
||||
expect(map!.sources).toEqual([`example.vue`])
|
||||
// when reusing AST from SFC parse for template compile,
|
||||
// the source corresponds to the entire SFC
|
||||
expect(map!.sourcesContent).toEqual([source])
|
||||
|
||||
const consumer = new SourceMapConsumer(map as RawSourceMap)
|
||||
expect(
|
||||
consumer.originalPositionFor(getPositionInCode(code, 'foobar'))
|
||||
).toMatchObject(getPositionInCode(source, `foobar`))
|
||||
|
||||
expect(code).toBe(
|
||||
compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content,
|
||||
ssr: true
|
||||
}).code
|
||||
)
|
||||
})
|
||||
|
||||
test('should not reuse AST if using custom compiler', () => {
|
||||
|
|
@ -185,6 +231,66 @@ test('should not reuse AST if using custom compiler', () => {
|
|||
expect(code).toBe(template.content)
|
||||
})
|
||||
|
||||
test('should force re-parse on already transformed AST', () => {
|
||||
const source = `
|
||||
<template>
|
||||
<div><p>{{ foobar }}</p></div>
|
||||
</template>
|
||||
`
|
||||
const template = parse(source, {
|
||||
filename: 'example.vue',
|
||||
sourceMap: true
|
||||
}).descriptor.template!
|
||||
|
||||
// force set to empty, if this is reused then it won't generate proper code
|
||||
template.ast!.children = []
|
||||
template.ast!.transformed = true
|
||||
|
||||
const { code } = compile({
|
||||
filename: 'example.vue',
|
||||
source: '',
|
||||
ast: template.ast
|
||||
})
|
||||
|
||||
expect(code).toBe(
|
||||
compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content
|
||||
}).code
|
||||
)
|
||||
})
|
||||
|
||||
test('should force re-parse with correct compiler in SSR mode', () => {
|
||||
const source = `
|
||||
<template>
|
||||
<div><p>{{ foobar }}</p></div>
|
||||
</template>
|
||||
`
|
||||
const template = parse(source, {
|
||||
filename: 'example.vue',
|
||||
sourceMap: true
|
||||
}).descriptor.template!
|
||||
|
||||
// force set to empty, if this is reused then it won't generate proper code
|
||||
template.ast!.children = []
|
||||
template.ast!.transformed = true
|
||||
|
||||
const { code } = compile({
|
||||
filename: 'example.vue',
|
||||
source: '',
|
||||
ast: template.ast,
|
||||
ssr: true
|
||||
})
|
||||
|
||||
expect(code).toBe(
|
||||
compile({
|
||||
filename: 'example.vue',
|
||||
source: template.content,
|
||||
ssr: true
|
||||
}).code
|
||||
)
|
||||
})
|
||||
|
||||
test('template errors', () => {
|
||||
const result = compile({
|
||||
filename: 'example.vue',
|
||||
|
|
|
|||
|
|
@ -214,10 +214,10 @@ function doCompileTemplate({
|
|||
inAST = undefined
|
||||
}
|
||||
|
||||
if (inAST?.codegenNode) {
|
||||
// input AST has codegenNode - it has already been transformed and cannot
|
||||
// be reused. We need to parse a fresh one. Can't just use `source` here
|
||||
// since we need the AST location info to be relative to the entire SFC.
|
||||
if (inAST?.transformed) {
|
||||
// If input AST has already been transformed, then it cannot be reused.
|
||||
// We need to parse a fresh one. Can't just use `source` here since we need
|
||||
// the AST location info to be relative to the entire SFC.
|
||||
const newAST = (ssr ? CompilerDOM : compiler).parse(inAST.source, {
|
||||
parseMode: 'sfc',
|
||||
onError: e => errors.push(e)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,8 @@ import {
|
|||
noopDirectiveTransform,
|
||||
transformBind,
|
||||
transformStyle,
|
||||
transformOn
|
||||
transformOn,
|
||||
RootNode
|
||||
} from '@vue/compiler-dom'
|
||||
import { ssrCodegenTransform } from './ssrCodegenTransform'
|
||||
import { ssrTransformElement } from './transforms/ssrTransformElement'
|
||||
|
|
@ -28,12 +29,11 @@ import { ssrInjectFallthroughAttrs } from './transforms/ssrInjectFallthroughAttr
|
|||
import { ssrInjectCssVars } from './transforms/ssrInjectCssVars'
|
||||
|
||||
export function compile(
|
||||
template: string,
|
||||
source: string | RootNode,
|
||||
options: CompilerOptions = {}
|
||||
): CodegenResult {
|
||||
options = {
|
||||
...options,
|
||||
// apply DOM-specific parsing options
|
||||
...parserOptions,
|
||||
ssr: true,
|
||||
inSSR: true,
|
||||
|
|
@ -45,7 +45,7 @@ export function compile(
|
|||
hoistStatic: false
|
||||
}
|
||||
|
||||
const ast = baseParse(template, options)
|
||||
const ast = typeof source === 'string' ? baseParse(source, options) : source
|
||||
|
||||
// Save raw options for AST. This is needed when performing sub-transforms
|
||||
// on slot vnode branches.
|
||||
|
|
|
|||
Loading…
Reference in New Issue