diff --git a/packages/compiler-core/src/options.ts b/packages/compiler-core/src/options.ts
index bb18faf0..bb59f494 100644
--- a/packages/compiler-core/src/options.ts
+++ b/packages/compiler-core/src/options.ts
@@ -62,10 +62,31 @@ export type HoistTransform = (
) => void
export const enum BindingTypes {
+ /**
+ * returned from data()
+ */
DATA = 'data',
+ /**
+ * decalred as a prop
+ */
PROPS = 'props',
- SETUP = 'setup',
- CONST = 'const',
+ /**
+ * a let binding (may or may not be a ref)
+ */
+ SETUP_LET = 'setup-let',
+ /**
+ * a const binding that can never be a ref.
+ * these bindings don't need `unref()` calls when processed in inlined
+ * template expressions.
+ */
+ SETUP_CONST = 'setup-const',
+ /**
+ * a const binding that may be a ref.
+ */
+ SETUP_CONST_REF = 'setup-const-ref',
+ /**
+ * declared by other options, e.g. computed, inject
+ */
OPTIONS = 'options'
}
diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts
index e9e1ac58..e3989a80 100644
--- a/packages/compiler-core/src/transforms/transformElement.ts
+++ b/packages/compiler-core/src/transforms/transformElement.ts
@@ -263,20 +263,22 @@ export function resolveComponentType(
return resolvedTag
}
}
- const tagFromSetup = checkType(BindingTypes.SETUP)
- if (tagFromSetup) {
- return context.inline
- ? // setup scope bindings may be refs so they need to be unrefed
- `${context.helperString(UNREF)}(${tagFromSetup})`
- : `$setup[${JSON.stringify(tagFromSetup)}]`
- }
- const tagFromConst = checkType(BindingTypes.CONST)
+ const tagFromConst = checkType(BindingTypes.SETUP_CONST)
if (tagFromConst) {
return context.inline
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
tagFromConst
: `$setup[${JSON.stringify(tagFromConst)}]`
}
+ const tagFromSetup =
+ checkType(BindingTypes.SETUP_LET) ||
+ checkType(BindingTypes.SETUP_CONST_REF)
+ if (tagFromSetup) {
+ return context.inline
+ ? // setup scope bindings that may be refs need to be unrefed
+ `${context.helperString(UNREF)}(${tagFromSetup})`
+ : `$setup[${JSON.stringify(tagFromSetup)}]`
+ }
}
// 4. user component (resolve)
diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts
index 0a6cc8ef..9c33cf67 100644
--- a/packages/compiler-core/src/transforms/transformExpression.ts
+++ b/packages/compiler-core/src/transforms/transformExpression.ts
@@ -104,9 +104,12 @@ export function processExpression(
const type = hasOwn(bindingMetadata, raw) && bindingMetadata[raw]
if (inline) {
// setup inline mode
- if (type === BindingTypes.CONST) {
+ if (type === BindingTypes.SETUP_CONST) {
return raw
- } else if (type === BindingTypes.SETUP) {
+ } else if (
+ type === BindingTypes.SETUP_CONST_REF ||
+ type === BindingTypes.SETUP_LET
+ ) {
return `${context.helperString(UNREF)}(${raw})`
} else if (type === BindingTypes.PROPS) {
// use __props which is generated by compileScript so in ts mode
@@ -114,8 +117,12 @@ export function processExpression(
return `__props.${raw}`
}
} else {
- if (type === BindingTypes.CONST) {
- // setup const binding in non-inline mode
+ if (
+ type === BindingTypes.SETUP_LET ||
+ type === BindingTypes.SETUP_CONST ||
+ type === BindingTypes.SETUP_CONST_REF
+ ) {
+ // setup bindings in non-inline mode
return `$setup.${raw}`
} else if (type) {
return `$${type}.${raw}`
@@ -131,7 +138,9 @@ export function processExpression(
const bailConstant = rawExp.indexOf(`(`) > -1
if (isSimpleIdentifier(rawExp)) {
// const bindings exposed from setup - we know they never change
- if (bindingMetadata[node.content] === BindingTypes.CONST) {
+ // marking it as runtime constant will prevent it from being listed as
+ // a dynamic prop.
+ if (bindingMetadata[node.content] === BindingTypes.SETUP_CONST) {
node.isRuntimeConstant = true
}
if (
diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts
index 41771fd2..180b2473 100644
--- a/packages/compiler-sfc/__tests__/compileScript.spec.ts
+++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts
@@ -1,3 +1,4 @@
+import { BindingTypes } from '@vue/compiler-dom/src'
import { compileSFCScript as compile, assertCode } from './utils'
describe('SFC compile
`)
- expect(bindings).toStrictEqual({ foo: 'props', bar: 'props' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.PROPS,
+ bar: BindingTypes.PROPS
+ })
})
it('recognizes props object declaration', () => {
@@ -702,10 +706,10 @@ describe('SFC analyze
`)
expect(bindings).toStrictEqual({
- foo: 'props',
- bar: 'props',
- baz: 'props',
- qux: 'props'
+ foo: BindingTypes.PROPS,
+ bar: BindingTypes.PROPS,
+ baz: BindingTypes.PROPS,
+ qux: BindingTypes.PROPS
})
})
@@ -723,7 +727,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'setup', bar: 'setup' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.SETUP_CONST_REF,
+ bar: BindingTypes.SETUP_CONST_REF
+ })
})
it('recognizes async setup return', () => {
@@ -740,7 +747,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'setup', bar: 'setup' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.SETUP_CONST_REF,
+ bar: BindingTypes.SETUP_CONST_REF
+ })
})
it('recognizes data return', () => {
@@ -757,7 +767,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'data', bar: 'data' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.DATA,
+ bar: BindingTypes.DATA
+ })
})
it('recognizes methods', () => {
@@ -770,7 +783,7 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'options' })
+ expect(bindings).toStrictEqual({ foo: BindingTypes.OPTIONS })
})
it('recognizes computeds', () => {
@@ -787,7 +800,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'options', bar: 'options' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.OPTIONS,
+ bar: BindingTypes.OPTIONS
+ })
})
it('recognizes injections array declaration', () => {
@@ -798,7 +814,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'options', bar: 'options' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.OPTIONS,
+ bar: BindingTypes.OPTIONS
+ })
})
it('recognizes injections object declaration', () => {
@@ -812,7 +831,10 @@ describe('SFC analyze
`)
- expect(bindings).toStrictEqual({ foo: 'options', bar: 'options' })
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.OPTIONS,
+ bar: BindingTypes.OPTIONS
+ })
})
it('works for mixed bindings', () => {
@@ -843,12 +865,12 @@ describe('SFC analyze
`)
expect(bindings).toStrictEqual({
- foo: 'options',
- bar: 'props',
- baz: 'setup',
- qux: 'data',
- quux: 'options',
- quuz: 'options'
+ foo: BindingTypes.OPTIONS,
+ bar: BindingTypes.PROPS,
+ baz: BindingTypes.SETUP_CONST_REF,
+ qux: BindingTypes.DATA,
+ quux: BindingTypes.OPTIONS,
+ quuz: BindingTypes.OPTIONS
})
})
@@ -864,7 +886,7 @@ describe('SFC analyze
`)
expect(bindings).toStrictEqual({
- foo: 'props'
+ foo: BindingTypes.PROPS
})
})
})
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index aa44b99c..bdbd0b1d 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -159,11 +159,8 @@ export function compileScript(
source: string
}
> = Object.create(null)
- const setupBindings: Record<
- string,
- BindingTypes.SETUP | BindingTypes.CONST
- > = Object.create(null)
- const refBindings: Record = Object.create(null)
+ const setupBindings: Record = Object.create(null)
+ const refBindings: Record = Object.create(null)
const refIdentifiers: Set = new Set()
const enableRefSugar = options.refSugar !== false
let defaultExport: Node | undefined
@@ -311,7 +308,7 @@ export function compileScript(
if (id.name[0] === '$') {
error(`ref variable identifiers cannot start with $.`, id)
}
- refBindings[id.name] = setupBindings[id.name] = BindingTypes.SETUP
+ refBindings[id.name] = setupBindings[id.name] = BindingTypes.SETUP_CONST_REF
refIdentifiers.add(id)
}
@@ -787,8 +784,8 @@ export function compileScript(
}
for (const [key, { source }] of Object.entries(userImports)) {
bindingMetadata[key] = source.endsWith('.vue')
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : BindingTypes.SETUP_CONST_REF
}
for (const key in setupBindings) {
bindingMetadata[key] = setupBindings[key]
@@ -966,8 +963,10 @@ function walkDeclaration(
init!.type !== 'Identifier' && // const a = b
init!.type !== 'CallExpression' && // const a = ref()
init!.type !== 'MemberExpression') // const a = b.c
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : isConst
+ ? BindingTypes.SETUP_CONST_REF
+ : BindingTypes.SETUP_LET
} else if (id.type === 'ObjectPattern') {
walkObjectPattern(id, bindings, isConst, isUseOptionsCall)
} else if (id.type === 'ArrayPattern') {
@@ -980,7 +979,7 @@ function walkDeclaration(
) {
// export function foo() {} / export class Foo {}
// export declarations must be named.
- bindings[node.id!.name] = BindingTypes.CONST
+ bindings[node.id!.name] = BindingTypes.SETUP_CONST
}
}
@@ -997,8 +996,10 @@ function walkObjectPattern(
if (p.key === p.value) {
// const { x } = ...
bindings[p.key.name] = isUseOptionsCall
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : isConst
+ ? BindingTypes.SETUP_CONST_REF
+ : BindingTypes.SETUP_LET
} else {
walkPattern(p.value, bindings, isConst, isUseOptionsCall)
}
@@ -1007,8 +1008,8 @@ function walkObjectPattern(
// ...rest
// argument can only be identifer when destructuring
bindings[(p.argument as Identifier).name] = isConst
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : BindingTypes.SETUP_LET
}
}
}
@@ -1032,13 +1033,15 @@ function walkPattern(
) {
if (node.type === 'Identifier') {
bindings[node.name] = isUseOptionsCall
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : isConst
+ ? BindingTypes.SETUP_CONST_REF
+ : BindingTypes.SETUP_LET
} else if (node.type === 'RestElement') {
// argument can only be identifer when destructuring
bindings[(node.argument as Identifier).name] = isConst
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : BindingTypes.SETUP_LET
} else if (node.type === 'ObjectPattern') {
walkObjectPattern(node, bindings, isConst)
} else if (node.type === 'ArrayPattern') {
@@ -1046,8 +1049,10 @@ function walkPattern(
} else if (node.type === 'AssignmentPattern') {
if (node.left.type === 'Identifier') {
bindings[node.left.name] = isUseOptionsCall
- ? BindingTypes.CONST
- : BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST
+ : isConst
+ ? BindingTypes.SETUP_CONST_REF
+ : BindingTypes.SETUP_LET
} else {
walkPattern(node.left, bindings, isConst)
}
@@ -1490,7 +1495,7 @@ function analyzeBindingsFromOptions(node: ObjectExpression): BindingMetadata {
for (const key of getObjectExpressionKeys(bodyItem.argument)) {
bindings[key] =
property.key.name === 'setup'
- ? BindingTypes.SETUP
+ ? BindingTypes.SETUP_CONST_REF
: BindingTypes.DATA
}
}