]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(sfc): (experimental) new ref sugar
authorEvan You <yyx990803@gmail.com>
Wed, 14 Jul 2021 19:35:34 +0000 (15:35 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 16 Jul 2021 18:30:49 +0000 (14:30 -0400)
packages/compiler-sfc/__tests__/__snapshots__/compileScriptRefSugar.spec.ts.snap
packages/compiler-sfc/__tests__/compileScriptRefSugar.spec.ts
packages/compiler-sfc/src/compileScript.ts

index 17b1c8edd345fe7299030b0fa9d919fcf55359ed..df09c5afe95e2b30663105d2511c36ee8e7fd479 100644 (file)
@@ -1,5 +1,59 @@
 // Jest Snapshot v1, https://goo.gl/fbAQLP
 
+exports[`<script setup> ref sugar $computed declaration 1`] = `
+"import { computed as _computed } from 'vue'
+
+export default {
+  setup(__props, { expose }) {
+  expose()
+
+    const a = _computed(() => 1)
+    
+return { a }
+}
+
+}"
+`;
+
+exports[`<script setup> ref sugar $raw 1`] = `
+"import { ref as _ref } from 'vue'
+
+export default {
+  setup(__props, { expose }) {
+  expose()
+
+    let a = _ref(1)
+    const b = (a)
+    const c = ({ a })
+    callExternal((a))
+    
+return { a, b, c }
+}
+
+}"
+`;
+
+exports[`<script setup> ref sugar $ref declarations 1`] = `
+"import { ref as _ref } from 'vue'
+
+export default {
+  setup(__props, { expose }) {
+  expose()
+
+    let foo = _ref()
+    let a = _ref(1)
+    let b = _ref({
+      count: 0
+    })
+    let c = () => {}
+    let d
+    
+return { foo, a, b, c, d }
+}
+
+}"
+`;
+
 exports[`<script setup> ref sugar accessing ref binding 1`] = `
 "import { ref as _ref } from 'vue'
 
@@ -7,7 +61,7 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const a = _ref(1)
+    let a = _ref(1)
     console.log(a.value)
     function get() {
       return a.value + 1
@@ -26,7 +80,7 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const n = _ref(1), [__a, __b = 1, ...__c] = useFoo()
+    let n = _ref(1), [__a, __b = 1, ...__c] = (useFoo())
 const a = _ref(__a);
 const b = _ref(__b);
 const c = _ref(__c);
@@ -38,35 +92,29 @@ return { n, a, b, c }
 }"
 `;
 
-exports[`<script setup> ref sugar convert ref declarations 1`] = `
-"import { ref as _ref } from 'vue'
+exports[`<script setup> ref sugar mixing $ref & $computed declarations 1`] = `
+"import { ref as _ref, computed as _computed } from 'vue'
 
 export default {
   setup(__props, { expose }) {
   expose()
 
-    const foo = _ref()
-    const a = _ref(1)
-    const b = _ref({
-      count: 0
-    })
-    let c = () => {}
-    let d
+    let a = _ref(1), b = _computed(() => a.value + 1)
     
-return { foo, a, b, c, d }
+return { a, b }
 }
 
 }"
 `;
 
-exports[`<script setup> ref sugar multi ref declarations 1`] = `
+exports[`<script setup> ref sugar multi $ref declarations 1`] = `
 "import { ref as _ref } from 'vue'
 
 export default {
   setup(__props, { expose }) {
   expose()
 
-    const a = _ref(1), b = _ref(2), c = _ref({
+    let a = _ref(1), b = _ref(2), c = _ref({
       count: 0
     })
     
@@ -83,8 +131,8 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const a = _ref(1)
-    const b = _ref({ count: 0 })
+    let a = _ref(1)
+    let b = _ref({ count: 0 })
     function inc() {
       a.value++
       a.value = a.value + 1
@@ -107,9 +155,9 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const [{ a: { b: __b }}] = useFoo()
+    let [{ a: { b: __b }}] = (useFoo())
 const b = _ref(__b);
-    const { c: [__d, __e] } = useBar()
+    let { c: [__d, __e] } = (useBar())
 const d = _ref(__d);
 const e = _ref(__e);
     console.log(b.value, d.value, e.value)
@@ -127,13 +175,13 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const n = _ref(1), { a: __a, b: __c, d: __d = 1, e: __f = 2, ...__g } = useFoo()
+    let n = _ref(1), { a: __a, b: __c, d: __d = 1, e: __f = 2, ...__g } = (useFoo())
 const a = _ref(__a);
 const c = _ref(__c);
 const d = _ref(__d);
 const f = _ref(__f);
 const g = _ref(__g);
-    const { foo: __foo } = useSomthing(() => 1);
+    let { foo: __foo } = (useSomthing(() => 1));
 const foo = _ref(__foo);
     console.log(n.value, a.value, c.value, d.value, f.value, g.value, foo.value)
     
@@ -143,21 +191,6 @@ return { n, a, c, d, f, g, foo }
 }"
 `;
 
-exports[`<script setup> ref sugar should not convert non ref labels 1`] = `
-"export default {
-  setup(__props, { expose }) {
-  expose()
-
-    foo: a = 1, b = 2, c = {
-      count: 0
-    }
-    
-return {  }
-}
-
-}"
-`;
-
 exports[`<script setup> ref sugar should not rewrite scope variable 1`] = `
 "import { ref as _ref } from 'vue'
 
@@ -165,9 +198,9 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-      const a = _ref(1)
-      const b = _ref(1)
-      const d = _ref(1)
+      let a = _ref(1)
+      let b = _ref(1)
+      let d = _ref(1)
       const e = 1
       function test() {
         const a = 2
@@ -175,8 +208,6 @@ export default {
         console.log(b.value)
         let c = { c: 3 }
         console.log(c)
-        let $d
-        console.log($d)
         console.log(d.value)
         console.log(e)
       }
@@ -200,7 +231,7 @@ export default _defineComponent({
 
 const props = __props
         
-        const ids = _ref([])
+        let ids = _ref([])
       
 return { props, ids }
 }
@@ -215,7 +246,7 @@ export default {
   setup(__props, { expose }) {
   expose()
 
-    const a = _ref(1)
+    let a = _ref(1)
     const b = { a: a.value }
     function test() {
       const { a } = b
index 46935beb25f4264d8ea72b3ca6da1c2aa44533ec..a5267115088c9bdc33d331132a75d021fada5198 100644 (file)
@@ -6,24 +6,24 @@ describe('<script setup> ref sugar', () => {
     return compile(src, { refSugar: true })
   }
 
-  test('convert ref declarations', () => {
+  test('$ref declarations', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
-    ref: foo
-    ref: a = 1
-    ref: b = {
+    let foo = $ref()
+    let a = $ref(1)
+    let b = $ref({
       count: 0
-    }
+    })
     let c = () => {}
     let d
     </script>`)
     expect(content).toMatch(`import { ref as _ref } from 'vue'`)
-    expect(content).not.toMatch(`ref: foo`)
-    expect(content).not.toMatch(`ref: a`)
-    expect(content).not.toMatch(`ref: b`)
-    expect(content).toMatch(`const foo = _ref()`)
-    expect(content).toMatch(`const a = _ref(1)`)
+    expect(content).not.toMatch(`$ref()`)
+    expect(content).not.toMatch(`$ref(1)`)
+    expect(content).not.toMatch(`$ref({`)
+    expect(content).toMatch(`let foo = _ref()`)
+    expect(content).toMatch(`let a = _ref(1)`)
     expect(content).toMatch(`
-    const b = _ref({
+    let b = _ref({
       count: 0
     })
     `)
@@ -40,14 +40,14 @@ describe('<script setup> ref sugar', () => {
     })
   })
 
-  test('multi ref declarations', () => {
+  test('multi $ref declarations', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
-    ref: a = 1, b = 2, c = {
+    let a = $ref(1), b = $ref(2), c = $ref({
       count: 0
-    }
+    })
     </script>`)
     expect(content).toMatch(`
-    const a = _ref(1), b = _ref(2), c = _ref({
+    let a = _ref(1), b = _ref(2), c = _ref({
       count: 0
     })
     `)
@@ -60,19 +60,38 @@ describe('<script setup> ref sugar', () => {
     })
   })
 
-  test('should not convert non ref labels', () => {
-    const { content } = compileWithRefSugar(`<script setup>
-    foo: a = 1, b = 2, c = {
-      count: 0
-    }
+  test('$computed declaration', () => {
+    const { content, bindings } = compileWithRefSugar(`<script setup>
+    const a = $computed(() => 1)
+    </script>`)
+    expect(content).toMatch(`
+    const a = _computed(() => 1)
+    `)
+    expect(content).toMatch(`return { a }`)
+    assertCode(content)
+    expect(bindings).toStrictEqual({
+      a: BindingTypes.SETUP_REF
+    })
+  })
+
+  test('mixing $ref & $computed declarations', () => {
+    const { content, bindings } = compileWithRefSugar(`<script setup>
+    let a = $ref(1), b = $computed(() => a + 1)
     </script>`)
-    expect(content).toMatch(`foo: a = 1, b = 2`)
+    expect(content).toMatch(`
+    let a = _ref(1), b = _computed(() => a.value + 1)
+    `)
+    expect(content).toMatch(`return { a, b }`)
     assertCode(content)
+    expect(bindings).toStrictEqual({
+      a: BindingTypes.SETUP_REF,
+      b: BindingTypes.SETUP_REF
+    })
   })
 
   test('accessing ref binding', () => {
     const { content } = compileWithRefSugar(`<script setup>
-    ref: a = 1
+    let a = $ref(1)
     console.log(a)
     function get() {
       return a + 1
@@ -85,7 +104,7 @@ describe('<script setup> ref sugar', () => {
 
   test('cases that should not append .value', () => {
     const { content } = compileWithRefSugar(`<script setup>
-    ref: a = 1
+    let a = $ref(1)
     console.log(b.a)
     function get(a) {
       return a + 1
@@ -96,8 +115,8 @@ describe('<script setup> ref sugar', () => {
 
   test('mutating ref binding', () => {
     const { content } = compileWithRefSugar(`<script setup>
-    ref: a = 1
-    ref: b = { count: 0 }
+    let a = $ref(1)
+    let b = $ref({ count: 0 })
     function inc() {
       a++
       a = a + 1
@@ -118,7 +137,7 @@ describe('<script setup> ref sugar', () => {
 
   test('using ref binding in property shorthand', () => {
     const { content } = compileWithRefSugar(`<script setup>
-    ref: a = 1
+    let a = $ref(1)
     const b = { a }
     function test() {
       const { a } = b
@@ -133,9 +152,9 @@ describe('<script setup> ref sugar', () => {
   test('should not rewrite scope variable', () => {
     const { content } = compileWithRefSugar(`
     <script setup>
-      ref: a = 1
-      ref: b = 1
-      ref: d = 1
+      let a = $ref(1)
+      let b = $ref(1)
+      let d = $ref(1)
       const e = 1
       function test() {
         const a = 2
@@ -143,8 +162,6 @@ describe('<script setup> ref sugar', () => {
         console.log(b)
         let c = { c: 3 }
         console.log(c)
-        let $d
-        console.log($d)
         console.log(d)
         console.log(e)
       }
@@ -152,7 +169,6 @@ describe('<script setup> ref sugar', () => {
     expect(content).toMatch('console.log(a)')
     expect(content).toMatch('console.log(b.value)')
     expect(content).toMatch('console.log(c)')
-    expect(content).toMatch('console.log($d)')
     expect(content).toMatch('console.log(d.value)')
     expect(content).toMatch('console.log(e)')
     assertCode(content)
@@ -160,14 +176,14 @@ describe('<script setup> ref sugar', () => {
 
   test('object destructure', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
-    ref: n = 1, ({ a, b: c, d = 1, e: f = 2, ...g } = useFoo())
-    ref: ({ foo } = useSomthing(() => 1));
+    let n = $ref(1), { a, b: c, d = 1, e: f = 2, ...g } = $fromRefs(useFoo())
+    let { foo } = $fromRefs(useSomthing(() => 1));
     console.log(n, a, c, d, f, g, foo)
     </script>`)
     expect(content).toMatch(
-      `const n = _ref(1), { a: __a, b: __c, d: __d = 1, e: __f = 2, ...__g } = useFoo()`
+      `let n = _ref(1), { a: __a, b: __c, d: __d = 1, e: __f = 2, ...__g } = (useFoo())`
     )
-    expect(content).toMatch(`const { foo: __foo } = useSomthing(() => 1)`)
+    expect(content).toMatch(`let { foo: __foo } = (useSomthing(() => 1))`)
     expect(content).toMatch(`\nconst a = _ref(__a);`)
     expect(content).not.toMatch(`\nconst b = _ref(__b);`)
     expect(content).toMatch(`\nconst c = _ref(__c);`)
@@ -194,11 +210,11 @@ describe('<script setup> ref sugar', () => {
 
   test('array destructure', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
-    ref: n = 1, [a, b = 1, ...c] = useFoo()
+    let n = $ref(1), [a, b = 1, ...c] = $fromRefs(useFoo())
     console.log(n, a, b, c)
     </script>`)
     expect(content).toMatch(
-      `const n = _ref(1), [__a, __b = 1, ...__c] = useFoo()`
+      `let n = _ref(1), [__a, __b = 1, ...__c] = (useFoo())`
     )
     expect(content).toMatch(`\nconst a = _ref(__a);`)
     expect(content).toMatch(`\nconst b = _ref(__b);`)
@@ -216,12 +232,12 @@ describe('<script setup> ref sugar', () => {
 
   test('nested destructure', () => {
     const { content, bindings } = compileWithRefSugar(`<script setup>
-    ref: [{ a: { b }}] = useFoo()
-    ref: ({ c: [d, e] } = useBar())
+    let [{ a: { b }}] = $fromRefs(useFoo())
+    let { c: [d, e] } = $fromRefs(useBar())
     console.log(b, d, e)
     </script>`)
-    expect(content).toMatch(`const [{ a: { b: __b }}] = useFoo()`)
-    expect(content).toMatch(`const { c: [__d, __e] } = useBar()`)
+    expect(content).toMatch(`let [{ a: { b: __b }}] = (useFoo())`)
+    expect(content).toMatch(`let { c: [__d, __e] } = (useBar())`)
     expect(content).not.toMatch(`\nconst a = _ref(__a);`)
     expect(content).not.toMatch(`\nconst c = _ref(__c);`)
     expect(content).toMatch(`\nconst b = _ref(__b);`)
@@ -236,13 +252,26 @@ describe('<script setup> ref sugar', () => {
     assertCode(content)
   })
 
+  test('$raw', () => {
+    const { content } = compileWithRefSugar(`<script setup>
+    let a = $ref(1)
+    const b = $raw(a)
+    const c = $raw({ a })
+    callExternal($raw(a))
+    </script>`)
+    expect(content).toMatch(`const b = (a)`)
+    expect(content).toMatch(`const c = ({ a })`)
+    expect(content).toMatch(`callExternal((a))`)
+    assertCode(content)
+  })
+
   //#4062
   test('should not rewrite type identifiers', () => {
     const { content } = compile(
       `
       <script setup lang="ts">
         const props = defineProps<{msg: string; ids?: string[]}>()
-        ref: ids = []
+        let ids = $ref([])
       </script>`,
       {
         refSugar: true
@@ -253,22 +282,44 @@ describe('<script setup> ref sugar', () => {
   })
 
   describe('errors', () => {
-    test('ref: non-assignment expressions', () => {
+    test('non-let $ref declaration', () => {
+      expect(() =>
+        compile(
+          `<script setup>
+        const a = $ref(1)
+        </script>`,
+          { refSugar: true }
+        )
+      ).toThrow(`$ref() bindings can only be declared with let`)
+    })
+
+    test('$ref w/ destructure', () => {
+      expect(() =>
+        compile(
+          `<script setup>
+        let { a } = $ref(1)
+        </script>`,
+          { refSugar: true }
+        )
+      ).toThrow(`$ref() bindings cannot be used with destructuring`)
+    })
+
+    test('$computed w/ destructure', () => {
       expect(() =>
         compile(
           `<script setup>
-        ref: a = 1, foo()
+        const { a } = $computed(() => 1)
         </script>`,
           { refSugar: true }
         )
-      ).toThrow(`ref: statements can only contain assignment expressions`)
+      ).toThrow(`$computed() bindings cannot be used with destructuring`)
     })
 
     test('defineProps/Emit() referencing ref declarations', () => {
       expect(() =>
         compile(
           `<script setup>
-        ref: bar = 1
+        let bar = $ref(1)
         defineProps({
           bar
         })
@@ -280,7 +331,7 @@ describe('<script setup> ref sugar', () => {
       expect(() =>
         compile(
           `<script setup>
-        ref: bar = 1
+        let bar = $ref(1)
         defineEmits({
           bar
         })
index 175068d1c49b5578232f87732fb849bc50221952..7da9334ebb374162538613a693c1728c0061f78e 100644 (file)
@@ -28,12 +28,12 @@ import {
   ObjectProperty,
   ArrayExpression,
   Statement,
-  Expression,
-  LabeledStatement,
   CallExpression,
   RestElement,
   TSInterfaceBody,
-  AwaitExpression
+  AwaitExpression,
+  VariableDeclarator,
+  VariableDeclaration
 } from '@babel/types'
 import { walk } from 'estree-walker'
 import { RawSourceMap } from 'source-map'
@@ -46,11 +46,17 @@ import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
 import { warnExperimental, warnOnce } from './warn'
 import { rewriteDefault } from './rewriteDefault'
 
+// Special compiler macros
 const DEFINE_PROPS = 'defineProps'
 const DEFINE_EMIT = 'defineEmit'
 const DEFINE_EXPOSE = 'defineExpose'
 const WITH_DEFAULTS = 'withDefaults'
 
+const $REF = `$ref`
+const $COMPUTED = `$computed`
+const $FROM_REFS = `$fromRefs`
+const $RAW = `$raw`
+
 // deprecated
 const DEFINE_EMITS = 'defineEmits'
 
@@ -288,7 +294,7 @@ export function compileScript(
     msg: string,
     node: Node,
     end: number = node.end! + startOffset
-  ) {
+  ): never {
     throw new Error(
       `[@vue/compiler-sfc] ${msg}\n\n${sfc.filename}\n${generateCodeFrame(
         source,
@@ -499,42 +505,67 @@ export function compileScript(
     )
   }
 
-  function processRefExpression(exp: Expression, statement: LabeledStatement) {
-    if (exp.type === 'AssignmentExpression') {
-      const { left, right } = exp
-      if (left.type === 'Identifier') {
-        registerRefBinding(left)
-        s.prependRight(right.start! + startOffset, `${helper('ref')}(`)
-        s.appendLeft(right.end! + startOffset, ')')
-      } else if (left.type === 'ObjectPattern') {
-        // remove wrapping parens
-        for (let i = left.start!; i > 0; i--) {
-          const char = source[i + startOffset]
-          if (char === '(') {
-            s.remove(i + startOffset, i + startOffset + 1)
-            break
-          }
-        }
-        for (let i = right.end!; i > 0; i++) {
-          const char = source[i + startOffset]
-          if (char === ')') {
-            s.remove(i + startOffset, i + startOffset + 1)
-            break
-          }
-        }
-        processRefObjectPattern(left, statement)
-      } else if (left.type === 'ArrayPattern') {
-        processRefArrayPattern(left, statement)
-      }
-    } else if (exp.type === 'SequenceExpression') {
-      // possible multiple declarations
-      // ref: x = 1, y = 2
-      exp.expressions.forEach(e => processRefExpression(e, statement))
-    } else if (exp.type === 'Identifier') {
-      registerRefBinding(exp)
-      s.appendLeft(exp.end! + startOffset, ` = ${helper('ref')}()`)
+  function isRefSugarCall(callee: string) {
+    return callee === $REF || callee === $COMPUTED || callee === $FROM_REFS
+  }
+
+  function processRefSugar(
+    decl: VariableDeclarator,
+    statement: VariableDeclaration
+  ) {
+    if (!isCallOf(decl.init, isRefSugarCall)) {
+      return
+    }
+
+    if (!enableRefSugar) {
+      error(
+        `ref sugar is an experimental proposal and must be explicitly ` +
+          `enabled via @vue/compiler-sfc options.`,
+        // TODO link to RFC details
+        decl.init
+      )
     } else {
-      error(`ref: statements can only contain assignment expressions.`, exp)
+      warnExperimental(`ref sugar`, 0 /* TODO */)
+    }
+
+    const callee = (decl.init.callee as Identifier).name
+    const start = decl.init.start! + startOffset
+    if (callee === $REF) {
+      if (statement.kind !== 'let') {
+        error(`${$REF}() bindings can only be declared with let.`, decl)
+      }
+      if (decl.id.type !== 'Identifier') {
+        error(
+          `${$REF}() 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'))
+    } else if (callee === $COMPUTED) {
+      if (decl.id.type !== 'Identifier') {
+        error(
+          `${$COMPUTED}() bindings cannot be used with destructuring.`,
+          decl.id
+        )
+      }
+      registerRefBinding(decl.id)
+      s.overwrite(start, start + $COMPUTED.length, helper('computed'))
+    } else if (callee === $FROM_REFS) {
+      if (!decl.id.type.endsWith('Pattern')) {
+        error(
+          `${$FROM_REFS}() declaration must be used with destructure patterns.`,
+          decl
+        )
+      }
+      if (decl.id.type === 'ObjectPattern') {
+        processRefObjectPattern(decl.id, statement)
+      } else if (decl.id.type === 'ArrayPattern') {
+        processRefArrayPattern(decl.id, statement)
+      }
+      s.remove(start, start + callee.length)
     }
   }
 
@@ -551,7 +582,7 @@ export function compileScript(
 
   function processRefObjectPattern(
     pattern: ObjectPattern,
-    statement: LabeledStatement
+    statement: VariableDeclaration
   ) {
     for (const p of pattern.properties) {
       let nameId: Identifier | undefined
@@ -597,7 +628,7 @@ export function compileScript(
 
   function processRefArrayPattern(
     pattern: ArrayPattern,
-    statement: LabeledStatement
+    statement: VariableDeclaration
   ) {
     for (const e of pattern.elements) {
       if (!e) continue
@@ -795,29 +826,18 @@ export function compileScript(
       end++
     }
 
-    // process `ref: x` bindings (convert to refs)
+    // (Dropped) `ref: x` bindings
     if (
       node.type === 'LabeledStatement' &&
       node.label.name === 'ref' &&
       node.body.type === 'ExpressionStatement'
     ) {
-      if (enableRefSugar) {
-        !parseOnly && warnExperimental(`ref: sugar`, 228)
-        s.overwrite(
-          node.label.start! + startOffset,
-          node.body.start! + startOffset,
-          'const '
-        )
-        processRefExpression(node.body.expression, node)
-      } else {
-        error(
-          `ref: sugar now needs to be explicitly enabled via @vitejs/plugin-vue ` +
-            `or vue-loader options:\n` +
-            `- @vitejs/plugin-vue: via \`script.refSugar\`\n` +
-            `- vue-loader: via \`refSugar\` (requires 16.3.0+)`,
-          node
-        )
-      }
+      error(
+        `ref sugar using the label syntax was an experimental proposal and ` +
+          `has been dropped based on community feedback.`,
+        // TODO + ` Please check out the adjusted proposal at ...`,
+        node
+      )
     }
 
     if (node.type === 'ImportDeclaration') {
@@ -909,6 +929,7 @@ export function compileScript(
       for (let i = 0; i < total; i++) {
         const decl = node.declarations[i]
         if (decl.init) {
+          // defineProps / defineEmits
           const isDefineProps =
             processDefineProps(decl.init) || processWithDefaults(decl.init)
           if (isDefineProps) {
@@ -924,7 +945,7 @@ export function compileScript(
               decl.id.end!
             )
           }
-          if (isDefineProps || isDefineEmits)
+          if (isDefineProps || isDefineEmits) {
             if (left === 1) {
               s.remove(node.start! + startOffset, node.end! + startOffset)
             } else {
@@ -940,6 +961,9 @@ export function compileScript(
               s.remove(start, end)
               left--
             }
+          } else {
+            processRefSugar(decl, node)
+          }
         }
       }
     }
@@ -1046,28 +1070,37 @@ export function compileScript(
   // 3. Do a full walk to rewrite identifiers referencing let exports with ref
   // value access
   if (enableRefSugar && Object.keys(refBindings).length) {
+    const onIdent = (id: Identifier, parent: Node, parentStack: Node[]) => {
+      if (refBindings[id.name] && !refIdentifiers.has(id)) {
+        if (isStaticProperty(parent) && parent.shorthand) {
+          // let binding used in a property shorthand
+          // { foo } -> { foo: foo.value }
+          // skip for destructure patterns
+          if (
+            !(parent as any).inPattern ||
+            isInDestructureAssignment(parent, parentStack)
+          ) {
+            s.appendLeft(id.end! + startOffset, `: ${id.name}.value`)
+          }
+        } else {
+          s.appendLeft(id.end! + startOffset, '.value')
+        }
+      }
+    }
+
+    const onNode = (node: Node) => {
+      if (isCallOf(node, $RAW)) {
+        s.remove(
+          node.callee.start! + startOffset,
+          node.callee.end! + startOffset
+        )
+        return false // skip walk
+      }
+    }
+
     for (const node of scriptSetupAst) {
       if (node.type !== 'ImportDeclaration') {
-        walkIdentifiers(node, (id, parent, parentStack) => {
-          if (refBindings[id.name] && !refIdentifiers.has(id)) {
-            if (isStaticProperty(parent) && parent.shorthand) {
-              // let binding used in a property shorthand
-              // { foo } -> { foo: foo.value }
-              // skip for destructure patterns
-              if (
-                !(parent as any).inPattern ||
-                isInDestructureAssignment(parent, parentStack)
-              ) {
-                s.appendLeft(id.end! + startOffset, `: ${id.name}.value`)
-              }
-            } else {
-              s.appendLeft(id.end! + startOffset, '.value')
-            }
-          } else if (id.name[0] === '$' && refBindings[id.name.slice(1)]) {
-            // $xxx raw ref access variables, remove the $ prefix
-            s.remove(id.start! + startOffset, id.start! + startOffset + 1)
-          }
-        })
+        walkIdentifiers(node, onIdent, onNode)
       }
     }
   }
@@ -1129,6 +1162,10 @@ export function compileScript(
   for (const key in setupBindings) {
     bindingMetadata[key] = setupBindings[key].type
   }
+  // known ref bindings
+  for (const key in refBindings) {
+    bindingMetadata[key] = BindingTypes.SETUP_REF
+  }
 
   // 8. inject `useCssVars` calls
   if (cssVars.length) {
@@ -1714,7 +1751,8 @@ function markScopeIdentifier(
  */
 export function walkIdentifiers(
   root: Node,
-  onIdentifier: (node: Identifier, parent: Node, parentStack: Node[]) => void
+  onIdentifier: (node: Identifier, parent: Node, parentStack: Node[]) => void,
+  onNode?: (node: Node, parent: Node, parentStack: Node[]) => void | boolean
 ) {
   const parentStack: Node[] = []
   const knownIds: Record<string, number> = Object.create(null)
@@ -1724,6 +1762,9 @@ export function walkIdentifiers(
       if (node.type.startsWith('TS')) {
         return this.skip()
       }
+      if (onNode && onNode(node, parent!, parentStack) === false) {
+        return this.skip()
+      }
       if (node.type === 'Identifier') {
         if (
           !knownIds[node.name] &&