vue3-yuanma/packages/compiler-sfc/src/compileTemplate.ts

120 lines
3.2 KiB
TypeScript
Raw Normal View History

import {
CompilerOptions,
CodegenResult,
CompilerError,
NodeTransform
} from '@vue/compiler-core'
import { RawSourceMap } from 'source-map'
import {
transformAssetUrl,
AssetURLOptions,
createAssetUrlTransformWithOptions
} from './templateTransformAssetUrl'
import { transformSrcset } from './templateTransformSrcset'
import { isObject } from '@vue/shared'
import consolidate from 'consolidate'
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
transformAssetUrls?: AssetURLOptions | boolean
}
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
const preprocessor =
preprocessLang && consolidate[preprocessLang as keyof typeof consolidate]
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({
filename,
source,
compiler,
compilerOptions = {},
transformAssetUrls
}: TemplateCompileOptions): TemplateCompileResults {
const errors: CompilerError[] = []
const nodeTransforms: NodeTransform[] = [transformSrcset]
if (isObject(transformAssetUrls)) {
nodeTransforms.push(createAssetUrlTransformWithOptions(transformAssetUrls))
} else if (transformAssetUrls !== false) {
nodeTransforms.push(transformAssetUrl)
}
const { code, map } = compiler.compile(source, {
...compilerOptions,
filename,
mode: 'module', // implies prefixIdentifiers: true
hoistStatic: true,
cacheHandlers: true,
sourceMap: true,
nodeTransforms,
onError: e => errors.push(e)
})
return { code, source, errors, tips: [], map }
2019-11-07 02:58:15 +00:00
}