--- /dev/null
+import { compileTemplate } from '../src/compileTemplate'
+import { compile } from '@vue/compiler-dom'
+import { parse, SFCTemplateBlock } from '../src/parse'
+
+const compiler = { compile }
+
+test('should work', () => {
+ const source = `<div><p>{{ render }}</p></div>`
+
+ const result = compileTemplate({ filename: 'example.vue', source, compiler })
+
+ expect(result.errors.length).toBe(0)
+ expect(result.source).toBe(source)
+ // should expose render fn
+ expect(result.code).toMatch(`export default function render()`)
+})
+
+test('preprocess pug', () => {
+ const template = parse(
+ `
+<template lang="pug">
+body
+ h1 Pug Examples
+ div.container
+ p Cool Pug example!
+</template>
+`,
+ { filename: 'example.vue', needMap: true }
+ ).template as SFCTemplateBlock
+
+ const result = compileTemplate({
+ filename: 'example.vue',
+ source: template.content,
+ preprocessLang: template.lang,
+ compiler
+ })
+
+ expect(result.errors.length).toBe(0)
+})
+
+test('warn missing preprocessor', () => {
+ const template = parse(`<template lang="unknownLang">\n</template>\n`, {
+ filename: 'example.vue',
+ needMap: true
+ }).template as SFCTemplateBlock
+
+ const result = compileTemplate({
+ filename: 'example.vue',
+ compiler,
+ source: template.content,
+ preprocessLang: template.lang
+ })
+
+ expect(result.errors.length).toBe(1)
+})
-export function compileTemplate() {
- // TODO
+import {
+ CompilerOptions,
+ CodegenResult,
+ CompilerError
+} from '@vue/compiler-core'
+import { RawSourceMap } from 'source-map'
+import { transformAssetUrl } from './templateTransformAssetUrl'
+import { transformSrcset } from './templateTransformSrcset'
+
+const consolidate = require('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
+}
+
+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]
+ 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({
+ source,
+ compiler,
+ compilerOptions = {},
+ filename
+}: TemplateCompileOptions): TemplateCompileResults {
+ const errors: CompilerError[] = []
+ const { code, map } = compiler.compile(source, {
+ ...compilerOptions,
+ filename,
+ mode: 'module',
+ sourceMap: true,
+ nodeTransforms: [transformAssetUrl, transformSrcset],
+ onError: e => errors.push(e)
+ })
+ return { code, source, errors, tips: [], map }
}