diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
index 6c358654..792de768 100644
--- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
+++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap
@@ -554,212 +554,6 @@ return () => {}
}"
`;
-exports[`SFC compile
- `)
+ `,
+ { refSugar: true }
+ )
assertCode(content)
expect(content).toMatch(`import { ref } from 'vue'`)
})
@@ -829,7 +832,9 @@ const emit = defineEmits(['a', 'b'])
expected: string | ((content: string) => boolean),
shouldAsync = true
) {
- const { content } = compile(``)
+ const { content } = compile(``, {
+ refSugar: true
+ })
expect(content).toMatch(`${shouldAsync ? `async ` : ``}setup(`)
if (typeof expected === 'string') {
expect(content).toMatch(expected)
@@ -893,238 +898,6 @@ const emit = defineEmits(['a', 'b'])
})
})
- describe('ref: syntax sugar', () => {
- test('convert ref declarations', () => {
- const { content, bindings } = compile(``)
- 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).toMatch(`
- const b = _ref({
- count: 0
- })
- `)
- // normal declarations left untouched
- expect(content).toMatch(`let c = () => {}`)
- expect(content).toMatch(`let d`)
- assertCode(content)
- expect(bindings).toStrictEqual({
- foo: BindingTypes.SETUP_REF,
- a: BindingTypes.SETUP_REF,
- b: BindingTypes.SETUP_REF,
- c: BindingTypes.SETUP_LET,
- d: BindingTypes.SETUP_LET
- })
- })
-
- test('multi ref declarations', () => {
- const { content, bindings } = compile(``)
- expect(content).toMatch(`
- const a = _ref(1), b = _ref(2), c = _ref({
- count: 0
- })
- `)
- expect(content).toMatch(`return { a, b, c }`)
- assertCode(content)
- expect(bindings).toStrictEqual({
- a: BindingTypes.SETUP_REF,
- b: BindingTypes.SETUP_REF,
- c: BindingTypes.SETUP_REF
- })
- })
-
- test('should not convert non ref labels', () => {
- const { content } = compile(``)
- expect(content).toMatch(`foo: a = 1, b = 2`)
- assertCode(content)
- })
-
- test('accessing ref binding', () => {
- const { content } = compile(``)
- expect(content).toMatch(`console.log(a.value)`)
- expect(content).toMatch(`return a.value + 1`)
- assertCode(content)
- })
-
- test('cases that should not append .value', () => {
- const { content } = compile(``)
- expect(content).not.toMatch(`a.value`)
- })
-
- test('mutating ref binding', () => {
- const { content } = compile(``)
- expect(content).toMatch(`a.value++`)
- expect(content).toMatch(`a.value = a.value + 1`)
- expect(content).toMatch(`b.value.count++`)
- expect(content).toMatch(`b.value.count = b.value.count + 1`)
- expect(content).toMatch(`;({ a: a.value } = { a: 2 })`)
- expect(content).toMatch(`;[a.value] = [1]`)
- assertCode(content)
- })
-
- test('using ref binding in property shorthand', () => {
- const { content } = compile(``)
- expect(content).toMatch(`const b = { a: a.value }`)
- // should not convert destructure
- expect(content).toMatch(`const { a } = b`)
- assertCode(content)
- })
-
- test('should not rewrite scope variable', () => {
- const { content } = compile(`
- `)
- 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)
- })
-
- test('object destructure', () => {
- const { content, bindings } = compile(``)
- expect(content).toMatch(
- `const 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(`\nconst a = _ref(__a);`)
- expect(content).not.toMatch(`\nconst b = _ref(__b);`)
- expect(content).toMatch(`\nconst c = _ref(__c);`)
- expect(content).toMatch(`\nconst d = _ref(__d);`)
- expect(content).not.toMatch(`\nconst e = _ref(__e);`)
- expect(content).toMatch(`\nconst f = _ref(__f);`)
- expect(content).toMatch(`\nconst g = _ref(__g);`)
- expect(content).toMatch(`\nconst foo = _ref(__foo);`)
- expect(content).toMatch(
- `console.log(n.value, a.value, c.value, d.value, f.value, g.value, foo.value)`
- )
- expect(content).toMatch(`return { n, a, c, d, f, g, foo }`)
- expect(bindings).toStrictEqual({
- n: BindingTypes.SETUP_REF,
- a: BindingTypes.SETUP_REF,
- c: BindingTypes.SETUP_REF,
- d: BindingTypes.SETUP_REF,
- f: BindingTypes.SETUP_REF,
- g: BindingTypes.SETUP_REF,
- foo: BindingTypes.SETUP_REF
- })
- assertCode(content)
- })
-
- test('array destructure', () => {
- const { content, bindings } = compile(``)
- expect(content).toMatch(
- `const n = _ref(1), [__a, __b = 1, ...__c] = useFoo()`
- )
- expect(content).toMatch(`\nconst a = _ref(__a);`)
- expect(content).toMatch(`\nconst b = _ref(__b);`)
- expect(content).toMatch(`\nconst c = _ref(__c);`)
- expect(content).toMatch(`console.log(n.value, a.value, b.value, c.value)`)
- expect(content).toMatch(`return { n, a, b, c }`)
- expect(bindings).toStrictEqual({
- n: BindingTypes.SETUP_REF,
- a: BindingTypes.SETUP_REF,
- b: BindingTypes.SETUP_REF,
- c: BindingTypes.SETUP_REF
- })
- assertCode(content)
- })
-
- test('nested destructure', () => {
- const { content, bindings } = compile(``)
- expect(content).toMatch(`const [{ a: { b: __b }}] = useFoo()`)
- expect(content).toMatch(`const { 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);`)
- expect(content).toMatch(`\nconst d = _ref(__d);`)
- expect(content).toMatch(`\nconst e = _ref(__e);`)
- expect(content).toMatch(`return { b, d, e }`)
- expect(bindings).toStrictEqual({
- b: BindingTypes.SETUP_REF,
- d: BindingTypes.SETUP_REF,
- e: BindingTypes.SETUP_REF
- })
- assertCode(content)
- })
- })
-
describe('errors', () => {
test('`)
- ).toThrow(`ref: statements can only contain assignment expressions`)
- })
-
test('defineProps/Emit() w/ both type and non-type args', () => {
expect(() => {
compile(``)
- ).toThrow(`cannot reference locally declared variables`)
-
- expect(() =>
- compile(``)
- ).toThrow(`cannot reference locally declared variables`)
- })
-
test('should allow defineProps/Emit() referencing scope var', () => {
assertCode(
compile(``)
+ 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).toMatch(`
+ const b = _ref({
+ count: 0
+ })
+ `)
+ // normal declarations left untouched
+ expect(content).toMatch(`let c = () => {}`)
+ expect(content).toMatch(`let d`)
+ assertCode(content)
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.SETUP_REF,
+ a: BindingTypes.SETUP_REF,
+ b: BindingTypes.SETUP_REF,
+ c: BindingTypes.SETUP_LET,
+ d: BindingTypes.SETUP_LET
+ })
+ })
+
+ test('multi ref declarations', () => {
+ const { content, bindings } = compileWithRefSugar(``)
+ expect(content).toMatch(`
+ const a = _ref(1), b = _ref(2), c = _ref({
+ count: 0
+ })
+ `)
+ expect(content).toMatch(`return { a, b, c }`)
+ assertCode(content)
+ expect(bindings).toStrictEqual({
+ a: BindingTypes.SETUP_REF,
+ b: BindingTypes.SETUP_REF,
+ c: BindingTypes.SETUP_REF
+ })
+ })
+
+ test('should not convert non ref labels', () => {
+ const { content } = compileWithRefSugar(``)
+ expect(content).toMatch(`foo: a = 1, b = 2`)
+ assertCode(content)
+ })
+
+ test('accessing ref binding', () => {
+ const { content } = compileWithRefSugar(``)
+ expect(content).toMatch(`console.log(a.value)`)
+ expect(content).toMatch(`return a.value + 1`)
+ assertCode(content)
+ })
+
+ test('cases that should not append .value', () => {
+ const { content } = compileWithRefSugar(``)
+ expect(content).not.toMatch(`a.value`)
+ })
+
+ test('mutating ref binding', () => {
+ const { content } = compileWithRefSugar(``)
+ expect(content).toMatch(`a.value++`)
+ expect(content).toMatch(`a.value = a.value + 1`)
+ expect(content).toMatch(`b.value.count++`)
+ expect(content).toMatch(`b.value.count = b.value.count + 1`)
+ expect(content).toMatch(`;({ a: a.value } = { a: 2 })`)
+ expect(content).toMatch(`;[a.value] = [1]`)
+ assertCode(content)
+ })
+
+ test('using ref binding in property shorthand', () => {
+ const { content } = compileWithRefSugar(``)
+ expect(content).toMatch(`const b = { a: a.value }`)
+ // should not convert destructure
+ expect(content).toMatch(`const { a } = b`)
+ assertCode(content)
+ })
+
+ test('should not rewrite scope variable', () => {
+ const { content } = compileWithRefSugar(`
+ `)
+ 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)
+ })
+
+ test('object destructure', () => {
+ const { content, bindings } = compileWithRefSugar(``)
+ expect(content).toMatch(
+ `const 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(`\nconst a = _ref(__a);`)
+ expect(content).not.toMatch(`\nconst b = _ref(__b);`)
+ expect(content).toMatch(`\nconst c = _ref(__c);`)
+ expect(content).toMatch(`\nconst d = _ref(__d);`)
+ expect(content).not.toMatch(`\nconst e = _ref(__e);`)
+ expect(content).toMatch(`\nconst f = _ref(__f);`)
+ expect(content).toMatch(`\nconst g = _ref(__g);`)
+ expect(content).toMatch(`\nconst foo = _ref(__foo);`)
+ expect(content).toMatch(
+ `console.log(n.value, a.value, c.value, d.value, f.value, g.value, foo.value)`
+ )
+ expect(content).toMatch(`return { n, a, c, d, f, g, foo }`)
+ expect(bindings).toStrictEqual({
+ n: BindingTypes.SETUP_REF,
+ a: BindingTypes.SETUP_REF,
+ c: BindingTypes.SETUP_REF,
+ d: BindingTypes.SETUP_REF,
+ f: BindingTypes.SETUP_REF,
+ g: BindingTypes.SETUP_REF,
+ foo: BindingTypes.SETUP_REF
+ })
+ assertCode(content)
+ })
+
+ test('array destructure', () => {
+ const { content, bindings } = compileWithRefSugar(``)
+ expect(content).toMatch(
+ `const n = _ref(1), [__a, __b = 1, ...__c] = useFoo()`
+ )
+ expect(content).toMatch(`\nconst a = _ref(__a);`)
+ expect(content).toMatch(`\nconst b = _ref(__b);`)
+ expect(content).toMatch(`\nconst c = _ref(__c);`)
+ expect(content).toMatch(`console.log(n.value, a.value, b.value, c.value)`)
+ expect(content).toMatch(`return { n, a, b, c }`)
+ expect(bindings).toStrictEqual({
+ n: BindingTypes.SETUP_REF,
+ a: BindingTypes.SETUP_REF,
+ b: BindingTypes.SETUP_REF,
+ c: BindingTypes.SETUP_REF
+ })
+ assertCode(content)
+ })
+
+ test('nested destructure', () => {
+ const { content, bindings } = compileWithRefSugar(``)
+ expect(content).toMatch(`const [{ a: { b: __b }}] = useFoo()`)
+ expect(content).toMatch(`const { 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);`)
+ expect(content).toMatch(`\nconst d = _ref(__d);`)
+ expect(content).toMatch(`\nconst e = _ref(__e);`)
+ expect(content).toMatch(`return { b, d, e }`)
+ expect(bindings).toStrictEqual({
+ b: BindingTypes.SETUP_REF,
+ d: BindingTypes.SETUP_REF,
+ e: BindingTypes.SETUP_REF
+ })
+ assertCode(content)
+ })
+
+ describe('errors', () => {
+ test('ref: non-assignment expressions', () => {
+ expect(() =>
+ compile(
+ ``,
+ { refSugar: true }
+ )
+ ).toThrow(`ref: statements can only contain assignment expressions`)
+ })
+
+ test('defineProps/Emit() referencing ref declarations', () => {
+ expect(() =>
+ compile(
+ ``,
+ { refSugar: true }
+ )
+ ).toThrow(`cannot reference locally declared variables`)
+
+ expect(() =>
+ compile(
+ ``,
+ { refSugar: true }
+ )
+ ).toThrow(`cannot reference locally declared variables`)
+ })
+ })
+})
diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts
index 9347e996..d8873610 100644
--- a/packages/compiler-sfc/src/compileScript.ts
+++ b/packages/compiler-sfc/src/compileScript.ts
@@ -189,7 +189,7 @@ export function compileScript(
const setupBindings: Record = Object.create(null)
const refBindings: Record = Object.create(null)
const refIdentifiers: Set = new Set()
- const enableRefSugar = options.refSugar !== false
+ const enableRefSugar = !!options.refSugar
let defaultExport: Node | undefined
let hasDefinePropsCall = false
let hasDefineEmitCall = false
@@ -732,10 +732,11 @@ export function compileScript(
)
processRefExpression(node.body.expression, node)
} else {
- // TODO if we end up shipping ref: sugar as an opt-in feature,
- // need to proxy the option in vite, vue-loader and rollup-plugin-vue.
error(
- `ref: sugar needs to be explicitly enabled via vite or vue-loader options.`,
+ `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
)
}