1 |
|
2 |
|
3 | import { noop, extend } from 'shared/util'
|
4 | import { warn as baseWarn, tip } from 'core/util/debug'
|
5 | import { generateCodeFrame } from './codeframe'
|
6 |
|
7 | type CompiledFunctionResult = {
|
8 | render: Function;
|
9 | staticRenderFns: Array<Function>;
|
10 | };
|
11 |
|
12 | function createFunction (code, errors) {
|
13 | try {
|
14 | return new Function(code)
|
15 | } catch (err) {
|
16 | errors.push({ err, code })
|
17 | return noop
|
18 | }
|
19 | }
|
20 |
|
21 | export 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 |
|
34 | if (process.env.NODE_ENV !== 'production') {
|
35 |
|
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 |
|
52 | const key = options.delimiters
|
53 | ? String(options.delimiters) + template
|
54 | : template
|
55 | if (cache[key]) {
|
56 | return cache[key]
|
57 | }
|
58 |
|
59 |
|
60 | const compiled = compile(template, options)
|
61 |
|
62 |
|
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 |
|
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 |
|
99 |
|
100 |
|
101 |
|
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 | }
|