feat(compiler-sfc): compile template WIP (#534)

This commit is contained in:
宋铄运 2019-12-11 01:01:56 +08:00 committed by Evan You
parent b198a665cf
commit 0a14c04c81
3 changed files with 157 additions and 3 deletions

View File

@ -0,0 +1,55 @@
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)
})

View File

@ -37,6 +37,7 @@
"source-map": "^0.7.3"
},
"devDependencies": {
"@types/lru-cache": "^5.1.0"
"@types/lru-cache": "^5.1.0",
"pug": "^2.0.4"
}
}

View File

@ -1,3 +1,101 @@
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 }
}