Skip to content

Commit af12d3f

Browse files
committed
progress
1 parent 579653a commit af12d3f

File tree

7 files changed

+203
-6
lines changed

7 files changed

+203
-6
lines changed

Diff for: flow/compiler.js

+10
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ declare type ASTElement = {
132132
onceProcessed?: boolean;
133133
wrapData?: (code: string) => string;
134134

135+
// 2.4 ssr optimization
136+
ssrOptimizable?: boolean;
137+
ssrOptimizableRoot?: boolean;
138+
135139
// weex specific
136140
appendAsTree?: boolean;
137141
}
@@ -141,12 +145,18 @@ declare type ASTExpression = {
141145
expression: string;
142146
text: string;
143147
static?: boolean;
148+
// 2.4 ssr optimization
149+
ssrOptimizable?: boolean;
150+
ssrOptimizableRoot?: boolean;
144151
}
145152

146153
declare type ASTText = {
147154
type: 3;
148155
text: string;
149156
static?: boolean;
157+
// 2.4 ssr optimization
158+
ssrOptimizable?: boolean;
159+
ssrOptimizableRoot?: boolean;
150160
}
151161

152162
// SFC-parser related declarations

Diff for: src/compiler/codegen/index.js

+8-6
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type TransformFunction = (el: ASTElement, code: string) => string;
99
type DataGenFunction = (el: ASTElement) => string;
1010
type DirectiveFunction = (el: ASTElement, dir: ASTDirective, warn: Function) => boolean;
1111

12-
class CodegenState {
12+
export class CodegenState {
1313
options: CompilerOptions;
1414
warn: Function;
1515
transforms: Array<TransformFunction>;
@@ -19,7 +19,7 @@ class CodegenState {
1919
onceId: number;
2020
staticRenderFns: Array<string>;
2121

22-
constructor (options = {}) {
22+
constructor (options: CompilerOptions) {
2323
this.options = options
2424
this.warn = options.warn || baseWarn
2525
this.transforms = pluckModuleFunction(options.modules, 'transformCode')
@@ -32,13 +32,15 @@ class CodegenState {
3232
}
3333
}
3434

35+
type CodegenResult = {
36+
render: string,
37+
staticRenderFns: Array<string>
38+
};
39+
3540
export function generate (
3641
ast: ASTElement | void,
3742
options: CompilerOptions
38-
): {
39-
render: string,
40-
staticRenderFns: Array<string>
41-
} {
43+
): CodegenResult {
4244
const state = new CodegenState(options)
4345
const code = ast ? genElement(ast, state) : '_c("div")'
4446
return {

Diff for: src/server/optimizing-compiler/codegen.js

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* @flow */
2+
3+
// import * as directives from './directives'
4+
import { CodegenState } from 'compiler/codegen/index'
5+
6+
type SSRCompileResult = {
7+
render: string;
8+
staticRenderFns: Array<string>;
9+
stringRenderFns: Array<string>;
10+
};
11+
12+
class SSRCodegenState extends CodegenState {
13+
stringRenderFns: Array<string>;
14+
15+
constructor (options: CompilerOptions) {
16+
super(options)
17+
this.stringRenderFns = []
18+
}
19+
}
20+
21+
export function generate (
22+
ast: ASTElement | void,
23+
options: CompilerOptions
24+
): SSRCompileResult {
25+
const state = new SSRCodegenState(options)
26+
const code = ast ? genElement(ast, state) : '_c("div")'
27+
return {
28+
render: `with(this){return ${code}}`,
29+
staticRenderFns: state.staticRenderFns,
30+
stringRenderFns: state.stringRenderFns
31+
}
32+
}
33+
34+
function genElement (el: ASTElement, state: SSRCodegenState): string {
35+
36+
}

Diff for: src/server/optimizing-compiler/directives.js

Whitespace-only changes.

Diff for: src/server/optimizing-compiler/index.js

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/* @flow */
2+
3+
import { extend } from 'shared/util'
4+
import { parse } from 'compiler/parser/index'
5+
import { detectErrors } from 'compiler/error-detector'
6+
7+
import { generate } from './codegen'
8+
import { optimize } from './optimizer'
9+
10+
function baseCompile (
11+
template: string,
12+
options: CompilerOptions
13+
): CompiledResult {
14+
const ast = parse(template.trim(), options)
15+
optimize(ast, options)
16+
const code = generate(ast, options)
17+
return {
18+
ast,
19+
render: code.render,
20+
staticRenderFns: code.staticRenderFns
21+
}
22+
}
23+
24+
export function createCompiler (baseOptions: CompilerOptions) {
25+
return function compile (
26+
template: string,
27+
options?: CompilerOptions
28+
): CompiledResult {
29+
const finalOptions = Object.create(baseOptions)
30+
const errors = []
31+
const tips = []
32+
finalOptions.warn = (msg, tip) => {
33+
(tip ? tips : errors).push(msg)
34+
}
35+
36+
if (options) {
37+
// merge custom modules
38+
if (options.modules) {
39+
finalOptions.modules = (baseOptions.modules || []).concat(options.modules)
40+
}
41+
// merge custom directives
42+
if (options.directives) {
43+
finalOptions.directives = extend(
44+
Object.create(baseOptions.directives),
45+
options.directives
46+
)
47+
}
48+
// copy other options
49+
for (const key in options) {
50+
if (key !== 'modules' && key !== 'directives') {
51+
finalOptions[key] = options[key]
52+
}
53+
}
54+
}
55+
56+
const compiled = baseCompile(template, finalOptions)
57+
if (process.env.NODE_ENV !== 'production') {
58+
errors.push.apply(errors, detectErrors(compiled.ast))
59+
}
60+
compiled.errors = errors
61+
compiled.tips = tips
62+
return compiled
63+
}
64+
}

Diff for: src/server/optimizing-compiler/optimizer.js

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/* @flow */
2+
3+
import { no, isBuiltInTag } from 'shared/util'
4+
5+
let isPlatformReservedTag
6+
7+
/**
8+
* In SSR, the vdom tree is generated only once and never patched, so
9+
* we can optimize most element / trees into plain string render functions.
10+
* The SSR optimizer walks the AST tree to detect optimizable elements and trees.
11+
*
12+
* The criteria for SSR optimizability is quite a bit looser than static tree
13+
* detection (which is designed for client re-render). In SSR we bail only for
14+
* components/slots/custom directives.
15+
*/
16+
export function optimize (root: ?ASTElement, options: CompilerOptions) {
17+
if (!root) return
18+
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)
23+
}
24+
25+
function markNonOptimizable (node: ASTNode) {
26+
node.ssrOptimizable = isOptimizable(node)
27+
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+
}
37+
for (let i = 0, l = node.children.length; i < l; i++) {
38+
const child = node.children[i]
39+
markNonOptimizable(child)
40+
if (!child.ssrOptimizable) {
41+
node.ssrOptimizable = false
42+
}
43+
}
44+
if (node.ifConditions) {
45+
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
46+
const block = node.ifConditions[i].block
47+
markNonOptimizable(block)
48+
if (!block.ssrOptimizable) {
49+
node.ssrOptimizable = false
50+
}
51+
}
52+
}
53+
}
54+
}
55+
56+
function isOptimizable (node: ASTNode): boolean {
57+
if (node.type === 2 || node.type === 3) { // text or expression
58+
return true
59+
}
60+
return (
61+
!isBuiltInTag(node.tag) && // not a built-in (slot, component)
62+
!!isPlatformReservedTag(node.tag) // not a component
63+
)
64+
}
65+
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+
}
85+
}

Diff for: test/unit/modules/server-compiler/optimizer.spec.js

Whitespace-only changes.

0 commit comments

Comments
 (0)