to-function.js 2.7 KB

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