Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(complier-sfc): add hoistStatic for <script setup> #5752

Merged
merged 1 commit into from
Mar 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/compiler-core/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ export const enum BindingTypes {
/**
* declared by other options, e.g. computed, inject
*/
OPTIONS = 'options'
OPTIONS = 'options',
/**
* a literal constant, e.g. 'foo', 1, true
*/
LITERAL_CONST = 'literal-const'
}

export type BindingMetadata = {
Expand Down
3 changes: 2 additions & 1 deletion packages/compiler-core/src/transforms/transformElement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,8 @@ function resolveSetupReference(name: string, context: TransformContext) {

const fromConst =
checkType(BindingTypes.SETUP_CONST) ||
checkType(BindingTypes.SETUP_REACTIVE_CONST)
checkType(BindingTypes.SETUP_REACTIVE_CONST) ||
checkType(BindingTypes.LITERAL_CONST)
if (fromConst) {
return context.inline
? // in inline mode, const setup bindings (e.g. imports) can be used as-is
Expand Down
16 changes: 10 additions & 6 deletions packages/compiler-core/src/transforms/transformExpression.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,7 @@ export function processExpression(
const isDestructureAssignment =
parent && isInDestructureAssignment(parent, parentStack)

if (
type === BindingTypes.SETUP_CONST ||
type === BindingTypes.SETUP_REACTIVE_CONST ||
localVars[raw]
) {
if (isConst(type) || localVars[raw]) {
return raw
} else if (type === BindingTypes.SETUP_REF) {
return `${raw}.value`
Expand Down Expand Up @@ -223,7 +219,7 @@ export function processExpression(
if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) {
// const bindings exposed from setup can be skipped for patching but
// cannot be hoisted to module scope
if (bindingMetadata[node.content] === BindingTypes.SETUP_CONST) {
if (isConst(bindingMetadata[node.content])) {
node.constType = ConstantTypes.CAN_SKIP_PATCH
}
node.content = rewriteIdentifier(rawExp)
Expand Down Expand Up @@ -372,3 +368,11 @@ export function stringifyExpression(exp: ExpressionNode | string): string {
.join('')
}
}

function isConst(type: unknown) {
return (
type === BindingTypes.SETUP_CONST ||
type === BindingTypes.LITERAL_CONST ||
type === BindingTypes.SETUP_REACTIVE_CONST
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`SFC analyze <script> bindings > auto name inference > basic 1`] = `
"export default {
"const a = 1
export default {
__name: 'FooBar',
setup(__props, { expose }) {
expose();
const a = 1

return { a }
}

Expand Down Expand Up @@ -670,7 +671,9 @@ return { props, get x() { return x } }
`;

exports[`SFC compile <script setup> > defineProps() 1`] = `
"export default {
"const bar = 1

export default {
props: {
foo: String
},
Expand All @@ -680,7 +683,6 @@ exports[`SFC compile <script setup> > defineProps() 1`] = `
const props = __props;


const bar = 1

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

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

const a = 1
function b() {}

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

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

const cond = true

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

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

const fooBar: FooBar = 1

return { fooBar, get FooBaz() { return FooBaz }, get FooQux() { return FooQux }, get foo() { return foo } }
}
Expand Down Expand Up @@ -873,7 +875,9 @@ return { get bar() { return bar } }
`;

exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() referencing scope var 1`] = `
"export default {
"const bar = 1

export default {
props: {
foo: {
default: bar => bar + 1
Expand All @@ -885,7 +889,6 @@ exports[`SFC compile <script setup> > errors > should allow defineProps/Emit() r
setup(__props, { expose }) {
expose();

const bar = 1



Expand Down Expand Up @@ -1709,8 +1712,7 @@ return { Foo }

exports[`SFC compile <script setup> > with TypeScript > runtime Enum in normal script 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
enum Foo { A = 123 }


export enum D { D = \\"D\\" }
const enum C { C = \\"C\\" }
enum B { B = \\"B\\" }
Expand All @@ -1719,6 +1721,7 @@ export default /*#__PURE__*/_defineComponent({
setup(__props, { expose }) {
expose();

enum Foo { A = 123 }

return { D, C, B, Foo }
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Vitest Snapshot v1

exports[`sfc hoist static > should enable when only script setup 1`] = `
"const foo = 'bar'

export default {
setup(__props) {

const foo = 'bar'

return () => {}
}

}"
`;

exports[`sfc hoist static > should hoist expressions 1`] = `
"const unary = !false
const binary = 1 + 2
const conditional = 1 ? 2 : 3
const sequence = (1, true, 'foo', 1)

export default {
setup(__props) {


return () => {}
}

}"
`;

exports[`sfc hoist static > should hoist literal value 1`] = `
"const string = 'default value'
const number = 123
const boolean = false
const nil = null
const bigint = 100n
const template = \`str\`
const regex = /.*/g

export default {
setup(__props) {


return () => {}
}

}"
`;

exports[`sfc hoist static > should hoist w/ defineProps/Emits 1`] = `
"const defaultValue = 'default value'

export default {
props: {
foo: {
default: defaultValue
}
},
setup(__props) {



return () => {}
}

}"
`;

exports[`sfc hoist static > should not hoist a constant initialized to a reference value 1`] = `
"import { defineComponent as _defineComponent } from 'vue'

export default /*#__PURE__*/_defineComponent({
setup(__props) {

const KEY1 = Boolean
const KEY2 = [Boolean]
const KEY3 = [getCurrentInstance()]
let i = 0;
const KEY4 = (i++, 'foo')
enum KEY5 {
FOO = 1,
BAR = getCurrentInstance(),
}
const KEY6 = \`template\${i}\`

return () => {}
}

})"
`;

exports[`sfc hoist static > should not hoist a function or class 1`] = `
"export default {
setup(__props) {

const fn = () => {}
function fn2() {}
class Foo {}

return () => {}
}

}"
`;

exports[`sfc hoist static > should not hoist a object or array 1`] = `
"export default {
setup(__props) {

const obj = { foo: 'bar' }
const arr = [1, 2, 3]

return () => {}
}

}"
`;

exports[`sfc hoist static > should not hoist a variable 1`] = `
"export default {
setup(__props) {

let KEY1 = 'default value'
var KEY2 = 123

return () => {}
}

}"
`;
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ export default __default__"

exports[`CSS vars injection > codegen > should ignore comments 1`] = `
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'

const color = 'red';const width = 100
export default {
setup(__props, { expose }) {
expose();

_useCssVars(_ctx => ({
\\"xxxxxxxx-width\\": (width)
}))
const color = 'red';const width = 100

return { color, width }
}

Expand Down Expand Up @@ -92,15 +92,15 @@ return { get a() { return a }, set a(v) { a = v }, get b() { return b }, set b(v

exports[`CSS vars injection > codegen > w/ <script setup> 1`] = `
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'

const color = 'red'
export default {
setup(__props, { expose }) {
expose();

_useCssVars(_ctx => ({
\\"xxxxxxxx-color\\": (color)
}))
const color = 'red'

return { color }
}

Expand All @@ -109,7 +109,8 @@ return { color }

exports[`CSS vars injection > codegen > w/ <script setup> using the same var multiple times 1`] = `
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'

const color = 'red'

export default {
setup(__props, { expose }) {
expose();
Expand All @@ -118,7 +119,6 @@ _useCssVars(_ctx => ({
\\"xxxxxxxx-color\\": (color)
}))

const color = 'red'

return { color }
}
Expand Down Expand Up @@ -146,6 +146,7 @@ export default __default__"
exports[`CSS vars injection > w/ <script setup> binding analysis 1`] = `
"import { useCssVars as _useCssVars, unref as _unref } from 'vue'
import { ref } from 'vue'
const color = 'red'

export default {
props: {
Expand All @@ -160,7 +161,6 @@ _useCssVars(_ctx => ({
\\"xxxxxxxx-foo\\": (__props.foo)
}))

const color = 'red'
const size = ref('10px')


Expand Down
Loading