From 00b76d3dc192138514ae6464ded34be5b0c730bb Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 11 Aug 2021 10:19:58 -0400 Subject: [PATCH] feat(sfc): support $shallowRef ref sugar --- .../compileScriptRefSugar.spec.ts.snap | 6 ++-- .../__tests__/compileScriptRefSugar.spec.ts | 12 ++++---- packages/compiler-sfc/src/compileScript.ts | 29 ++++++++++++------- packages/runtime-core/src/helpers/refSugar.ts | 4 +++ packages/runtime-core/src/index.ts | 8 ++++- .../types/scriptSetupHelpers.d.ts | 2 ++ test-dts/refSugar.test-d.ts | 5 ++++ 7 files changed, 46 insertions(+), 20 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap index 32acabe3d..dbe6aa1dd 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap @@ -33,8 +33,8 @@ return { a, b, c } }" `; -exports[``) - expect(content).toMatch(`import { ref as _ref } from 'vue'`) + expect(content).toMatch( + `import { ref as _ref, shallowRef as _shallowRef } from 'vue'` + ) expect(content).not.toMatch(`$ref()`) expect(content).not.toMatch(`$ref(1)`) - expect(content).not.toMatch(`$ref({`) + expect(content).not.toMatch(`$shallowRef({`) expect(content).toMatch(`let foo = _ref()`) expect(content).toMatch(`let a = _ref(1)`) expect(content).toMatch(` - let b = _ref({ + let b = _shallowRef({ count: 0 }) `) diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index 000dff412..9e4a2ceb8 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/packages/compiler-sfc/src/compileScript.ts @@ -65,6 +65,7 @@ const DEFINE_EXPOSE = 'defineExpose' const WITH_DEFAULTS = 'withDefaults' const $REF = `$ref` +const $SHALLOW_REF = '$shallowRef' const $COMPUTED = `$computed` const $FROM_REFS = `$fromRefs` const $RAW = `$raw` @@ -531,7 +532,12 @@ export function compileScript( } function isRefSugarCall(callee: string) { - return callee === $REF || callee === $COMPUTED || callee === $FROM_REFS + return ( + callee === $REF || + callee === $COMPUTED || + callee === $FROM_REFS || + callee === $SHALLOW_REF + ) } function processRefSugar( @@ -558,24 +564,28 @@ export function compileScript( const callee = (decl.init.callee as Identifier).name const start = decl.init.start! + startOffset - if (callee === $REF) { + if (callee === $REF || callee === $SHALLOW_REF) { if (statement.kind !== 'let') { - error(`${$REF}() bindings can only be declared with let.`, decl) + error(`${callee}() bindings can only be declared with let.`, decl) } if (decl.id.type !== 'Identifier') { error( - `${$REF}() bindings cannot be used with destructuring. ` + + `${callee}() bindings cannot be used with destructuring. ` + `If you are trying to destructure from an object of refs, ` + `use \`let { x } = $fromRefs(obj)\`.`, decl.id ) } registerRefBinding(decl.id) - s.overwrite(start, start + $REF.length, helper('ref')) + s.overwrite( + start, + start + callee.length, + helper(callee === $REF ? 'ref' : 'shallowRef') + ) } else if (callee === $COMPUTED) { if (decl.id.type !== 'Identifier') { error( - `${$COMPUTED}() bindings cannot be used with destructuring.`, + `${callee}() bindings cannot be used with destructuring.`, decl.id ) } @@ -584,7 +594,7 @@ export function compileScript( } else if (callee === $FROM_REFS) { if (!decl.id.type.endsWith('Pattern')) { error( - `${$FROM_REFS}() declaration must be used with destructure patterns.`, + `${callee}() declaration must be used with destructure patterns.`, decl ) } @@ -1124,10 +1134,7 @@ export function compileScript( return false // skip walk } else if ( parent && - isCallOf( - node, - id => id === $REF || id === $FROM_REFS || id === $COMPUTED - ) && + isCallOf(node, isRefSugarCall) && (parent.type !== 'VariableDeclarator' || node !== parent.init) ) { error( diff --git a/packages/runtime-core/src/helpers/refSugar.ts b/packages/runtime-core/src/helpers/refSugar.ts index 4c62441d2..91480dfa9 100644 --- a/packages/runtime-core/src/helpers/refSugar.ts +++ b/packages/runtime-core/src/helpers/refSugar.ts @@ -3,6 +3,10 @@ import { Ref, UnwrapRef, ShallowUnwrapRef, ComputedRef } from '@vue/reactivity' export function $ref(arg: T | Ref): UnwrapRef export function $ref() {} +export function $shallowRef(arg: T): T { + return arg +} + declare const ComputedRefMarker: unique symbol type ComputedRefValue = T & { [ComputedRefMarker]?: any } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index a784bd73f..c46b6df22 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -354,4 +354,10 @@ export const compatUtils = ( // Ref sugar macros ------------------------------------------------------------ // for dts generation only -export { $ref, $computed, $raw, $fromRefs } from './helpers/refSugar' +export { + $ref, + $shallowRef, + $computed, + $raw, + $fromRefs +} from './helpers/refSugar' diff --git a/packages/runtime-core/types/scriptSetupHelpers.d.ts b/packages/runtime-core/types/scriptSetupHelpers.d.ts index fc56cb19c..69cab07ad 100644 --- a/packages/runtime-core/types/scriptSetupHelpers.d.ts +++ b/packages/runtime-core/types/scriptSetupHelpers.d.ts @@ -6,6 +6,7 @@ type _defineExpose = typeof defineExpose type _withDefaults = typeof withDefaults type _ref = typeof $ref +type _shallowRef = typeof $shallowRef type _computed = typeof $computed type _fromRefs = typeof $fromRefs type _raw = typeof $raw @@ -17,6 +18,7 @@ declare global { const withDefaults: _withDefaults const $ref: _ref + const $shallowRef: _shallowRef const $computed: _computed const $fromRefs: _fromRefs const $raw: _raw diff --git a/test-dts/refSugar.test-d.ts b/test-dts/refSugar.test-d.ts index 29d837091..4ea579b91 100644 --- a/test-dts/refSugar.test-d.ts +++ b/test-dts/refSugar.test-d.ts @@ -1,6 +1,7 @@ import { expectType, $ref, + $shallowRef, $computed, $fromRefs, $raw, @@ -14,6 +15,10 @@ expectType($ref(1)) expectType($ref(ref(1))) expectType<{ foo: number }>($ref({ foo: ref(1) })) +// $shallowRef +expectType($shallowRef(1)) +expectType<{ foo: Ref }>($shallowRef({ foo: ref(1) })) + // $computed expectType($computed(() => 1)) let b = $ref(1)