123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- const qs = require('querystring')
- const loaderUtils = require('loader-utils')
- const { resolveCompiler } = require('../compiler')
- const { getDescriptor } = require('../descriptorCache')
- const { resolveScript } = require('../resolveScript')
- // 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 filename = this.resourcePath
- const ctx = this.rootContext
- 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
- const compilerOptions = Object.assign(
- {
- outputSourceRange: true
- },
- options.compilerOptions,
- {
- scopeId: query.scoped ? `data-v-${id}` : null,
- comments: query.comments
- }
- )
- const { compiler, templateCompiler } = resolveCompiler(ctx, loaderContext)
- const descriptor = getDescriptor(filename, options, loaderContext)
- const script = resolveScript(descriptor, id, options, loaderContext)
- // for vue/compiler-sfc OR @vue/component-compiler-utils
- const finalOptions = {
- source,
- filename: this.resourcePath,
- compiler: options.compiler || templateCompiler,
- 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,
- bindings: script ? script.bindings : undefined
- }
- const compiled = compiler.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) {
- const generateCodeFrame =
- (templateCompiler && templateCompiler.generateCodeFrame) ||
- compiler.generateCodeFrame
- // 2.6 compiler outputs errors as objects with range
- if (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 = 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')
- }
|