to-function.js 2.8 KB

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