2019-12-10 17:01:56 +00:00
|
|
|
import {
|
|
|
|
CompilerOptions,
|
|
|
|
CodegenResult,
|
2019-12-10 17:22:23 +00:00
|
|
|
CompilerError,
|
|
|
|
NodeTransform
|
2019-12-10 17:01:56 +00:00
|
|
|
} from '@vue/compiler-core'
|
|
|
|
import { RawSourceMap } from 'source-map'
|
2019-12-10 17:22:23 +00:00
|
|
|
import {
|
|
|
|
transformAssetUrl,
|
|
|
|
AssetURLOptions,
|
|
|
|
createAssetUrlTransformWithOptions
|
|
|
|
} from './templateTransformAssetUrl'
|
2019-12-10 17:01:56 +00:00
|
|
|
import { transformSrcset } from './templateTransformSrcset'
|
2019-12-10 17:22:23 +00:00
|
|
|
import { isObject } from '@vue/shared'
|
|
|
|
import consolidate from 'consolidate'
|
2019-12-10 17:01:56 +00:00
|
|
|
|
|
|
|
export interface TemplateCompileResults {
|
|
|
|
code: string
|
|
|
|
source: string
|
|
|
|
tips: string[]
|
|
|
|
errors: (string | CompilerError)[]
|
|
|
|
map?: RawSourceMap
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface TemplateCompiler {
|
|
|
|
compile(template: string, options: CompilerOptions): CodegenResult
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface TemplateCompileOptions {
|
|
|
|
source: string
|
|
|
|
filename: string
|
|
|
|
compiler: TemplateCompiler
|
|
|
|
compilerOptions?: CompilerOptions
|
|
|
|
preprocessLang?: string
|
|
|
|
preprocessOptions?: any
|
2019-12-10 17:22:23 +00:00
|
|
|
transformAssetUrls?: AssetURLOptions | boolean
|
2019-12-10 17:01:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function preprocess(
|
|
|
|
{ source, filename, preprocessOptions }: TemplateCompileOptions,
|
|
|
|
preprocessor: any
|
|
|
|
): string {
|
|
|
|
// Consolidate exposes a callback based API, but the callback is in fact
|
|
|
|
// called synchronously for most templating engines. In our case, we have to
|
|
|
|
// expose a synchronous API so that it is usable in Jest transforms (which
|
|
|
|
// have to be sync because they are applied via Node.js require hooks)
|
|
|
|
let res: any, err
|
|
|
|
preprocessor.render(
|
|
|
|
source,
|
|
|
|
{ filename, ...preprocessOptions },
|
|
|
|
(_err: Error | null, _res: string) => {
|
|
|
|
if (_err) err = _err
|
|
|
|
res = _res
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
if (err) throw err
|
|
|
|
return res
|
|
|
|
}
|
|
|
|
|
|
|
|
export function compileTemplate(
|
|
|
|
options: TemplateCompileOptions
|
|
|
|
): TemplateCompileResults {
|
|
|
|
const { preprocessLang } = options
|
2019-12-10 17:22:23 +00:00
|
|
|
const preprocessor =
|
|
|
|
preprocessLang && consolidate[preprocessLang as keyof typeof consolidate]
|
2019-12-10 17:01:56 +00:00
|
|
|
if (preprocessor) {
|
|
|
|
return doCompileTemplate({
|
|
|
|
...options,
|
|
|
|
source: preprocess(options, preprocessor)
|
|
|
|
})
|
|
|
|
} else if (preprocessLang) {
|
|
|
|
return {
|
|
|
|
code: `export default function render() {}`,
|
|
|
|
source: options.source,
|
|
|
|
tips: [
|
|
|
|
`Component ${
|
|
|
|
options.filename
|
|
|
|
} uses lang ${preprocessLang} for template. Please install the language preprocessor.`
|
|
|
|
],
|
|
|
|
errors: [
|
|
|
|
`Component ${
|
|
|
|
options.filename
|
|
|
|
} uses lang ${preprocessLang} for template, however it is not installed.`
|
|
|
|
]
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return doCompileTemplate(options)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function doCompileTemplate({
|
2019-12-10 17:22:23 +00:00
|
|
|
filename,
|
2019-12-10 17:01:56 +00:00
|
|
|
source,
|
|
|
|
compiler,
|
|
|
|
compilerOptions = {},
|
2019-12-10 17:22:23 +00:00
|
|
|
transformAssetUrls
|
2019-12-10 17:01:56 +00:00
|
|
|
}: TemplateCompileOptions): TemplateCompileResults {
|
|
|
|
const errors: CompilerError[] = []
|
2019-12-10 17:22:23 +00:00
|
|
|
|
|
|
|
const nodeTransforms: NodeTransform[] = [transformSrcset]
|
|
|
|
if (isObject(transformAssetUrls)) {
|
|
|
|
nodeTransforms.push(createAssetUrlTransformWithOptions(transformAssetUrls))
|
|
|
|
} else if (transformAssetUrls !== false) {
|
|
|
|
nodeTransforms.push(transformAssetUrl)
|
|
|
|
}
|
|
|
|
|
2019-12-10 17:01:56 +00:00
|
|
|
const { code, map } = compiler.compile(source, {
|
|
|
|
...compilerOptions,
|
|
|
|
filename,
|
2019-12-10 17:22:23 +00:00
|
|
|
mode: 'module', // implies prefixIdentifiers: true
|
|
|
|
hoistStatic: true,
|
|
|
|
cacheHandlers: true,
|
2019-12-10 17:01:56 +00:00
|
|
|
sourceMap: true,
|
2019-12-10 17:22:23 +00:00
|
|
|
nodeTransforms,
|
2019-12-10 17:01:56 +00:00
|
|
|
onError: e => errors.push(e)
|
|
|
|
})
|
|
|
|
return { code, source, errors, tips: [], map }
|
2019-11-07 02:58:15 +00:00
|
|
|
}
|