wip(ssr): ssr slot vnode fallback

This commit is contained in:
Evan You
2020-02-07 01:06:51 -05:00
parent 31f3383a02
commit b7a74d0439
15 changed files with 308 additions and 131 deletions

View File

@@ -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
}
}

View File

@@ -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)
}
}

View File

@@ -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
}
})

View File

@@ -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 {

View File

@@ -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: {

View File

@@ -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]} */`
)