Skip to content

Commit

Permalink
feat(compiler-sfc): introduce defineRender
Browse files Browse the repository at this point in the history
  • Loading branch information
sxzz committed Oct 17, 2023
1 parent 9177199 commit 9a8053c
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`defineRender() > JSX Element 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();
return () => <div />
}
})"
`;

exports[`defineRender() > function 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();
return () => <div />
}
})"
`;

exports[`defineRender() > identifier 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
import { renderFn } from './ctx'
export default /*#__PURE__*/_defineComponent({
setup(__props, { expose: __expose }) {
__expose();
return renderFn
}
})"
`;
46 changes: 46 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/defineRender.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { compileSFCScript as compile, assertCode } from '../utils'

describe('defineRender()', () => {
test('JSX Element', () => {
const { content } = compile(
`
<script setup lang="tsx">
defineRender(<div />)
</script>
`,
{ defineRender: true }
)
assertCode(content)
expect(content).toMatch(`return () => <div />`)
expect(content).not.toMatch('defineRender')
})

test('function', () => {
const { content } = compile(
`
<script setup lang="tsx">
defineRender(() => <div />)
</script>
`,
{ defineRender: true }
)
assertCode(content)
expect(content).toMatch(`return () => <div />`)
expect(content).not.toMatch('defineRender')
})

test('identifier', () => {
const { content } = compile(
`
<script setup lang="ts">
import { renderFn } from './ctx'
defineRender(renderFn)
</script>
`,
{ defineRender: true }
)
assertCode(content)
expect(content).toMatch(`return renderFn`)
expect(content).not.toMatch('defineRender')
})
})
2 changes: 1 addition & 1 deletion packages/compiler-sfc/__tests__/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export function assertCode(code: string) {
try {
babelParse(code, {
sourceType: 'module',
plugins: ['typescript']
plugins: ['typescript', 'jsx']
})
} catch (e: any) {
console.log(code)
Expand Down
27 changes: 23 additions & 4 deletions packages/compiler-sfc/src/compileScript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import {
import { analyzeScriptBindings } from './script/analyzeScriptBindings'
import { isImportUsed } from './script/importUsageCheck'
import { processAwait } from './script/topLevelAwait'
import { DEFINE_RENDER, processDefineRender } from './script/defineRender'

export interface SFCScriptCompileOptions {
/**
Expand Down Expand Up @@ -108,6 +109,11 @@ export interface SFCScriptCompileOptions {
* @default false
*/
defineModel?: boolean
/**
* (**Experimental**) Enable macro `defineRender`
* @default false
*/
defineRender?: boolean
/**
* (**Experimental**) Enable reactive destructure for `defineProps`
* @default false
Expand Down Expand Up @@ -512,7 +518,8 @@ export function compileScript(
processDefineProps(ctx, expr) ||
processDefineEmits(ctx, expr) ||
processDefineOptions(ctx, expr) ||
processDefineSlots(ctx, expr)
processDefineSlots(ctx, expr) ||
processDefineRender(ctx, expr)
) {
ctx.s.remove(node.start! + startOffset, node.end! + startOffset)
} else if (processDefineExpose(ctx, expr)) {
Expand Down Expand Up @@ -550,7 +557,8 @@ export function compileScript(
!isDefineProps && processDefineEmits(ctx, init, decl.id)
!isDefineEmits &&
(processDefineSlots(ctx, init, decl.id) ||
processDefineModel(ctx, init, decl.id))
processDefineModel(ctx, init, decl.id) ||
processDefineRender(ctx, init))

if (
isDefineProps &&
Expand Down Expand Up @@ -832,8 +840,19 @@ export function compileScript(
}

// 10. generate return statement
let returned
if (
let returned = ''
if (ctx.renderFunction) {
if (sfc.template) {
warnOnce(`<template> is ignored when using ${DEFINE_RENDER}().`)
}
if (ctx.renderFunction.type === 'JSXElement') {
returned = '() => '
}
returned += scriptSetup.content.slice(
ctx.renderFunction.start!,
ctx.renderFunction.end!
)
} else if (
!options.inlineTemplate ||
(!sfc.template && ctx.hasDefaultExportRender)
) {
Expand Down
4 changes: 4 additions & 0 deletions packages/compiler-sfc/src/script/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export class ScriptCompileContext {
hasDefaultExportRender = false
hasDefineOptionsCall = false
hasDefineSlotsCall = false
hasDefineRenderCall = false
hasDefineModelCall = false

// defineProps
Expand All @@ -58,6 +59,9 @@ export class ScriptCompileContext {
// defineOptions
optionsRuntimeDecl: Node | undefined

// defineRender
renderFunction?: Node

// codegen
bindingMetadata: BindingMetadata = {}
helperImports: Set<string> = new Set()
Expand Down
34 changes: 34 additions & 0 deletions packages/compiler-sfc/src/script/defineRender.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Node } from '@babel/types'
import { isCallOf } from './utils'
import { ScriptCompileContext } from './context'
import { warnOnce } from '../warn'

export const DEFINE_RENDER = 'defineRender'

export function processDefineRender(
ctx: ScriptCompileContext,
node: Node
): boolean {
if (!isCallOf(node, DEFINE_RENDER)) {
return false
}

if (!ctx.options.defineRender) {
warnOnce(
`${DEFINE_RENDER}() is an experimental feature and disabled by default.\n` +
`To enable it, follow the RFC at https://github.com/vuejs/rfcs/discussions/TODO.`
)
return false
}

if (ctx.hasDefineRenderCall) {
ctx.error(`duplicate ${DEFINE_RENDER}() call`, node)
}

ctx.hasDefineRenderCall = true
if (node.arguments.length > 0) {
ctx.renderFunction = node.arguments[0]
}

return true
}

0 comments on commit 9a8053c

Please sign in to comment.