Skip to content

Commit 85e24b3

Browse files
committed
progress
1 parent a00e4d3 commit 85e24b3

File tree

6 files changed

+145
-78
lines changed

6 files changed

+145
-78
lines changed

flow/compiler.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ declare type ASTElement = {
129129
wrapData?: (code: string) => string;
130130

131131
// 2.4 ssr optimization
132-
ssrOptimizable?: boolean;
133-
ssrOptimizableRoot?: boolean;
132+
ssrOptimizability?: number;
134133

135134
// weex specific
136135
appendAsTree?: boolean;
@@ -142,17 +141,15 @@ declare type ASTExpression = {
142141
text: string;
143142
static?: boolean;
144143
// 2.4 ssr optimization
145-
ssrOptimizable?: boolean;
146-
ssrOptimizableRoot?: boolean;
144+
ssrOptimizability?: number;
147145
};
148146

149147
declare type ASTText = {
150148
type: 3;
151149
text: string;
152150
static?: boolean;
153151
// 2.4 ssr optimization
154-
ssrOptimizable?: boolean;
155-
ssrOptimizableRoot?: boolean;
152+
ssrOptimizability?: number;
156153
};
157154

158155
// SFC-parser related declarations

src/compiler/codegen/index.js

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,15 @@ function genOnce (el: ASTElement, state: CodegenState): string {
119119
}
120120
}
121121

122-
function genIf (el: any, state: CodegenState): string {
122+
export function genIf (el: any, state: CodegenState, altGen?: Function): string {
123123
el.ifProcessed = true // avoid recursion
124-
return genIfConditions(el.ifConditions.slice(), state)
124+
return genIfConditions(el.ifConditions.slice(), state, altGen)
125125
}
126126

127127
function genIfConditions (
128128
conditions: ASTIfConditions,
129-
state: CodegenState
129+
state: CodegenState,
130+
altGen?: Function
130131
): string {
131132
if (!conditions.length) {
132133
return '_e()'
@@ -145,11 +146,15 @@ function genIfConditions (
145146

146147
// v-if with v-once should generate code like (a)?_m(0):_m(1)
147148
function genTernaryExp (el) {
148-
return el.once ? genOnce(el, state) : genElement(el, state)
149+
return altGen
150+
? altGen(el, state)
151+
: el.once
152+
? genOnce(el, state)
153+
: genElement(el, state)
149154
}
150155
}
151156

152-
function genFor (el: any, state: CodegenState): string {
157+
export function genFor (el: any, state: CodegenState, altGen?: Function): string {
153158
const exp = el.for
154159
const alias = el.alias
155160
const iterator1 = el.iterator1 ? `,${el.iterator1}` : ''
@@ -172,11 +177,11 @@ function genFor (el: any, state: CodegenState): string {
172177
el.forProcessed = true // avoid recursion
173178
return `_l((${exp}),` +
174179
`function(${alias}${iterator1}${iterator2}){` +
175-
`return ${genElement(el, state)}` +
180+
`return ${(altGen || genElement)(el, state)}` +
176181
'})'
177182
}
178183

179-
function genData (el: ASTElement, state: CodegenState): string {
184+
export function genData (el: ASTElement, state: CodegenState): string {
180185
let data = '{'
181186

182187
// directives first.
@@ -345,10 +350,12 @@ function genForScopedSlot (
345350
'})'
346351
}
347352

348-
function genChildren (
353+
export function genChildren (
349354
el: ASTElement,
350355
state: CodegenState,
351-
checkSkip?: boolean
356+
checkSkip?: boolean,
357+
altGenElement?: Function,
358+
altGenNode?: Function
352359
): string | void {
353360
const children = el.children
354361
if (children.length) {
@@ -359,12 +366,13 @@ function genChildren (
359366
el.tag !== 'template' &&
360367
el.tag !== 'slot'
361368
) {
362-
return genElement(el, state)
369+
return (altGenElement || genElement)(el, state)
363370
}
364371
const normalizationType = checkSkip
365372
? getNormalizationType(children, state.maybeComponent)
366373
: 0
367-
return `[${children.map(c => genNode(c, state)).join(',')}]${
374+
const gen = altGenNode || genNode
375+
return `[${children.map(c => gen(c, state)).join(',')}]${
368376
normalizationType ? `,${normalizationType}` : ''
369377
}`
370378
}

src/server/optimizing-compiler/codegen.js

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,16 @@
55
// a node is not optimizable it simply falls back to the default codegen.
66

77
// import * as directives from './directives'
8-
import { CodegenState, genElement } from 'compiler/codegen/index'
8+
import { FULL, PARTIAL, CHILDREN } from './optimizer'
9+
10+
import {
11+
genIf,
12+
genFor,
13+
genData,
14+
genElement,
15+
genChildren,
16+
CodegenState
17+
} from 'compiler/codegen/index'
918

1019
type SSRCompileResult = {
1120
render: string;
@@ -27,26 +36,63 @@ export function generate (
2736
options: CompilerOptions
2837
): SSRCompileResult {
2938
const state = new SSRCodegenState(options)
30-
const code = ast ? genSSRElement(ast, state, true) : '_c("div")'
39+
const code = ast ? genSSRElement(ast, state) : '_c("div")'
3140
return {
3241
render: `with(this){return ${code}}`,
3342
staticRenderFns: state.staticRenderFns,
3443
stringRenderFns: state.stringRenderFns
3544
}
3645
}
3746

38-
function genSSRElement (
39-
el: ASTElement,
40-
state: SSRCodegenState,
41-
isComponentRoot?: boolean
42-
): string {
43-
if (el.ssrOptimizableRoot && !isComponentRoot) {
44-
return genStringRenderFn(el, state)
45-
} else {
46-
return genElement(el, state)
47+
function genSSRElement (el: ASTElement, state: SSRCodegenState): string {
48+
if (el.for && !el.forProcessed) {
49+
return genFor(el, state, genSSRElement)
50+
} else if (el.if && !el.ifProcessed) {
51+
return genIf(el, state, genSSRElement)
52+
}
53+
54+
switch (el.ssrOptimizability) {
55+
case FULL:
56+
// stringify whole tree
57+
return genStringNode(el, state, true)
58+
case PARTIAL:
59+
// stringify self and check children
60+
return genStringNode(el, state, false)
61+
case CHILDREN:
62+
// generate self as VNode and check children
63+
return genVNode(el, state)
64+
default:
65+
// bail whole tree
66+
return genElement(el, state)
67+
}
68+
}
69+
70+
function genSSRNode (el, state) {
71+
return el.type === 1
72+
? genSSRElement(el, state)
73+
: genStringNode(el, state)
74+
}
75+
76+
function genSSRChildren (el, state, checkSkip) {
77+
return genChildren(el, state, checkSkip, genSSRElement, genSSRNode)
78+
}
79+
80+
function genVNode (el, state) {
81+
let code
82+
const data = el.plain ? undefined : genData(el, state)
83+
const children = el.inlineTemplate ? null : genSSRChildren(el, state, true)
84+
code = `_c('${el.tag}'${
85+
data ? `,${data}` : '' // data
86+
}${
87+
children ? `,${children}` : '' // children
88+
})`
89+
// module transforms
90+
for (let i = 0; i < state.transforms.length; i++) {
91+
code = state.transforms[i](el, code)
4792
}
93+
return code
4894
}
4995

50-
function genStringRenderFn (el, state) {
51-
return ''
96+
function genStringNode (el, state, includeChildren) {
97+
return '!!!'
5298
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* @flow */
2+
3+
export default {
4+
show () {
5+
6+
}
7+
}
Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/* @flow */
22

3-
import { no, isBuiltInTag } from 'shared/util'
3+
import { no, makeMap, isBuiltInTag } from 'shared/util'
4+
5+
// optimizability constants
6+
export const FALSE = 0 // whole sub tree un-optimizable
7+
export const FULL = 1 // whole sub tree optimizable
8+
export const PARTIAL = 2 // self optimizable but has un-optimizable children
9+
export const CHILDREN = 3 // self un-optimizable but may have optimizable children
410

511
let isPlatformReservedTag
612

@@ -16,70 +22,60 @@ let isPlatformReservedTag
1622
export function optimize (root: ?ASTElement, options: CompilerOptions) {
1723
if (!root) return
1824
isPlatformReservedTag = options.isReservedTag || no
19-
// first pass: mark all non-optimizable nodes.
20-
markNonOptimizable(root)
21-
// second pass: mark optimizable trees.
22-
markOptimizableTrees(root, false)
25+
walk(root, true)
2326
}
2427

25-
function markNonOptimizable (node: ASTNode) {
26-
node.ssrOptimizable = isOptimizable(node)
28+
function walk (node: ASTNode, isRoot?: boolean) {
29+
if (isUnOptimizableTree(node)) {
30+
node.ssrOptimizability = FALSE
31+
return
32+
}
33+
// root node or nodes with custom directives should always be a VNode
34+
if (isRoot || hasCustomDirective(node)) {
35+
node.ssrOptimizability = CHILDREN
36+
}
2737
if (node.type === 1) {
28-
// do not make component slot content optimizable so that render fns can
29-
// still manipulate the nodes.
30-
if (
31-
!isPlatformReservedTag(node.tag) &&
32-
node.tag !== 'slot' &&
33-
node.attrsMap['inline-template'] == null
34-
) {
35-
return
36-
}
3738
for (let i = 0, l = node.children.length; i < l; i++) {
3839
const child = node.children[i]
39-
markNonOptimizable(child)
40-
if (!child.ssrOptimizable) {
41-
node.ssrOptimizable = false
40+
walk(child)
41+
if (child.ssrOptimizability !== FULL && node.ssrOptimizability == null) {
42+
node.ssrOptimizability = PARTIAL
4243
}
4344
}
4445
if (node.ifConditions) {
4546
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
4647
const block = node.ifConditions[i].block
47-
markNonOptimizable(block)
48-
if (!block.ssrOptimizable) {
49-
node.ssrOptimizable = false
48+
walk(block)
49+
if (block.ssrOptimizability !== FULL && node.ssrOptimizability == null) {
50+
node.ssrOptimizability = PARTIAL
5051
}
5152
}
5253
}
54+
if (node.ssrOptimizability == null) {
55+
node.ssrOptimizability = FULL
56+
}
57+
} else {
58+
node.ssrOptimizability = FULL
5359
}
5460
}
5561

56-
function isOptimizable (node: ASTNode): boolean {
62+
function isUnOptimizableTree (node: ASTNode): boolean {
5763
if (node.type === 2 || node.type === 3) { // text or expression
58-
return true
64+
return false
5965
}
6066
return (
61-
!isBuiltInTag(node.tag) && // not a built-in (slot, component)
62-
!!isPlatformReservedTag(node.tag) // not a component
67+
isBuiltInTag(node.tag) || // built-in (slot, component)
68+
!isPlatformReservedTag(node.tag) // custom component
6369
)
6470
}
6571

66-
function markOptimizableTrees (node: ASTNode) {
67-
if (node.type === 1) {
68-
if (node.ssrOptimizable) {
69-
node.ssrOptimizableRoot = true
70-
return
71-
} else {
72-
node.ssrOptimizableRoot = false
73-
}
74-
if (node.children) {
75-
for (let i = 0, l = node.children.length; i < l; i++) {
76-
markOptimizableTrees(node.children[i])
77-
}
78-
}
79-
if (node.ifConditions) {
80-
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
81-
markOptimizableTrees(node.ifConditions[i].block)
82-
}
83-
}
84-
}
72+
// only need to check built-in dirs with runtime
73+
const isBuiltInDir = makeMap('model,show')
74+
75+
function hasCustomDirective (node: ASTNode): ?boolean {
76+
return (
77+
node.type === 1 &&
78+
node.directives &&
79+
node.directives.some(d => !isBuiltInDir(d.name))
80+
)
8581
}

src/server/render.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ const normalizeRender = vm => {
3838
}
3939

4040
function renderNode (node, isRoot, context) {
41-
if (node.isTextNode) {
42-
renderTextNode(node, context)
41+
if (node.isString) {
42+
renderStringNode(node, context)
4343
} else if (isDef(node.componentOptions)) {
4444
renderComponent(node, isRoot, context)
4545
} else {
@@ -145,6 +145,18 @@ function renderComponentWithCache (node, isRoot, key, context) {
145145
renderComponentInner(node, isRoot, context)
146146
}
147147

148+
function StringNode (open, close, children) {
149+
this.isString = true
150+
this.open = open
151+
this.close = close
152+
this.children = children
153+
}
154+
155+
function createStringNode (id, children) {
156+
const { open, close } = this.$options.stringRenderFns[id]
157+
return new StringNode(open, close, children)
158+
}
159+
148160
function renderComponentInner (node, isRoot, context) {
149161
const prevActive = context.activeInstance
150162
// expose userContext on vnode
@@ -154,6 +166,7 @@ function renderComponentInner (node, isRoot, context) {
154166
context.activeInstance
155167
)
156168
normalizeRender(child)
169+
child._ss = createStringNode
157170
const childNode = child._render()
158171
childNode.parent = node
159172
context.renderStates.push({
@@ -163,7 +176,7 @@ function renderComponentInner (node, isRoot, context) {
163176
renderNode(childNode, isRoot, context)
164177
}
165178

166-
function renderTextNode (el, context) {
179+
function renderStringNode (el, context) {
167180
const { write, next } = context
168181
if (isUndef(el.children) || el.children.length === 0) {
169182
write(el.open() + (el.close || ''), next)

0 commit comments

Comments
 (0)