UNPKG

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