Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: transformer #61

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/editor/FileSelector.vue
Expand Up @@ -48,9 +48,9 @@ function doneAddFile() {
if (!pending.value) return
const filename = pendingFilename.value

if (!/\.(vue|js|ts|css)$/.test(filename)) {
if (!store.supportedLanguages.some((ext) => filename.endsWith(ext))) {
store.state.errors = [
`Playground only supports *.vue, *.js, *.ts, *.css files.`
`Playground only supports ${store.supportedLanguages.join(', ')} files.`
]
return
}
Expand Down
11 changes: 11 additions & 0 deletions src/store.ts
Expand Up @@ -58,6 +58,14 @@ export interface SFCOptions {
template?: SFCTemplateCompileOptions
}

export interface TransformerOptions {
code: string
filename: string
file: File
stage: 'pre' | 'post'
ssr: boolean
}

export interface Store {
state: StoreState
options?: SFCOptions
Expand All @@ -70,6 +78,8 @@ export interface Store {
getImportMap: () => any
initialShowOutput: boolean
initialOutputMode: OutputModes
supportedLanguages: string[]
transformer?(options: TransformerOptions): undefined | string
}

export interface StoreOptions {
Expand All @@ -88,6 +98,7 @@ export class ReplStore implements Store {
options?: SFCOptions
initialShowOutput: boolean
initialOutputMode: OutputModes
supportedLanguages = ['vue', 'js', 'ts', 'css', 'pug']

private defaultVueRuntimeURL: string
private defaultVueServerRendererURL: string
Expand Down
105 changes: 78 additions & 27 deletions src/transform.ts
Expand Up @@ -18,18 +18,34 @@ async function transformTS(src: string) {
}).code
}

export async function compileFile(
store: Store,
{ filename, code, compiled }: File
) {
export async function compileFile(store: Store, file: File) {
function withTransformer(
code: string,
filename: string,
stage: 'pre' | 'post',
ssr = false
) {
if (!store.transformer) return code
try {
return store.transformer({ code, filename, file, stage, ssr }) || code
} catch (err: any) {
store.state.errors.push(err)
}
return code
}

store.state.errors = []

let { code } = file
const { filename, compiled } = file
if (!code.trim()) {
store.state.errors = []
return
}

code = withTransformer(code, filename, 'pre')

if (filename.endsWith('.css')) {
compiled.css = code
store.state.errors = []
compiled.css = withTransformer(code, filename, 'post')
return
}

Expand All @@ -40,13 +56,13 @@ export async function compileFile(
if (filename.endsWith('.ts')) {
code = await transformTS(code)
}
compiled.js = compiled.ssr = code
store.state.errors = []
compiled.js = withTransformer(code, filename, 'post')
compiled.ssr = withTransformer(code, filename, 'post', true)
return
}

if (!filename.endsWith('.vue')) {
store.state.errors = []
compiled.js = withTransformer(code, filename, 'post')
return
}

Expand All @@ -60,14 +76,24 @@ export async function compileFile(
return
}

const unsupportedStyle = descriptor.styles.find(
(s) => s.lang && !store.supportedLanguages.includes(s.lang)
)
if (unsupportedStyle) {
store.state.errors.push(
`lang="${unsupportedStyle.lang}" pre-processors for <style> are not supported.`
)
return
}

if (
descriptor.styles.some((s) => s.lang) ||
(descriptor.template && descriptor.template.lang)
descriptor.template &&
descriptor.template.lang &&
!store.supportedLanguages.includes(descriptor.template.lang)
) {
store.state.errors = [
`lang="x" pre-processors for <template> or <style> are currently not ` +
`supported.`
]
store.state.errors.push(
`lang="${descriptor.template.lang}" pre-processors for <template> are not supported.`
)
return
}

Expand All @@ -76,7 +102,7 @@ export async function compileFile(
(descriptor.scriptSetup && descriptor.scriptSetup.lang)
const isTS = scriptLang === 'ts'
if (scriptLang && !isTS) {
store.state.errors = [`Only lang="ts" is supported for <script> blocks.`]
store.state.errors.push(`Only lang="ts" is supported for <script> blocks.`)
return
}

Expand Down Expand Up @@ -128,27 +154,48 @@ export async function compileFile(
descriptor.template &&
(!descriptor.scriptSetup || store.options?.script?.inlineTemplate === false)
) {
const clientTemplateResult = await doCompileTemplate(
const templateFilename = `${filename}.template.${
descriptor.template.lang || 'html'
}`
const source = withTransformer(
descriptor.template!.content,
templateFilename,
'pre'
)
let clientTemplateResult = await doCompileTemplate(
store,
descriptor,
source,
id,
bindings,
false,
isTS
)
clientTemplateResult = withTransformer(
clientTemplateResult || '',
templateFilename,
'post'
)
if (!clientTemplateResult) {
return
}
clientCode += clientTemplateResult

const ssrTemplateResult = await doCompileTemplate(
let ssrTemplateResult = await doCompileTemplate(
store,
descriptor,
source,
id,
bindings,
true,
isTS
)
ssrTemplateResult = withTransformer(
ssrTemplateResult || '',
templateFilename,
'post',
true
)
if (ssrTemplateResult) {
// ssr compile failure is fine
ssrCode += ssrTemplateResult
Expand All @@ -174,17 +221,19 @@ export async function compileFile(

// styles
let css = ''
for (const style of descriptor.styles) {
for (const [i, style] of descriptor.styles.entries()) {
if (style.module) {
store.state.errors = [
store.state.errors.push(
`<style module> is not supported in the playground.`
]
)
return
}

const styleFilename = `${filename}.${i}.${style.lang || 'css'}`
const source = withTransformer(style.content, styleFilename, 'pre')
const styleResult = await store.compiler.compileStyleAsync({
...store.options?.style,
source: style.content,
source,
filename,
id,
scoped: style.scoped,
Expand All @@ -198,7 +247,7 @@ export async function compileFile(
}
// proceed even if css compile errors
} else {
css += styleResult.code + '\n'
css += withTransformer(styleResult.code + '\n', styleFilename, 'post')
}
}
if (css) {
Expand All @@ -207,8 +256,9 @@ export async function compileFile(
compiled.css = '/* No <style> tags present */'
}

// clear errors
store.state.errors = []
compiled.js = withTransformer(compiled.js, filename, 'post')
compiled.ssr = withTransformer(compiled.ssr, filename, 'post', true)
compiled.css = withTransformer(compiled.css, filename + '.css', 'post')
}

async function doCompileScript(
Expand Down Expand Up @@ -270,14 +320,15 @@ async function doCompileScript(
async function doCompileTemplate(
store: Store,
descriptor: SFCDescriptor,
source: string,
id: string,
bindingMetadata: BindingMetadata | undefined,
ssr: boolean,
isTS: boolean
) {
const templateResult = store.compiler.compileTemplate({
...store.options?.template,
source: descriptor.template!.content,
source,
filename: descriptor.filename,
id,
scoped: descriptor.styles.some((s) => s.scoped),
Expand Down