Skip to content

Commit 02081e0

Browse files
committed
feat(complier-sfc): add hoistStatic for script
1 parent 0fbc19f commit 02081e0

File tree

10 files changed

+464
-59
lines changed

10 files changed

+464
-59
lines changed

packages/compiler-core/src/options.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,11 @@ export const enum BindingTypes {
112112
/**
113113
* declared by other options, e.g. computed, inject
114114
*/
115-
OPTIONS = 'options'
115+
OPTIONS = 'options',
116+
/**
117+
* a literal constant, e.g. 'foo', 1, true
118+
*/
119+
LITERAL_CONST = 'literal-const'
116120
}
117121

118122
export type BindingMetadata = {

packages/compiler-core/src/transforms/transformElement.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ function resolveSetupReference(name: string, context: TransformContext) {
360360

361361
const fromConst =
362362
checkType(BindingTypes.SETUP_CONST) ||
363-
checkType(BindingTypes.SETUP_REACTIVE_CONST)
363+
checkType(BindingTypes.SETUP_REACTIVE_CONST) ||
364+
checkType(BindingTypes.LITERAL_CONST)
364365
if (fromConst) {
365366
return context.inline
366367
? // in inline mode, const setup bindings (e.g. imports) can be used as-is

packages/compiler-core/src/transforms/transformExpression.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,7 @@ export function processExpression(
128128
const isDestructureAssignment =
129129
parent && isInDestructureAssignment(parent, parentStack)
130130

131-
if (
132-
type === BindingTypes.SETUP_CONST ||
133-
type === BindingTypes.SETUP_REACTIVE_CONST ||
134-
localVars[raw]
135-
) {
131+
if (isConst(type) || localVars[raw]) {
136132
return raw
137133
} else if (type === BindingTypes.SETUP_REF) {
138134
return `${raw}.value`
@@ -223,7 +219,7 @@ export function processExpression(
223219
if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) {
224220
// const bindings exposed from setup can be skipped for patching but
225221
// cannot be hoisted to module scope
226-
if (bindingMetadata[node.content] === BindingTypes.SETUP_CONST) {
222+
if (isConst(bindingMetadata[node.content])) {
227223
node.constType = ConstantTypes.CAN_SKIP_PATCH
228224
}
229225
node.content = rewriteIdentifier(rawExp)
@@ -372,3 +368,11 @@ export function stringifyExpression(exp: ExpressionNode | string): string {
372368
.join('')
373369
}
374370
}
371+
372+
function isConst(type: unknown) {
373+
return (
374+
type === BindingTypes.SETUP_CONST ||
375+
type === BindingTypes.LITERAL_CONST ||
376+
type === BindingTypes.SETUP_REACTIVE_CONST
377+
)
378+
}

packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
// Vitest Snapshot v1
22

33
exports[`SFC analyze <script> bindings > auto name inference > basic 1`] = `
4-
"export default {
4+
"const a = 1
5+
export default {
56
__name: 'FooBar',
67
setup(__props, { expose }) {
78
expose();
8-
const a = 1
9+
910
return { a }
1011
}
1112

@@ -670,7 +671,9 @@ return { props, get x() { return x } }
670671
`;
671672

672673
exports[`SFC compile <script setup> > defineProps() 1`] = `
673-
"export default {
674+
"const bar = 1
675+
676+
export default {
674677
props: {
675678
foo: String
676679
},
@@ -680,7 +683,6 @@ exports[`SFC compile <script setup> > defineProps() 1`] = `
680683
const props = __props;
681684

682685

683-
const bar = 1
684686

685687
return { props, bar }
686688
}
@@ -742,12 +744,12 @@ return { a, props, emit }
742744
exports[`SFC compile <script setup> > dev mode import usage check > TS annotations 1`] = `
743745
"import { defineComponent as _defineComponent } from 'vue'
744746
import { Foo, Bar, Baz, Qux, Fred } from './x'
747+
const a = 1
745748

746749
export default /*#__PURE__*/_defineComponent({
747750
setup(__props, { expose }) {
748751
expose();
749752

750-
const a = 1
751753
function b() {}
752754

753755
return { a, b, get Baz() { return Baz } }
@@ -759,12 +761,12 @@ return { a, b, get Baz() { return Baz } }
759761
exports[`SFC compile <script setup> > dev mode import usage check > attribute expressions 1`] = `
760762
"import { defineComponent as _defineComponent } from 'vue'
761763
import { bar, baz } from './x'
764+
const cond = true
762765

763766
export default /*#__PURE__*/_defineComponent({
764767
setup(__props, { expose }) {
765768
expose();
766769

767-
const cond = true
768770

769771
return { cond, get bar() { return bar }, get baz() { return baz } }
770772
}
@@ -775,12 +777,12 @@ return { cond, get bar() { return bar }, get baz() { return baz } }
775777
exports[`SFC compile <script setup> > dev mode import usage check > components 1`] = `
776778
"import { defineComponent as _defineComponent } from 'vue'
777779
import { FooBar, FooBaz, FooQux, foo } from './x'
780+
const fooBar: FooBar = 1
778781

779782
export default /*#__PURE__*/_defineComponent({
780783
setup(__props, { expose }) {
781784
expose();
782785

783-
const fooBar: FooBar = 1
784786

785787
return { fooBar, get FooBaz() { return FooBaz }, get FooQux() { return FooQux }, get foo() { return foo } }
786788
}
@@ -873,7 +875,9 @@ return { get bar() { return bar } }
873875
`;
874876

875877
exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() referencing scope var 1`] = `
876-
"export default {
878+
"const bar = 1
879+
880+
export default {
877881
props: {
878882
foo: {
879883
default: bar => bar + 1
@@ -885,7 +889,6 @@ exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() r
885889
setup(__props, { expose }) {
886890
expose();
887891

888-
const bar = 1
889892

890893

891894

@@ -1691,8 +1694,7 @@ return { Foo }
16911694

16921695
exports[`SFC compile <script setup> > with TypeScript > runtime Enum in normal script 1`] = `
16931696
"import { defineComponent as _defineComponent } from 'vue'
1694-
enum Foo { A = 123 }
1695-
1697+
16961698
export enum D { D = \\"D\\" }
16971699
const enum C { C = \\"C\\" }
16981700
enum B { B = \\"B\\" }
@@ -1701,6 +1703,7 @@ export default /*#__PURE__*/_defineComponent({
17011703
setup(__props, { expose }) {
17021704
expose();
17031705

1706+
enum Foo { A = 123 }
17041707

17051708
return { D, C, B, Foo }
17061709
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`sfc hoist static should enable when only script setup 1`] = `
4+
"const foo = 'bar'
5+
6+
export default {
7+
setup(__props) {
8+
9+
const foo = 'bar'
10+
11+
return () => {}
12+
}
13+
14+
}"
15+
`;
16+
17+
exports[`sfc hoist static should hoist expressions 1`] = `
18+
"const unary = !false
19+
const binary = 1 + 2
20+
const conditional = 1 ? 2 : 3
21+
const sequence = (1, true, 'foo', 1)
22+
23+
export default {
24+
setup(__props) {
25+
26+
27+
return () => {}
28+
}
29+
30+
}"
31+
`;
32+
33+
exports[`sfc hoist static should hoist literal value 1`] = `
34+
"const string = 'default value'
35+
const number = 123
36+
const boolean = false
37+
const nil = null
38+
const bigint = 100n
39+
const template = \`str\`
40+
const regex = /.*/g
41+
42+
export default {
43+
setup(__props) {
44+
45+
46+
return () => {}
47+
}
48+
49+
}"
50+
`;
51+
52+
exports[`sfc hoist static should hoist w/ defineProps/Emits 1`] = `
53+
"const defaultValue = 'default value'
54+
55+
export default {
56+
props: {
57+
foo: {
58+
default: defaultValue
59+
}
60+
},
61+
setup(__props) {
62+
63+
64+
65+
return () => {}
66+
}
67+
68+
}"
69+
`;
70+
71+
exports[`sfc hoist static should not hoist a constant initialized to a reference value 1`] = `
72+
"import { defineComponent as _defineComponent } from 'vue'
73+
74+
export default /*#__PURE__*/_defineComponent({
75+
setup(__props) {
76+
77+
const KEY1 = Boolean
78+
const KEY2 = [Boolean]
79+
const KEY3 = [getCurrentInstance()]
80+
let i = 0;
81+
const KEY4 = (i++, 'foo')
82+
enum KEY5 {
83+
FOO = 1,
84+
BAR = getCurrentInstance(),
85+
}
86+
const KEY6 = \`template\${i}\`
87+
88+
return () => {}
89+
}
90+
91+
})"
92+
`;
93+
94+
exports[`sfc hoist static should not hoist a function or class 1`] = `
95+
"export default {
96+
setup(__props) {
97+
98+
const fn = () => {}
99+
function fn2() {}
100+
class Foo {}
101+
102+
return () => {}
103+
}
104+
105+
}"
106+
`;
107+
108+
exports[`sfc hoist static should not hoist a object or array 1`] = `
109+
"export default {
110+
setup(__props) {
111+
112+
const obj = { foo: 'bar' }
113+
const arr = [1, 2, 3]
114+
115+
return () => {}
116+
}
117+
118+
}"
119+
`;
120+
121+
exports[`sfc hoist static should not hoist a variable 1`] = `
122+
"export default {
123+
setup(__props) {
124+
125+
let KEY1 = 'default value'
126+
var KEY2 = 123
127+
128+
return () => {}
129+
}
130+
131+
}"
132+
`;

packages/compiler-sfc/__tests__/__snapshots__/cssVars.spec.ts.snap

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,15 @@ export default __default__"
5151
5252
exports[`CSS vars injection > codegen > should ignore comments 1`] = `
5353
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
54-
54+
const color = 'red';const width = 100
5555
export default {
5656
setup(__props, { expose }) {
5757
expose();
5858
5959
_useCssVars(_ctx => ({
6060
\\"xxxxxxxx-width\\": (width)
6161
}))
62-
const color = 'red';const width = 100
62+
6363
return { color, width }
6464
}
6565
@@ -92,15 +92,15 @@ return { get a() { return a }, set a(v) { a = v }, get b() { return b }, set b(v
9292
9393
exports[`CSS vars injection > codegen > w/ <script setup> 1`] = `
9494
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
95-
95+
const color = 'red'
9696
export default {
9797
setup(__props, { expose }) {
9898
expose();
9999
100100
_useCssVars(_ctx => ({
101101
\\"xxxxxxxx-color\\": (color)
102102
}))
103-
const color = 'red'
103+
104104
return { color }
105105
}
106106
@@ -109,7 +109,8 @@ return { color }
109109
110110
exports[`CSS vars injection > codegen > w/ <script setup> using the same var multiple times 1`] = `
111111
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
112-
112+
const color = 'red'
113+
113114
export default {
114115
setup(__props, { expose }) {
115116
expose();
@@ -118,7 +119,6 @@ _useCssVars(_ctx => ({
118119
\\"xxxxxxxx-color\\": (color)
119120
}))
120121
121-
const color = 'red'
122122
123123
return { color }
124124
}
@@ -146,6 +146,7 @@ export default __default__"
146146
exports[`CSS vars injection > w/ <script setup> binding analysis 1`] = `
147147
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
148148
import { ref } from 'vue'
149+
const color = 'red'
149150
150151
export default {
151152
props: {
@@ -160,7 +161,6 @@ _useCssVars(_ctx => ({
160161
\\"xxxxxxxx-foo\\": (__props.foo)
161162
}))
162163
163-
const color = 'red'
164164
const size = ref('10px')
165165
166166

0 commit comments

Comments
 (0)