120 lines
3.8 KiB
JavaScript
120 lines
3.8 KiB
JavaScript
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')
|
|
}
|