feat(compiler-sfc): compile template WIP (#534)
This commit is contained in:
parent
b198a665cf
commit
0a14c04c81
55
packages/compiler-sfc/__tests__/compileTemplate.spec.ts
Normal file
55
packages/compiler-sfc/__tests__/compileTemplate.spec.ts
Normal 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)
|
||||
})
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user