index.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. const prettier = require('prettier')
  2. const loaderUtils = require('loader-utils')
  3. const normalize = require('../utils/normalize')
  4. const compiler = require('vue-template-compiler')
  5. const transpile = require('vue-template-es2015-compiler')
  6. const hotReloadAPIPath = normalize.dep('vue-hot-reload-api')
  7. const transformRequire = require('./modules/transform-require')
  8. const transformSrcset = require('./modules/transform-srcset')
  9. module.exports = function (html) {
  10. this.cacheable()
  11. const isServer = this.target === 'node'
  12. const isProduction = this.minimize || process.env.NODE_ENV === 'production'
  13. const vueOptions = this.options.__vueOptions__ || {}
  14. const options = loaderUtils.getOptions(this) || {}
  15. const needsHotReload = !isServer && !isProduction && vueOptions.hotReload !== false
  16. const defaultModules = [transformRequire(options.transformToRequire), transformSrcset()]
  17. let userModules = vueOptions.compilerModules || options.compilerModules
  18. // for HappyPack cross-process use cases
  19. if (typeof userModules === 'string') {
  20. userModules = require(userModules)
  21. }
  22. const compilerOptions = {
  23. preserveWhitespace: options.preserveWhitespace,
  24. modules: defaultModules.concat(userModules || []),
  25. directives:
  26. vueOptions.compilerDirectives || options.compilerDirectives || {},
  27. scopeId: options.hasScoped ? options.id : null,
  28. comments: options.hasComment
  29. }
  30. const compile =
  31. isServer && compiler.ssrCompile && vueOptions.optimizeSSR !== false
  32. ? compiler.ssrCompile
  33. : compiler.compile
  34. const compiled = compile(html, compilerOptions)
  35. // tips
  36. if (compiled.tips && compiled.tips.length) {
  37. compiled.tips.forEach(tip => {
  38. this.emitWarning(tip)
  39. })
  40. }
  41. let code
  42. if (compiled.errors && compiled.errors.length) {
  43. this.emitError(
  44. `\n Error compiling template:\n${pad(html)}\n` +
  45. compiled.errors.map(e => ` - ${e}`).join('\n') +
  46. '\n'
  47. )
  48. code = vueOptions.esModule
  49. ? `var esExports = {render:function(){},staticRenderFns: []}\nexport default esExports`
  50. : 'module.exports={render:function(){},staticRenderFns:[]}'
  51. } else {
  52. const bubleOptions = options.buble
  53. const stripWith = bubleOptions.transforms.stripWith !== false
  54. const stripWithFunctional = bubleOptions.transforms.stripWithFunctional
  55. const staticRenderFns = compiled.staticRenderFns.map(fn =>
  56. toFunction(fn, stripWithFunctional)
  57. )
  58. code =
  59. transpile(
  60. 'var render = ' +
  61. toFunction(compiled.render, stripWithFunctional) +
  62. '\n' +
  63. 'var staticRenderFns = [' +
  64. staticRenderFns.join(',') +
  65. ']',
  66. bubleOptions
  67. ) + '\n'
  68. // prettify render fn
  69. if (!isProduction) {
  70. code = prettier.format(code, { semi: false, parser: 'babylon' })
  71. }
  72. // mark with stripped (this enables Vue to use correct runtime proxy detection)
  73. if (!isProduction && stripWith) {
  74. code += `render._withStripped = true\n`
  75. }
  76. const exports = `{ render: render, staticRenderFns: staticRenderFns }`
  77. code += vueOptions.esModule
  78. ? `var esExports = ${exports}\nexport default esExports`
  79. : `module.exports = ${exports}`
  80. }
  81. // hot-reload
  82. if (needsHotReload) {
  83. const exportsName = vueOptions.esModule ? 'esExports' : 'module.exports'
  84. code +=
  85. '\nif (module.hot) {\n' +
  86. ' module.hot.accept()\n' +
  87. ' if (module.hot.data) {\n' +
  88. ' require("' + hotReloadAPIPath + '")' +
  89. ' .rerender("' + options.id + '", ' + exportsName + ')\n' +
  90. ' }\n' +
  91. '}'
  92. }
  93. return code
  94. }
  95. function toFunction (code, stripWithFunctional) {
  96. return (
  97. 'function (' + (stripWithFunctional ? '_h,_vm' : '') + ') {' + code + '}'
  98. )
  99. }
  100. function pad (html) {
  101. return html
  102. .split(/\r?\n/)
  103. .map(line => ` ${line}`)
  104. .join('\n')
  105. }