Skip to content

Commit 303780a

Browse files
committed
make function compilation reusable
1 parent 4461b4c commit 303780a

File tree

8 files changed

+131
-122
lines changed

8 files changed

+131
-122
lines changed

src/compiler/codegen/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export function generate (
4949
}
5050
}
5151

52-
function genElement (el: ASTElement, state: CodegenState): string {
52+
export function genElement (el: ASTElement, state: CodegenState): string {
5353
if (el.staticRoot && !el.staticProcessed) {
5454
return genStatic(el, state)
5555
} else if (el.once && !el.onceProcessed) {

src/compiler/index.js

+3-93
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/* @flow */
22

3+
import { extend } from 'shared/util'
34
import { parse } from './parser/index'
45
import { optimize } from './optimizer'
56
import { generate } from './codegen/index'
67
import { detectErrors } from './error-detector'
7-
import { extend, noop } from 'shared/util'
8-
import { warn, tip } from 'core/util/debug'
8+
import { createCompileToFunctionFn } from './to-function'
99

1010
function baseCompile (
1111
template: string,
@@ -21,20 +21,7 @@ function baseCompile (
2121
}
2222
}
2323

24-
function makeFunction (code, errors) {
25-
try {
26-
return new Function(code)
27-
} catch (err) {
28-
errors.push({ err, code })
29-
return noop
30-
}
31-
}
32-
3324
export function createCompiler (baseOptions: CompilerOptions) {
34-
const functionCompileCache: {
35-
[key: string]: CompiledFunctionResult;
36-
} = Object.create(null)
37-
3825
function compile (
3926
template: string,
4027
options?: CompilerOptions
@@ -75,85 +62,8 @@ export function createCompiler (baseOptions: CompilerOptions) {
7562
return compiled
7663
}
7764

78-
function compileToFunctions (
79-
template: string,
80-
options?: CompilerOptions,
81-
vm?: Component
82-
): CompiledFunctionResult {
83-
options = options || {}
84-
85-
/* istanbul ignore if */
86-
if (process.env.NODE_ENV !== 'production') {
87-
// detect possible CSP restriction
88-
try {
89-
new Function('return 1')
90-
} catch (e) {
91-
if (e.toString().match(/unsafe-eval|CSP/)) {
92-
warn(
93-
'It seems you are using the standalone build of Vue.js in an ' +
94-
'environment with Content Security Policy that prohibits unsafe-eval. ' +
95-
'The template compiler cannot work in this environment. Consider ' +
96-
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
97-
'templates into render functions.'
98-
)
99-
}
100-
}
101-
}
102-
103-
// check cache
104-
const key = options.delimiters
105-
? String(options.delimiters) + template
106-
: template
107-
if (functionCompileCache[key]) {
108-
return functionCompileCache[key]
109-
}
110-
111-
// compile
112-
const compiled = compile(template, options)
113-
114-
// check compilation errors/tips
115-
if (process.env.NODE_ENV !== 'production') {
116-
if (compiled.errors && compiled.errors.length) {
117-
warn(
118-
`Error compiling template:\n\n${template}\n\n` +
119-
compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
120-
vm
121-
)
122-
}
123-
if (compiled.tips && compiled.tips.length) {
124-
compiled.tips.forEach(msg => tip(msg, vm))
125-
}
126-
}
127-
128-
// turn code into functions
129-
const res = {}
130-
const fnGenErrors = []
131-
res.render = makeFunction(compiled.render, fnGenErrors)
132-
const l = compiled.staticRenderFns.length
133-
res.staticRenderFns = new Array(l)
134-
for (let i = 0; i < l; i++) {
135-
res.staticRenderFns[i] = makeFunction(compiled.staticRenderFns[i], fnGenErrors)
136-
}
137-
138-
// check function generation errors.
139-
// this should only happen if there is a bug in the compiler itself.
140-
// mostly for codegen development use
141-
/* istanbul ignore if */
142-
if (process.env.NODE_ENV !== 'production') {
143-
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
144-
warn(
145-
`Failed to generate render function:\n\n` +
146-
fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
147-
vm
148-
)
149-
}
150-
}
151-
152-
return (functionCompileCache[key] = res)
153-
}
154-
15565
return {
15666
compile,
157-
compileToFunctions
67+
compileToFunctions: createCompileToFunctionFn(compile)
15868
}
15969
}

src/compiler/to-function.js

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/* @flow */
2+
3+
import { noop } from 'shared/util'
4+
import { warn, tip } from 'core/util/debug'
5+
6+
function createFunction (code, errors) {
7+
try {
8+
return new Function(code)
9+
} catch (err) {
10+
errors.push({ err, code })
11+
return noop
12+
}
13+
}
14+
15+
export function createCompileToFunctionFn (compile: Function): Function {
16+
const cache: {
17+
[key: string]: CompiledFunctionResult;
18+
} = Object.create(null)
19+
20+
return function compileToFunctions (
21+
template: string,
22+
options?: CompilerOptions,
23+
vm?: Component
24+
): CompiledFunctionResult {
25+
options = options || {}
26+
27+
/* istanbul ignore if */
28+
if (process.env.NODE_ENV !== 'production') {
29+
// detect possible CSP restriction
30+
try {
31+
new Function('return 1')
32+
} catch (e) {
33+
if (e.toString().match(/unsafe-eval|CSP/)) {
34+
warn(
35+
'It seems you are using the standalone build of Vue.js in an ' +
36+
'environment with Content Security Policy that prohibits unsafe-eval. ' +
37+
'The template compiler cannot work in this environment. Consider ' +
38+
'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
39+
'templates into render functions.'
40+
)
41+
}
42+
}
43+
}
44+
45+
// check cache
46+
const key = options.delimiters
47+
? String(options.delimiters) + template
48+
: template
49+
if (cache[key]) {
50+
return cache[key]
51+
}
52+
53+
// compile
54+
const compiled = compile(template, options)
55+
56+
// check compilation errors/tips
57+
if (process.env.NODE_ENV !== 'production') {
58+
if (compiled.errors && compiled.errors.length) {
59+
warn(
60+
`Error compiling template:\n\n${template}\n\n` +
61+
compiled.errors.map(e => `- ${e}`).join('\n') + '\n',
62+
vm
63+
)
64+
}
65+
if (compiled.tips && compiled.tips.length) {
66+
compiled.tips.forEach(msg => tip(msg, vm))
67+
}
68+
}
69+
70+
// turn code into functions
71+
const res = {}
72+
const fnGenErrors = []
73+
res.render = createFunction(compiled.render, fnGenErrors)
74+
const l = compiled.staticRenderFns.length
75+
res.staticRenderFns = new Array(l)
76+
for (let i = 0; i < l; i++) {
77+
res.staticRenderFns[i] = createFunction(compiled.staticRenderFns[i], fnGenErrors)
78+
}
79+
80+
// check function generation errors.
81+
// this should only happen if there is a bug in the compiler itself.
82+
// mostly for codegen development use
83+
/* istanbul ignore if */
84+
if (process.env.NODE_ENV !== 'production') {
85+
if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
86+
warn(
87+
`Failed to generate render function:\n\n` +
88+
fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
89+
vm
90+
)
91+
}
92+
}
93+
94+
return (cache[key] = res)
95+
}
96+
}

src/platforms/web/compiler/index.js

+2-25
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,8 @@
11
/* @flow */
22

3-
import { isUnaryTag, canBeLeftOpenTag } from './util'
4-
import { genStaticKeys } from 'shared/util'
3+
import { baseOptions } from './options'
54
import { createCompiler } from 'compiler/index'
65

7-
import modules from './modules/index'
8-
import directives from './directives/index'
9-
10-
import {
11-
isPreTag,
12-
mustUseProp,
13-
isReservedTag,
14-
getTagNamespace
15-
} from '../util/index'
16-
17-
export const baseOptions: CompilerOptions = {
18-
expectHTML: true,
19-
modules,
20-
directives,
21-
isPreTag,
22-
isUnaryTag,
23-
mustUseProp,
24-
canBeLeftOpenTag,
25-
isReservedTag,
26-
getTagNamespace,
27-
staticKeys: genStaticKeys(modules)
28-
}
29-
306
const { compile, compileToFunctions } = createCompiler(baseOptions)
7+
318
export { compile, compileToFunctions }

src/platforms/web/compiler/options.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* @flow */
2+
3+
import {
4+
isPreTag,
5+
mustUseProp,
6+
isReservedTag,
7+
getTagNamespace
8+
} from '../util/index'
9+
10+
import modules from './modules/index'
11+
import directives from './directives/index'
12+
import { genStaticKeys } from 'shared/util'
13+
import { isUnaryTag, canBeLeftOpenTag } from './util'
14+
15+
export const baseOptions: CompilerOptions = {
16+
expectHTML: true,
17+
modules,
18+
directives,
19+
isPreTag,
20+
isUnaryTag,
21+
mustUseProp,
22+
canBeLeftOpenTag,
23+
isReservedTag,
24+
getTagNamespace,
25+
staticKeys: genStaticKeys(modules)
26+
}

test/unit/modules/compiler/codegen.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { optimize } from 'compiler/optimizer'
33
import { generate } from 'compiler/codegen'
44
import { isObject } from 'shared/util'
55
import { isReservedTag } from 'web/util/index'
6-
import { baseOptions } from 'web/compiler/index'
6+
import { baseOptions } from 'web/compiler/options'
77

88
function assertCodegen (template, generatedCode, ...args) {
99
let staticRenderFnCodes = []

test/unit/modules/compiler/optimizer.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parse } from 'compiler/parser/index'
22
import { optimize } from 'compiler/optimizer'
3-
import { baseOptions } from 'web/compiler/index'
3+
import { baseOptions } from 'web/compiler/options'
44

55
describe('optimizer', () => {
66
it('simple', () => {

test/unit/modules/compiler/parser.spec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parse } from 'compiler/parser/index'
22
import { extend } from 'shared/util'
3-
import { baseOptions } from 'web/compiler/index'
3+
import { baseOptions } from 'web/compiler/options'
44
import { isIE, isEdge } from 'core/util/env'
55

66
describe('parser', () => {

0 commit comments

Comments
 (0)