Blame view

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