wip: defineContext()
This commit is contained in:
parent
dc098c7f81
commit
6a9b56ca60
@ -62,7 +62,7 @@ export type HoistTransform = (
|
|||||||
) => void
|
) => void
|
||||||
|
|
||||||
export interface BindingMetadata {
|
export interface BindingMetadata {
|
||||||
[key: string]: 'data' | 'props' | 'setup' | 'options' | 'component-import'
|
[key: string]: 'data' | 'props' | 'setup' | 'options' | 'setup-raw'
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SharedTransformCodegenOptions {
|
interface SharedTransformCodegenOptions {
|
||||||
|
@ -270,9 +270,9 @@ export function resolveComponentType(
|
|||||||
`${context.helperString(UNREF)}(${tagFromSetup})`
|
`${context.helperString(UNREF)}(${tagFromSetup})`
|
||||||
: `$setup[${JSON.stringify(tagFromSetup)}]`
|
: `$setup[${JSON.stringify(tagFromSetup)}]`
|
||||||
}
|
}
|
||||||
const tagFromImport = checkType('component-import')
|
const tagFromImport = checkType('setup-raw')
|
||||||
if (tagFromImport) {
|
if (tagFromImport) {
|
||||||
// imports can be used as-is
|
// raw setup bindings (e.g. imports) can be used as-is
|
||||||
return tagFromImport
|
return tagFromImport
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,11 @@ export function processExpression(
|
|||||||
// setup inline mode
|
// setup inline mode
|
||||||
if (type === 'setup') {
|
if (type === 'setup') {
|
||||||
return `${context.helperString(UNREF)}(${raw})`
|
return `${context.helperString(UNREF)}(${raw})`
|
||||||
} else if (type === 'component-import') {
|
} else if (type === 'props') {
|
||||||
|
// use __props which is generated by compileScript so in ts mode
|
||||||
|
// it gets correct type
|
||||||
|
return `__props.${raw}`
|
||||||
|
} else if (type === 'setup-raw') {
|
||||||
return raw
|
return raw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,13 +134,13 @@ export function compileScript(
|
|||||||
source: string
|
source: string
|
||||||
}
|
}
|
||||||
> = Object.create(null)
|
> = Object.create(null)
|
||||||
const setupBindings: Record<string, boolean> = Object.create(null)
|
const setupBindings: Record<string, 'var' | 'const'> = Object.create(null)
|
||||||
const refBindings: Record<string, boolean> = Object.create(null)
|
const refBindings: Record<string, 'var'> = Object.create(null)
|
||||||
const refIdentifiers: Set<Identifier> = new Set()
|
const refIdentifiers: Set<Identifier> = new Set()
|
||||||
const enableRefSugar = options.refSugar !== false
|
const enableRefSugar = options.refSugar !== false
|
||||||
let defaultExport: Node | undefined
|
let defaultExport: Node | undefined
|
||||||
let setupContextExp: string | undefined
|
let setupContextExp: string | undefined
|
||||||
let setupContextArg: Node | undefined
|
let setupContextArg: ObjectExpression | undefined
|
||||||
let setupContextType: TSTypeLiteral | undefined
|
let setupContextType: TSTypeLiteral | undefined
|
||||||
let hasAwait = false
|
let hasAwait = false
|
||||||
|
|
||||||
@ -222,7 +222,7 @@ export function compileScript(
|
|||||||
if (id.name[0] === '$') {
|
if (id.name[0] === '$') {
|
||||||
error(`ref variable identifiers cannot start with $.`, id)
|
error(`ref variable identifiers cannot start with $.`, id)
|
||||||
}
|
}
|
||||||
refBindings[id.name] = setupBindings[id.name] = true
|
refBindings[id.name] = setupBindings[id.name] = 'var'
|
||||||
refIdentifiers.add(id)
|
refIdentifiers.add(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,10 +513,25 @@ export function compileScript(
|
|||||||
decl.id.start!,
|
decl.id.start!,
|
||||||
decl.id.end!
|
decl.id.end!
|
||||||
)
|
)
|
||||||
setupContextArg = decl.init.arguments[0]
|
const optsArg = decl.init.arguments[0]
|
||||||
|
if (optsArg.type === 'ObjectExpression') {
|
||||||
|
setupContextArg = optsArg
|
||||||
|
} else {
|
||||||
|
error(
|
||||||
|
`${CTX_FN_NAME}() argument must be an object literal.`,
|
||||||
|
optsArg
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// useSetupContext() has type parameters - infer runtime types from it
|
// useSetupContext() has type parameters - infer runtime types from it
|
||||||
if (decl.init.typeParameters) {
|
if (decl.init.typeParameters) {
|
||||||
|
if (setupContextArg) {
|
||||||
|
error(
|
||||||
|
`${CTX_FN_NAME}() cannot accept both type and non-type arguments ` +
|
||||||
|
`at the same time. Use one or the other.`,
|
||||||
|
decl.init
|
||||||
|
)
|
||||||
|
}
|
||||||
const typeArg = decl.init.typeParameters.params[0]
|
const typeArg = decl.init.typeParameters.params[0]
|
||||||
if (typeArg.type === 'TSTypeLiteral') {
|
if (typeArg.type === 'TSTypeLiteral') {
|
||||||
setupContextType = typeArg
|
setupContextType = typeArg
|
||||||
@ -685,7 +700,7 @@ export function compileScript(
|
|||||||
|
|
||||||
// 7. finalize setup argument signature.
|
// 7. finalize setup argument signature.
|
||||||
let args = setupContextExp ? `__props, ${setupContextExp}` : ``
|
let args = setupContextExp ? `__props, ${setupContextExp}` : ``
|
||||||
if (isTS) {
|
if (setupContextExp && setupContextType) {
|
||||||
if (slotsType === 'Slots') {
|
if (slotsType === 'Slots') {
|
||||||
helperImports.add('Slots')
|
helperImports.add('Slots')
|
||||||
}
|
}
|
||||||
@ -695,32 +710,11 @@ export function compileScript(
|
|||||||
slots: ${slotsType},
|
slots: ${slotsType},
|
||||||
attrs: ${attrsType}
|
attrs: ${attrsType}
|
||||||
}`
|
}`
|
||||||
// if (hasExplicitSignature) {
|
|
||||||
// // inject types to user signature
|
|
||||||
// args = setupValue as string
|
|
||||||
// const ss = new MagicString(args)
|
|
||||||
// if (propsASTNode) {
|
|
||||||
// // compensate for () wraper offset
|
|
||||||
// ss.appendRight(propsASTNode.end! - 1, `: ${propsType}`)
|
|
||||||
// }
|
|
||||||
// if (setupCtxASTNode) {
|
|
||||||
// ss.appendRight(setupCtxASTNode.end! - 1!, `: ${ctxType}`)
|
|
||||||
// }
|
|
||||||
// args = ss.toString()
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 8. wrap setup code with function.
|
|
||||||
// export the content of <script setup> as a named export, `setup`.
|
|
||||||
// this allows `import { setup } from '*.vue'` for testing purposes.
|
|
||||||
s.prependLeft(
|
|
||||||
startOffset,
|
|
||||||
`\nexport ${hasAwait ? `async ` : ``}function setup(${args}) {\n`
|
|
||||||
)
|
|
||||||
|
|
||||||
const allBindings = { ...setupBindings }
|
const allBindings = { ...setupBindings }
|
||||||
for (const key in userImports) {
|
for (const key in userImports) {
|
||||||
allBindings[key] = true
|
allBindings[key] = 'var'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 9. inject `useCssVars` calls
|
// 9. inject `useCssVars` calls
|
||||||
@ -741,23 +735,27 @@ export function compileScript(
|
|||||||
if (scriptAst) {
|
if (scriptAst) {
|
||||||
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
|
||||||
}
|
}
|
||||||
|
if (setupContextType) {
|
||||||
|
for (const key in typeDeclaredProps) {
|
||||||
|
bindingMetadata[key] = 'props'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (setupContextArg) {
|
||||||
|
Object.assign(bindingMetadata, analyzeBindingsFromOptions(setupContextArg))
|
||||||
|
}
|
||||||
if (options.inlineTemplate) {
|
if (options.inlineTemplate) {
|
||||||
for (const [key, { source }] of Object.entries(userImports)) {
|
for (const [key, { source }] of Object.entries(userImports)) {
|
||||||
bindingMetadata[key] = source.endsWith('.vue')
|
bindingMetadata[key] = source.endsWith('.vue') ? 'setup-raw' : 'setup'
|
||||||
? 'component-import'
|
|
||||||
: 'setup'
|
|
||||||
}
|
}
|
||||||
for (const key in setupBindings) {
|
for (const key in setupBindings) {
|
||||||
bindingMetadata[key] = 'setup'
|
bindingMetadata[key] =
|
||||||
|
setupBindings[key] === 'var' ? 'setup' : 'setup-raw'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const key in allBindings) {
|
for (const key in allBindings) {
|
||||||
bindingMetadata[key] = 'setup'
|
bindingMetadata[key] = 'setup'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const key in typeDeclaredProps) {
|
|
||||||
bindingMetadata[key] = 'props'
|
|
||||||
}
|
|
||||||
|
|
||||||
// 11. generate return statement
|
// 11. generate return statement
|
||||||
let returned
|
let returned
|
||||||
@ -798,6 +796,16 @@ export function compileScript(
|
|||||||
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
|
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
|
||||||
|
|
||||||
// 12. finalize default export
|
// 12. finalize default export
|
||||||
|
let runtimeOptions = ``
|
||||||
|
if (setupContextArg) {
|
||||||
|
runtimeOptions = `\n ${scriptSetup.content
|
||||||
|
.slice(setupContextArg.start! + 1, setupContextArg.end! - 1)
|
||||||
|
.trim()},`
|
||||||
|
} else if (setupContextType) {
|
||||||
|
runtimeOptions =
|
||||||
|
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
|
||||||
|
}
|
||||||
|
|
||||||
if (isTS) {
|
if (isTS) {
|
||||||
// for TS, make sure the exported type is still valid type with
|
// for TS, make sure the exported type is still valid type with
|
||||||
// correct props information
|
// correct props information
|
||||||
@ -805,18 +813,34 @@ export function compileScript(
|
|||||||
// we have to use object spread for types to be merged properly
|
// we have to use object spread for types to be merged properly
|
||||||
// user's TS setting should compile it down to proper targets
|
// user's TS setting should compile it down to proper targets
|
||||||
const def = defaultExport ? `\n ...${defaultTempVar},` : ``
|
const def = defaultExport ? `\n ...${defaultTempVar},` : ``
|
||||||
const runtimeProps = genRuntimeProps(typeDeclaredProps)
|
// wrap setup code with function.
|
||||||
const runtimeEmits = genRuntimeEmits(typeDeclaredEmits)
|
// export the content of <script setup> as a named export, `setup`.
|
||||||
s.append(
|
// this allows `import { setup } from '*.vue'` for testing purposes.
|
||||||
`export default defineComponent({${def}${runtimeProps}${runtimeEmits}\n setup\n})`
|
s.prependLeft(
|
||||||
|
startOffset,
|
||||||
|
`\nexport default defineComponent({${def}${runtimeOptions}\n ${
|
||||||
|
hasAwait ? `async ` : ``
|
||||||
|
}setup(${args}) {\n`
|
||||||
)
|
)
|
||||||
|
s.append(`})`)
|
||||||
} else {
|
} else {
|
||||||
if (defaultExport) {
|
if (defaultExport) {
|
||||||
|
// can't rely on spread operator in non ts mode
|
||||||
|
s.prependLeft(
|
||||||
|
startOffset,
|
||||||
|
`\n${hasAwait ? `async ` : ``}function setup(${args}) {\n`
|
||||||
|
)
|
||||||
s.append(
|
s.append(
|
||||||
`${defaultTempVar}.setup = setup\nexport default ${defaultTempVar}`
|
`/*#__PURE__*/ Object.assign(${defaultTempVar}, {${runtimeOptions}\n setup\n})\n` +
|
||||||
|
`export default ${defaultTempVar}`
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
s.append(`export default { setup }`)
|
s.prependLeft(
|
||||||
|
startOffset,
|
||||||
|
`\nexport default {${runtimeOptions}\n ` +
|
||||||
|
`${hasAwait ? `async ` : ``}setup(${args}) {\n`
|
||||||
|
)
|
||||||
|
s.append(`}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -843,16 +867,25 @@ export function compileScript(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkDeclaration(node: Declaration, bindings: Record<string, boolean>) {
|
function walkDeclaration(node: Declaration, bindings: Record<string, string>) {
|
||||||
if (node.type === 'VariableDeclaration') {
|
if (node.type === 'VariableDeclaration') {
|
||||||
|
const isConst = node.kind === 'const'
|
||||||
// export const foo = ...
|
// export const foo = ...
|
||||||
for (const { id } of node.declarations) {
|
for (const { id, init } of node.declarations) {
|
||||||
if (id.type === 'Identifier') {
|
if (id.type === 'Identifier') {
|
||||||
bindings[id.name] = true
|
bindings[id.name] =
|
||||||
|
// if a declaration is a const literal, we can mark it so that
|
||||||
|
// the generated render fn code doesn't need to unref() it
|
||||||
|
isConst &&
|
||||||
|
init!.type !== 'Identifier' && // const a = b
|
||||||
|
init!.type !== 'CallExpression' && // const a = ref()
|
||||||
|
init!.type !== 'MemberExpression' // const a = b.c
|
||||||
|
? 'const'
|
||||||
|
: 'var'
|
||||||
} else if (id.type === 'ObjectPattern') {
|
} else if (id.type === 'ObjectPattern') {
|
||||||
walkObjectPattern(id, bindings)
|
walkObjectPattern(id, bindings, isConst)
|
||||||
} else if (id.type === 'ArrayPattern') {
|
} else if (id.type === 'ArrayPattern') {
|
||||||
walkArrayPattern(id, bindings)
|
walkArrayPattern(id, bindings, isConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
@ -861,13 +894,14 @@ function walkDeclaration(node: Declaration, bindings: Record<string, boolean>) {
|
|||||||
) {
|
) {
|
||||||
// export function foo() {} / export class Foo {}
|
// export function foo() {} / export class Foo {}
|
||||||
// export declarations must be named.
|
// export declarations must be named.
|
||||||
bindings[node.id!.name] = true
|
bindings[node.id!.name] = 'const'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkObjectPattern(
|
function walkObjectPattern(
|
||||||
node: ObjectPattern,
|
node: ObjectPattern,
|
||||||
bindings: Record<string, boolean>
|
bindings: Record<string, string>,
|
||||||
|
isConst: boolean
|
||||||
) {
|
) {
|
||||||
for (const p of node.properties) {
|
for (const p of node.properties) {
|
||||||
if (p.type === 'ObjectProperty') {
|
if (p.type === 'ObjectProperty') {
|
||||||
@ -875,43 +909,48 @@ function walkObjectPattern(
|
|||||||
if (p.key.type === 'Identifier') {
|
if (p.key.type === 'Identifier') {
|
||||||
if (p.key === p.value) {
|
if (p.key === p.value) {
|
||||||
// const { x } = ...
|
// const { x } = ...
|
||||||
bindings[p.key.name] = true
|
bindings[p.key.name] = 'var'
|
||||||
} else {
|
} else {
|
||||||
walkPattern(p.value, bindings)
|
walkPattern(p.value, bindings, isConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// ...rest
|
// ...rest
|
||||||
// argument can only be identifer when destructuring
|
// argument can only be identifer when destructuring
|
||||||
bindings[(p.argument as Identifier).name] = true
|
bindings[(p.argument as Identifier).name] = isConst ? 'const' : 'var'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkArrayPattern(
|
function walkArrayPattern(
|
||||||
node: ArrayPattern,
|
node: ArrayPattern,
|
||||||
bindings: Record<string, boolean>
|
bindings: Record<string, string>,
|
||||||
|
isConst: boolean
|
||||||
) {
|
) {
|
||||||
for (const e of node.elements) {
|
for (const e of node.elements) {
|
||||||
e && walkPattern(e, bindings)
|
e && walkPattern(e, bindings, isConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function walkPattern(node: Node, bindings: Record<string, boolean>) {
|
function walkPattern(
|
||||||
|
node: Node,
|
||||||
|
bindings: Record<string, string>,
|
||||||
|
isConst: boolean
|
||||||
|
) {
|
||||||
if (node.type === 'Identifier') {
|
if (node.type === 'Identifier') {
|
||||||
bindings[node.name] = true
|
bindings[node.name] = 'var'
|
||||||
} else if (node.type === 'RestElement') {
|
} else if (node.type === 'RestElement') {
|
||||||
// argument can only be identifer when destructuring
|
// argument can only be identifer when destructuring
|
||||||
bindings[(node.argument as Identifier).name] = true
|
bindings[(node.argument as Identifier).name] = isConst ? 'const' : 'var'
|
||||||
} else if (node.type === 'ObjectPattern') {
|
} else if (node.type === 'ObjectPattern') {
|
||||||
walkObjectPattern(node, bindings)
|
walkObjectPattern(node, bindings, isConst)
|
||||||
} else if (node.type === 'ArrayPattern') {
|
} else if (node.type === 'ArrayPattern') {
|
||||||
walkArrayPattern(node, bindings)
|
walkArrayPattern(node, bindings, isConst)
|
||||||
} else if (node.type === 'AssignmentPattern') {
|
} else if (node.type === 'AssignmentPattern') {
|
||||||
if (node.left.type === 'Identifier') {
|
if (node.left.type === 'Identifier') {
|
||||||
bindings[node.left.name] = true
|
bindings[node.left.name] = 'var'
|
||||||
} else {
|
} else {
|
||||||
walkPattern(node.left, bindings)
|
walkPattern(node.left, bindings, isConst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1273,14 +1312,20 @@ function getObjectOrArrayExpressionKeys(property: ObjectProperty): string[] {
|
|||||||
* compilation process so this should only be used on single `<script>` SFCs.
|
* compilation process so this should only be used on single `<script>` SFCs.
|
||||||
*/
|
*/
|
||||||
function analyzeScriptBindings(ast: Statement[]): BindingMetadata {
|
function analyzeScriptBindings(ast: Statement[]): BindingMetadata {
|
||||||
const bindings: BindingMetadata = {}
|
|
||||||
|
|
||||||
for (const node of ast) {
|
for (const node of ast) {
|
||||||
if (
|
if (
|
||||||
node.type === 'ExportDefaultDeclaration' &&
|
node.type === 'ExportDefaultDeclaration' &&
|
||||||
node.declaration.type === 'ObjectExpression'
|
node.declaration.type === 'ObjectExpression'
|
||||||
) {
|
) {
|
||||||
for (const property of node.declaration.properties) {
|
return analyzeBindingsFromOptions(node.declaration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
|
||||||
|
function analyzeBindingsFromOptions(node: ObjectExpression): BindingMetadata {
|
||||||
|
const bindings: BindingMetadata = {}
|
||||||
|
for (const property of node.properties) {
|
||||||
if (
|
if (
|
||||||
property.type === 'ObjectProperty' &&
|
property.type === 'ObjectProperty' &&
|
||||||
!property.computed &&
|
!property.computed &&
|
||||||
@ -1307,8 +1352,7 @@ function analyzeScriptBindings(ast: Statement[]): BindingMetadata {
|
|||||||
// computed & methods
|
// computed & methods
|
||||||
else if (
|
else if (
|
||||||
property.value.type === 'ObjectExpression' &&
|
property.value.type === 'ObjectExpression' &&
|
||||||
(property.key.name === 'computed' ||
|
(property.key.name === 'computed' || property.key.name === 'methods')
|
||||||
property.key.name === 'methods')
|
|
||||||
) {
|
) {
|
||||||
// methods: { foo() {} }
|
// methods: { foo() {} }
|
||||||
// computed: { foo() {} }
|
// computed: { foo() {} }
|
||||||
@ -1342,8 +1386,6 @@ function analyzeScriptBindings(ast: Statement[]): BindingMetadata {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return bindings
|
return bindings
|
||||||
}
|
}
|
||||||
|
22
packages/runtime-core/src/apiDefineContext.ts
Normal file
22
packages/runtime-core/src/apiDefineContext.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { Slots } from './componentSlots'
|
||||||
|
import { warn } from './warning'
|
||||||
|
|
||||||
|
interface DefaultContext {
|
||||||
|
props: Record<string, unknown>
|
||||||
|
attrs: Record<string, unknown>
|
||||||
|
emit: (...args: any[]) => void
|
||||||
|
slots: Slots
|
||||||
|
}
|
||||||
|
|
||||||
|
export function defineContext<T extends Partial<DefaultContext> = {}>(
|
||||||
|
opts?: any // TODO infer
|
||||||
|
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
|
||||||
|
if (__DEV__) {
|
||||||
|
warn(
|
||||||
|
`defineContext() is a compiler-hint helper that is only usable inside ` +
|
||||||
|
`<script setup> of a single file component. It will be compiled away ` +
|
||||||
|
`and should not be used in final distributed code.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null as any
|
||||||
|
}
|
@ -105,7 +105,7 @@ export interface ComponentInternalOptions {
|
|||||||
export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
|
export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
|
||||||
extends ComponentInternalOptions {
|
extends ComponentInternalOptions {
|
||||||
// use of any here is intentional so it can be a valid JSX Element constructor
|
// use of any here is intentional so it can be a valid JSX Element constructor
|
||||||
(props: P, ctx: SetupContext<E>): any
|
(props: P, ctx: SetupContext<E, P>): any
|
||||||
props?: ComponentPropsOptions<P>
|
props?: ComponentPropsOptions<P>
|
||||||
emits?: E | (keyof E)[]
|
emits?: E | (keyof E)[]
|
||||||
inheritAttrs?: boolean
|
inheritAttrs?: boolean
|
||||||
@ -167,7 +167,8 @@ export const enum LifecycleHooks {
|
|||||||
ERROR_CAPTURED = 'ec'
|
ERROR_CAPTURED = 'ec'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SetupContext<E = EmitsOptions> {
|
export interface SetupContext<E = EmitsOptions, P = Data> {
|
||||||
|
props: P
|
||||||
attrs: Data
|
attrs: Data
|
||||||
slots: Slots
|
slots: Slots
|
||||||
emit: EmitFn<E>
|
emit: EmitFn<E>
|
||||||
@ -735,6 +736,9 @@ function createSetupContext(instance: ComponentInternalInstance): SetupContext {
|
|||||||
// We use getters in dev in case libs like test-utils overwrite instance
|
// We use getters in dev in case libs like test-utils overwrite instance
|
||||||
// properties (overwrites should not be done in prod)
|
// properties (overwrites should not be done in prod)
|
||||||
return Object.freeze({
|
return Object.freeze({
|
||||||
|
get props() {
|
||||||
|
return instance.props
|
||||||
|
},
|
||||||
get attrs() {
|
get attrs() {
|
||||||
return new Proxy(instance.attrs, attrHandlers)
|
return new Proxy(instance.attrs, attrHandlers)
|
||||||
},
|
},
|
||||||
@ -747,6 +751,7 @@ function createSetupContext(instance: ComponentInternalInstance): SetupContext {
|
|||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
props: instance.props,
|
||||||
attrs: instance.attrs,
|
attrs: instance.attrs,
|
||||||
slots: instance.slots,
|
slots: instance.slots,
|
||||||
emit: instance.emit
|
emit: instance.emit
|
||||||
|
@ -96,7 +96,7 @@ export interface ComponentOptionsBase<
|
|||||||
setup?: (
|
setup?: (
|
||||||
this: void,
|
this: void,
|
||||||
props: Props,
|
props: Props,
|
||||||
ctx: SetupContext<E>
|
ctx: SetupContext<E, Props>
|
||||||
) => Promise<RawBindings> | RawBindings | RenderFunction | void
|
) => Promise<RawBindings> | RawBindings | RenderFunction | void
|
||||||
name?: string
|
name?: string
|
||||||
template?: string | object // can be a direct DOM node
|
template?: string | object // can be a direct DOM node
|
||||||
|
@ -95,6 +95,7 @@ export function renderComponentRoot(
|
|||||||
props,
|
props,
|
||||||
__DEV__
|
__DEV__
|
||||||
? {
|
? {
|
||||||
|
props,
|
||||||
get attrs() {
|
get attrs() {
|
||||||
markAttrsAccessed()
|
markAttrsAccessed()
|
||||||
return attrs
|
return attrs
|
||||||
@ -102,7 +103,7 @@ export function renderComponentRoot(
|
|||||||
slots,
|
slots,
|
||||||
emit
|
emit
|
||||||
}
|
}
|
||||||
: { attrs, slots, emit }
|
: { props, attrs, slots, emit }
|
||||||
)
|
)
|
||||||
: render(props, null as any /* we know it doesn't need it */)
|
: render(props, null as any /* we know it doesn't need it */)
|
||||||
)
|
)
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
import { EMPTY_OBJ } from '@vue/shared'
|
|
||||||
import { Slots } from '../componentSlots'
|
|
||||||
|
|
||||||
interface DefaultContext {
|
|
||||||
props: Record<string, unknown>
|
|
||||||
attrs: Record<string, unknown>
|
|
||||||
emit: (...args: any[]) => void
|
|
||||||
slots: Slots
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useSetupContext<T extends Partial<DefaultContext> = {}>(
|
|
||||||
opts?: any // TODO infer
|
|
||||||
): { [K in keyof DefaultContext]: T[K] extends {} ? T[K] : DefaultContext[K] } {
|
|
||||||
return EMPTY_OBJ as any
|
|
||||||
}
|
|
@ -43,6 +43,7 @@ export { provide, inject } from './apiInject'
|
|||||||
export { nextTick } from './scheduler'
|
export { nextTick } from './scheduler'
|
||||||
export { defineComponent } from './apiDefineComponent'
|
export { defineComponent } from './apiDefineComponent'
|
||||||
export { defineAsyncComponent } from './apiAsyncComponent'
|
export { defineAsyncComponent } from './apiAsyncComponent'
|
||||||
|
export { defineContext } from './apiDefineContext'
|
||||||
|
|
||||||
// Advanced API ----------------------------------------------------------------
|
// Advanced API ----------------------------------------------------------------
|
||||||
|
|
||||||
@ -261,8 +262,6 @@ import {
|
|||||||
setCurrentRenderingInstance
|
setCurrentRenderingInstance
|
||||||
} from './componentRenderUtils'
|
} from './componentRenderUtils'
|
||||||
import { isVNode, normalizeVNode } from './vnode'
|
import { isVNode, normalizeVNode } from './vnode'
|
||||||
import { Slots } from './componentSlots'
|
|
||||||
import { EMPTY_OBJ } from '@vue/shared/src'
|
|
||||||
|
|
||||||
const _ssrUtils = {
|
const _ssrUtils = {
|
||||||
createComponentInstance,
|
createComponentInstance,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user