You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
89 lines
2.9 KiB
89 lines
2.9 KiB
const qs = require('querystring') |
|
const loaderUtils = require('loader-utils') |
|
const { compileTemplate } = require('@vue/component-compiler-utils') |
|
|
|
// Loader that compiles raw template into JavaScript functions. |
|
// This is injected by the global pitcher (../pitch) for template |
|
// selection requests initiated from vue files. |
|
module.exports = function (source) { |
|
const loaderContext = this |
|
const query = qs.parse(this.resourceQuery.slice(1)) |
|
|
|
// although this is not the main vue-loader, we can get access to the same |
|
// vue-loader options because we've set an ident in the plugin and used that |
|
// ident to create the request for this loader in the pitcher. |
|
const options = loaderUtils.getOptions(loaderContext) || {} |
|
const { id } = query |
|
const isServer = loaderContext.target === 'node' |
|
const isProduction = options.productionMode || loaderContext.minimize || process.env.NODE_ENV === 'production' |
|
const isFunctional = query.functional |
|
|
|
// allow using custom compiler via options |
|
const compiler = options.compiler || require('vue-template-compiler') |
|
|
|
const compilerOptions = Object.assign({ |
|
outputSourceRange: true |
|
}, options.compilerOptions, { |
|
scopeId: query.scoped ? `data-v-${id}` : null, |
|
comments: query.comments |
|
}) |
|
|
|
// for vue-component-compiler |
|
const finalOptions = { |
|
source, |
|
filename: this.resourcePath, |
|
compiler, |
|
compilerOptions, |
|
// allow customizing behavior of vue-template-es2015-compiler |
|
transpileOptions: options.transpileOptions, |
|
transformAssetUrls: options.transformAssetUrls || true, |
|
isProduction, |
|
isFunctional, |
|
optimizeSSR: isServer && options.optimizeSSR !== false, |
|
prettify: options.prettify |
|
} |
|
|
|
const compiled = compileTemplate(finalOptions) |
|
|
|
// tips |
|
if (compiled.tips && compiled.tips.length) { |
|
compiled.tips.forEach(tip => { |
|
loaderContext.emitWarning(typeof tip === 'object' ? tip.msg : tip) |
|
}) |
|
} |
|
|
|
// errors |
|
if (compiled.errors && compiled.errors.length) { |
|
// 2.6 compiler outputs errors as objects with range |
|
if (compiler.generateCodeFrame && finalOptions.compilerOptions.outputSourceRange) { |
|
// TODO account for line offset in case template isn't placed at top |
|
// of the file |
|
loaderContext.emitError( |
|
`\n\n Errors compiling template:\n\n` + |
|
compiled.errors.map(({ msg, start, end }) => { |
|
const frame = compiler.generateCodeFrame(source, start, end) |
|
return ` ${msg}\n\n${pad(frame)}` |
|
}).join(`\n\n`) + |
|
'\n' |
|
) |
|
} else { |
|
loaderContext.emitError( |
|
`\n Error compiling template:\n${pad(compiled.source)}\n` + |
|
compiled.errors.map(e => ` - ${e}`).join('\n') + |
|
'\n' |
|
) |
|
} |
|
} |
|
|
|
const { code } = compiled |
|
|
|
// finish with ESM exports |
|
return code + `\nexport { render, staticRenderFns }` |
|
} |
|
|
|
function pad (source) { |
|
return source |
|
.split(/\r?\n/) |
|
.map(line => ` ${line}`) |
|
.join('\n') |
|
}
|
|
|