Skip to content

Commit b7a74d0

Browse files
committed
wip(ssr): ssr slot vnode fallback
1 parent 31f3383 commit b7a74d0

File tree

15 files changed

+306
-129
lines changed

15 files changed

+306
-129
lines changed

packages/compiler-core/src/ast.ts

+25-4
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,8 @@ export const enum NodeTypes {
5151
JS_BLOCK_STATEMENT,
5252
JS_TEMPLATE_LITERAL,
5353
JS_IF_STATEMENT,
54-
JS_ASSIGNMENT_EXPRESSION
54+
JS_ASSIGNMENT_EXPRESSION,
55+
JS_RETURN_STATEMENT
5556
}
5657

5758
export const enum ElementTypes {
@@ -294,7 +295,7 @@ export interface FunctionExpression extends Node {
294295
type: NodeTypes.JS_FUNCTION_EXPRESSION
295296
params: ExpressionNode | string | (ExpressionNode | string)[] | undefined
296297
returns?: TemplateChildNode | TemplateChildNode[] | JSChildNode
297-
body?: BlockStatement
298+
body?: BlockStatement | IfStatement
298299
newline: boolean
299300
// so that codegen knows it needs to generate ScopeId wrapper
300301
isSlot: boolean
@@ -322,7 +323,12 @@ export interface CacheExpression extends Node {
322323

323324
// SSR-specific Node Types -----------------------------------------------------
324325

325-
export type SSRCodegenNode = BlockStatement | TemplateLiteral | IfStatement
326+
export type SSRCodegenNode =
327+
| BlockStatement
328+
| TemplateLiteral
329+
| IfStatement
330+
| AssignmentExpression
331+
| ReturnStatement
326332

327333
export interface BlockStatement extends Node {
328334
type: NodeTypes.JS_BLOCK_STATEMENT
@@ -338,7 +344,7 @@ export interface IfStatement extends Node {
338344
type: NodeTypes.JS_IF_STATEMENT
339345
test: ExpressionNode
340346
consequent: BlockStatement
341-
alternate: IfStatement | BlockStatement | undefined
347+
alternate: IfStatement | BlockStatement | ReturnStatement | undefined
342348
}
343349

344350
export interface AssignmentExpression extends Node {
@@ -347,6 +353,11 @@ export interface AssignmentExpression extends Node {
347353
right: JSChildNode
348354
}
349355

356+
export interface ReturnStatement extends Node {
357+
type: NodeTypes.JS_RETURN_STATEMENT
358+
returns: TemplateChildNode | TemplateChildNode[] | JSChildNode
359+
}
360+
350361
// Codegen Node Types ----------------------------------------------------------
351362

352363
// createVNode(...)
@@ -733,3 +744,13 @@ export function createAssignmentExpression(
733744
loc: locStub
734745
}
735746
}
747+
748+
export function createReturnStatement(
749+
returns: ReturnStatement['returns']
750+
): ReturnStatement {
751+
return {
752+
type: NodeTypes.JS_RETURN_STATEMENT,
753+
returns,
754+
loc: locStub
755+
}
756+
}

packages/compiler-core/src/codegen.ts

+23-20
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
SSRCodegenNode,
2323
TemplateLiteral,
2424
IfStatement,
25-
AssignmentExpression
25+
AssignmentExpression,
26+
ReturnStatement
2627
} from './ast'
2728
import { SourceMapGenerator, RawSourceMap } from 'source-map'
2829
import {
@@ -44,8 +45,7 @@ import {
4445
CREATE_TEXT,
4546
PUSH_SCOPE_ID,
4647
POP_SCOPE_ID,
47-
WITH_SCOPE_ID,
48-
CREATE_BLOCK
48+
WITH_SCOPE_ID
4949
} from './runtimeHelpers'
5050
import { ImportItem } from './transform'
5151

@@ -334,24 +334,12 @@ function genModulePreamble(
334334
context: CodegenContext,
335335
genScopeId: boolean
336336
) {
337-
const { push, helper, newline, scopeId, runtimeModuleName, ssr } = context
337+
const { push, helper, newline, scopeId, runtimeModuleName } = context
338338

339-
if (!__BROWSER__) {
340-
// in ssr mode, `withId` helper is only needed if the template contains
341-
// de-optimized component slots (which uses the createVNode helper)
342-
if (
343-
ssr &&
344-
!(
345-
ast.helpers.includes(CREATE_VNODE) || ast.helpers.includes(CREATE_BLOCK)
346-
)
347-
) {
348-
genScopeId = false
349-
}
350-
if (genScopeId) {
351-
ast.helpers.push(WITH_SCOPE_ID)
352-
if (ast.hoists.length) {
353-
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
354-
}
339+
if (!__BROWSER__ && genScopeId) {
340+
ast.helpers.push(WITH_SCOPE_ID)
341+
if (ast.hoists.length) {
342+
ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID)
355343
}
356344
}
357345

@@ -572,6 +560,9 @@ function genNode(node: CodegenNode | symbol | string, context: CodegenContext) {
572560
case NodeTypes.JS_ASSIGNMENT_EXPRESSION:
573561
!__BROWSER__ && genAssignmentExpression(node, context)
574562
break
563+
case NodeTypes.JS_RETURN_STATEMENT:
564+
!__BROWSER__ && genReturnStatement(node, context)
565+
break
575566

576567
/* istanbul ignore next */
577568
default:
@@ -851,3 +842,15 @@ function genAssignmentExpression(
851842
context.push(` = `)
852843
genNode(node.right, context)
853844
}
845+
846+
function genReturnStatement(
847+
{ returns }: ReturnStatement,
848+
context: CodegenContext
849+
) {
850+
context.push(`return `)
851+
if (isArray(returns)) {
852+
genNodeListAsArray(returns, context)
853+
} else {
854+
genNode(returns, context)
855+
}
856+
}

packages/compiler-core/src/compile.ts

+39-18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { CompilerOptions } from './options'
22
import { baseParse } from './parse'
3-
import { transform } from './transform'
3+
import { transform, NodeTransform, DirectiveTransform } from './transform'
44
import { generate, CodegenResult } from './codegen'
55
import { RootNode } from './ast'
66
import { isString } from '@vue/shared'
@@ -17,6 +17,39 @@ import { transformOnce } from './transforms/vOnce'
1717
import { transformModel } from './transforms/vModel'
1818
import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
1919

20+
export type TransformPreset = [
21+
NodeTransform[],
22+
Record<string, DirectiveTransform>
23+
]
24+
25+
export function getBaseTransformPreset(
26+
prefixIdentifiers?: boolean
27+
): TransformPreset {
28+
return [
29+
[
30+
transformOnce,
31+
transformIf,
32+
transformFor,
33+
...(!__BROWSER__ && prefixIdentifiers
34+
? [
35+
// order is important
36+
trackVForSlotScopes,
37+
transformExpression
38+
]
39+
: []),
40+
transformSlotOutlet,
41+
transformElement,
42+
trackSlotScopes,
43+
transformText
44+
],
45+
{
46+
on: transformOn,
47+
bind: transformBind,
48+
model: transformModel
49+
}
50+
]
51+
}
52+
2053
// we name it `baseCompile` so that higher order compilers like
2154
// @vue/compiler-dom can export `compile` while re-exporting everything else.
2255
export function baseCompile(
@@ -44,30 +77,18 @@ export function baseCompile(
4477
}
4578

4679
const ast = isString(template) ? baseParse(template, options) : template
80+
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(
81+
prefixIdentifiers
82+
)
4783
transform(ast, {
4884
...options,
4985
prefixIdentifiers,
5086
nodeTransforms: [
51-
transformOnce,
52-
transformIf,
53-
transformFor,
54-
...(prefixIdentifiers
55-
? [
56-
// order is important
57-
trackVForSlotScopes,
58-
transformExpression
59-
]
60-
: []),
61-
transformSlotOutlet,
62-
transformElement,
63-
trackSlotScopes,
64-
transformText,
87+
...nodeTransforms,
6588
...(options.nodeTransforms || []) // user transforms
6689
],
6790
directiveTransforms: {
68-
on: transformOn,
69-
bind: transformBind,
70-
model: transformModel,
91+
...directiveTransforms,
7192
...(options.directiveTransforms || {}) // user transforms
7293
}
7394
})

packages/compiler-core/src/index.ts

+5-7
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export {
1010
export { baseParse, TextModes } from './parse'
1111
export {
1212
transform,
13-
createStructuralDirectiveTransform,
1413
TransformContext,
14+
createStructuralDirectiveTransform,
1515
NodeTransform,
1616
StructuralDirectiveTransform,
1717
DirectiveTransform
@@ -23,18 +23,16 @@ export {
2323
CompilerError,
2424
createCompilerError
2525
} from './errors'
26+
2627
export * from './ast'
2728
export * from './utils'
28-
export { registerRuntimeHelpers } from './runtimeHelpers'
29-
export { noopDirectiveTransform } from './transforms/noopDirectiveTransform'
29+
export * from './runtimeHelpers'
3030

31-
// expose transforms so higher-order compilers can import and extend them
31+
export { getBaseTransformPreset, TransformPreset } from './compile'
3232
export { transformModel } from './transforms/vModel'
3333
export { transformOn } from './transforms/vOn'
3434
export { transformBind } from './transforms/vBind'
35-
36-
// exported for compiler-ssr
37-
export * from './runtimeHelpers'
35+
export { noopDirectiveTransform } from './transforms/noopDirectiveTransform'
3836
export { processIf } from './transforms/vIf'
3937
export { processFor, createForLoopParams } from './transforms/vFor'
4038
export {

packages/compiler-core/src/transform.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,8 @@ export interface TransformContext extends Required<TransformOptions> {
8585
components: Set<string>
8686
directives: Set<string>
8787
hoists: JSChildNode[]
88-
temps: number
8988
imports: Set<ImportItem>
89+
temps: number
9090
cached: number
9191
identifiers: { [name: string]: number | undefined }
9292
scopes: {
@@ -141,8 +141,8 @@ function createTransformContext(
141141
components: new Set(),
142142
directives: new Set(),
143143
hoists: [],
144-
temps: 0,
145144
imports: new Set(),
145+
temps: 0,
146146
cached: 0,
147147
identifiers: {},
148148
scopes: {

packages/compiler-core/src/transforms/transformText.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export const transformText: NodeTransform = (node, context) => {
7777
callArgs.push(child)
7878
}
7979
// mark dynamic text with flag so it gets patched inside a block
80-
if (child.type !== NodeTypes.TEXT) {
80+
if (!context.ssr && child.type !== NodeTypes.TEXT) {
8181
callArgs.push(
8282
`${PatchFlags.TEXT} /* ${PatchFlagNames[PatchFlags.TEXT]} */`
8383
)

packages/compiler-dom/src/index.ts

+32-12
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
isBuiltInType,
77
ParserOptions,
88
RootNode,
9-
noopDirectiveTransform
9+
noopDirectiveTransform,
10+
TransformPreset,
11+
getBaseTransformPreset
1012
} from '@vue/compiler-core'
1113
import { parserOptionsMinimal } from './parserOptionsMinimal'
1214
import { parserOptionsStandard } from './parserOptionsStandard'
@@ -31,25 +33,43 @@ export const isBuiltInDOMComponent = (tag: string): symbol | undefined => {
3133
}
3234
}
3335

36+
export function getDOMTransformPreset(
37+
prefixIdentifiers?: boolean
38+
): TransformPreset {
39+
const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(
40+
prefixIdentifiers
41+
)
42+
return [
43+
[
44+
...nodeTransforms,
45+
transformStyle,
46+
...(__DEV__ ? [warnTransitionChildren] : [])
47+
],
48+
{
49+
...directiveTransforms,
50+
cloak: noopDirectiveTransform,
51+
html: transformVHtml,
52+
text: transformVText,
53+
model: transformModel, // override compiler-core
54+
on: transformOn, // override compiler-core
55+
show: transformShow
56+
}
57+
]
58+
}
59+
3460
export function compile(
3561
template: string,
3662
options: CompilerOptions = {}
3763
): CodegenResult {
64+
const [nodeTransforms, directiveTransforms] = getDOMTransformPreset(
65+
options.prefixIdentifiers
66+
)
3867
return baseCompile(template, {
3968
...parserOptions,
4069
...options,
41-
nodeTransforms: [
42-
transformStyle,
43-
...(__DEV__ ? [warnTransitionChildren] : []),
44-
...(options.nodeTransforms || [])
45-
],
70+
nodeTransforms: [...nodeTransforms, ...(options.nodeTransforms || [])],
4671
directiveTransforms: {
47-
cloak: noopDirectiveTransform,
48-
html: transformVHtml,
49-
text: transformVText,
50-
model: transformModel, // override compiler-core
51-
on: transformOn,
52-
show: transformShow,
72+
...directiveTransforms,
5373
...(options.directiveTransforms || {})
5474
},
5575
isBuiltInComponent: isBuiltInDOMComponent

0 commit comments

Comments
 (0)