wip(ssr): ssr slot vnode fallback
This commit is contained in:
@@ -51,7 +51,8 @@ export const enum NodeTypes {
|
||||
JS_BLOCK_STATEMENT,
|
||||
JS_TEMPLATE_LITERAL,
|
||||
JS_IF_STATEMENT,
|
||||
JS_ASSIGNMENT_EXPRESSION
|
||||
JS_ASSIGNMENT_EXPRESSION,
|
||||
JS_RETURN_STATEMENT
|
||||
}
|
||||
|
||||
export const enum ElementTypes {
|
||||
@@ -294,7 +295,7 @@ export interface FunctionExpression extends Node {
|
||||
type: NodeTypes.JS_FUNCTION_EXPRESSION
|
||||
params: ExpressionNode | string | (ExpressionNode | string)[] | undefined
|
||||
returns?: TemplateChildNode | TemplateChildNode[] | JSChildNode
|
||||
body?: BlockStatement
|
||||
body?: BlockStatement | IfStatement
|
||||
newline: boolean
|
||||
// so that codegen knows it needs to generate ScopeId wrapper
|
||||
isSlot: boolean
|
||||
@@ -322,7 +323,12 @@ export interface CacheExpression extends Node {
|
||||
|
||||
// SSR-specific Node Types -----------------------------------------------------
|
||||
|
||||
export type SSRCodegenNode = BlockStatement | TemplateLiteral | IfStatement
|
||||
export type SSRCodegenNode =
|
||||
| BlockStatement
|
||||
| TemplateLiteral
|
||||
| IfStatement
|
||||
| AssignmentExpression
|
||||
| ReturnStatement
|
||||
|
||||
export interface BlockStatement extends Node {
|
||||
type: NodeTypes.JS_BLOCK_STATEMENT
|
||||
@@ -338,7 +344,7 @@ export interface IfStatement extends Node {
|
||||
type: NodeTypes.JS_IF_STATEMENT
|
||||
test: ExpressionNode
|
||||
consequent: BlockStatement
|
||||
alternate: IfStatement | BlockStatement | undefined
|
||||
alternate: IfStatement | BlockStatement | ReturnStatement | undefined
|
||||
}
|
||||
|
||||
export interface AssignmentExpression extends Node {
|
||||
@@ -347,6 +353,11 @@ export interface AssignmentExpression extends Node {
|
||||
right: JSChildNode
|
||||
}
|
||||
|
||||
export interface ReturnStatement extends Node {
|
||||
type: NodeTypes.JS_RETURN_STATEMENT
|
||||
returns: TemplateChildNode | TemplateChildNode[] | JSChildNode
|
||||
}
|
||||
|
||||
// Codegen Node Types ----------------------------------------------------------
|
||||
|
||||
// createVNode(...)
|
||||
@@ -733,3 +744,13 @@ export function createAssignmentExpression(
|
||||
loc: locStub
|
||||
}
|
||||
}
|
||||
|
||||
export function createReturnStatement(
|
||||
returns: ReturnStatement['returns']
|
||||
): ReturnStatement {
|
||||
return {
|
||||
type: NodeTypes.JS_RETURN_STATEMENT,
|
||||
returns,
|
||||
loc: locStub
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@ import {
|
||||
SSRCodegenNode,
|
||||
TemplateLiteral,
|
||||
IfStatement,
|
||||
AssignmentExpression
|
||||
AssignmentExpression,
|
||||
ReturnStatement
|
||||
} from './ast'
|
||||
import { SourceMapGenerator, RawSourceMap } from 'source-map'
|
||||
import {
|
||||
@@ -44,8 +45,7 @@ import {
|
||||
CREATE_TEXT,
|
||||
PUSH_SCOPE_ID,
|
||||
POP_SCOPE_ID,
|
||||
WITH_SCOPE_ID,
|
||||
CREATE_BLOCK
|
||||
WITH_SCOPE_ID
|
||||
} from './runtimeHelpers'
|
||||
import { ImportItem } from './transform'
|
||||
|
||||
@@ -334,24 +334,12 @@ function genModulePreamble(
|
||||
context: CodegenContext,
|
||||
genScopeId: boolean
|
||||
) {
|
||||
const { push, helper, newline, scopeId, runtimeModuleName, ssr } = context
|
||||
const { push, helper, newline, scopeId, runtimeModuleName } = context
|
||||
|
||||
if (!__BROWSER__) {
|
||||
// in ssr mode, `withId` helper is only needed if the template contains
|
||||
// de-optimized component slots (which uses the createVNode helper)
|
||||
if (
|
||||
ssr &&
|
||||
!(
|
||||
ast.helpers.includes(CREATE_VNODE) || ast.helpers.includes(CREATE_BLOCK)
|
||||
)
|
||||
) {
|
||||
genScopeId = false
|
||||
}
|
||||
if (genScopeId) {
|
||||
ast.helpers.push(WITH_SCOPE_ID)
|
||||
if (ast.hoists.length) {
|
||||
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
|
||||
}
|
||||
if (!__BROWSER__ && genScopeId) {
|
||||
ast.helpers.push(WITH_SCOPE_ID)
|
||||
if (ast.hoists.length) {
|
||||
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -572,6 +560,9 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
|
||||
case NodeTypes.JS_ASSIGNMENT_EXPRESSION:
|
||||
!__BROWSER__ && genAssignmentExpression(node, context)
|
||||
break
|
||||
case NodeTypes.JS_RETURN_STATEMENT:
|
||||
!__BROWSER__ && genReturnStatement(node, context)
|
||||
break
|
||||
|
||||
/* istanbul ignore next */
|
||||
default:
|
||||
@@ -851,3 +842,15 @@ function genAssignmentExpression(
|
||||
context.push(` = `)
|
||||
genNode(node.right, context)
|
||||
}
|
||||
|
||||
function genReturnStatement(
|
||||
{ returns }: ReturnStatement,
|
||||
context: CodegenContext
|
||||
) {
|
||||
context.push(`return `)
|
||||
if (isArray(returns)) {
|
||||
genNodeListAsArray(returns, context)
|
||||
} else {
|
||||
genNode(returns, context)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CompilerOptions } from './options'
|
||||
import { baseParse } from './parse'
|
||||
import { transform } from './transform'
|
||||
import { transform, NodeTransform, DirectiveTransform } from './transform'
|
||||
import { generate, CodegenResult } from './codegen'
|
||||
import { RootNode } from './ast'
|
||||
import { isString } from '@vue/shared'
|
||||
@@ -17,6 +17,39 @@ import { transformOnce } from './transforms/vOnce'
|
||||
import { transformModel } from './transforms/vModel'
|
||||
import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
|
||||
|
||||
export type TransformPreset = [
|
||||
NodeTransform[],
|
||||
Record<string, DirectiveTransform>
|
||||
]
|
||||
|
||||
export function getBaseTransformPreset(
|
||||
prefixIdentifiers?: boolean
|
||||
): TransformPreset {
|
||||
return [
|
||||
[
|
||||
transformOnce,
|
||||
transformIf,
|
||||
transformFor,
|
||||
...(!__BROWSER__ && prefixIdentifiers
|
||||
? [
|
||||
// order is important
|
||||
trackVForSlotScopes,
|
||||
transformExpression
|
||||
]
|
||||
: []),
|
||||
transformSlotOutlet,
|
||||
transformElement,
|
||||
trackSlotScopes,
|
||||
transformText
|
||||
],
|
||||
{
|
||||
on: transformOn,
|
||||
bind: transformBind,
|
||||
model: transformModel
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
// we name it `baseCompile` so that higher order compilers like
|
||||
// @vue/compiler-dom can export `compile` while re-exporting everything else.
|
||||
export function baseCompile(
|
||||
@@ -44,30 +77,18 @@ export function baseCompile(
|
||||
}
|
||||
|
||||
const ast = isString(template) ? baseParse(template, options) : template
|
||||
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(
|
||||
prefixIdentifiers
|
||||
)
|
||||
transform(ast, {
|
||||
...options,
|
||||
prefixIdentifiers,
|
||||
nodeTransforms: [
|
||||
transformOnce,
|
||||
transformIf,
|
||||
transformFor,
|
||||
...(prefixIdentifiers
|
||||
? [
|
||||
// order is important
|
||||
trackVForSlotScopes,
|
||||
transformExpression
|
||||
]
|
||||
: []),
|
||||
transformSlotOutlet,
|
||||
transformElement,
|
||||
trackSlotScopes,
|
||||
transformText,
|
||||
...nodeTransforms,
|
||||
...(options.nodeTransforms || []) // user transforms
|
||||
],
|
||||
directiveTransforms: {
|
||||
on: transformOn,
|
||||
bind: transformBind,
|
||||
model: transformModel,
|
||||
...directiveTransforms,
|
||||
...(options.directiveTransforms || {}) // user transforms
|
||||
}
|
||||
})
|
||||
|
||||
@@ -10,8 +10,8 @@ export {
|
||||
export { baseParse, TextModes } from './parse'
|
||||
export {
|
||||
transform,
|
||||
createStructuralDirectiveTransform,
|
||||
TransformContext,
|
||||
createStructuralDirectiveTransform,
|
||||
NodeTransform,
|
||||
StructuralDirectiveTransform,
|
||||
DirectiveTransform
|
||||
@@ -23,18 +23,16 @@ export {
|
||||
CompilerError,
|
||||
createCompilerError
|
||||
} from './errors'
|
||||
|
||||
export * from './ast'
|
||||
export * from './utils'
|
||||
export { registerRuntimeHelpers } from './runtimeHelpers'
|
||||
export { noopDirectiveTransform } from './transforms/noopDirectiveTransform'
|
||||
export * from './runtimeHelpers'
|
||||
|
||||
// expose transforms so higher-order compilers can import and extend them
|
||||
export { getBaseTransformPreset, TransformPreset } from './compile'
|
||||
export { transformModel } from './transforms/vModel'
|
||||
export { transformOn } from './transforms/vOn'
|
||||
export { transformBind } from './transforms/vBind'
|
||||
|
||||
// exported for compiler-ssr
|
||||
export * from './runtimeHelpers'
|
||||
export { noopDirectiveTransform } from './transforms/noopDirectiveTransform'
|
||||
export { processIf } from './transforms/vIf'
|
||||
export { processFor, createForLoopParams } from './transforms/vFor'
|
||||
export {
|
||||
|
||||
@@ -85,8 +85,8 @@ export interface TransformContext extends Required<TransformOptions> {
|
||||
components: Set<string>
|
||||
directives: Set<string>
|
||||
hoists: JSChildNode[]
|
||||
temps: number
|
||||
imports: Set<ImportItem>
|
||||
temps: number
|
||||
cached: number
|
||||
identifiers: { [name: string]: number | undefined }
|
||||
scopes: {
|
||||
@@ -141,8 +141,8 @@ function createTransformContext(
|
||||
components: new Set(),
|
||||
directives: new Set(),
|
||||
hoists: [],
|
||||
temps: 0,
|
||||
imports: new Set(),
|
||||
temps: 0,
|
||||
cached: 0,
|
||||
identifiers: {},
|
||||
scopes: {
|
||||
|
||||
@@ -77,7 +77,7 @@ export const transformText: NodeTransform = (node, context) => {
|
||||
callArgs.push(child)
|
||||
}
|
||||
// mark dynamic text with flag so it gets patched inside a block
|
||||
if (child.type !== NodeTypes.TEXT) {
|
||||
if (!context.ssr && child.type !== NodeTypes.TEXT) {
|
||||
callArgs.push(
|
||||
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user