Skip to content

Commit 4a00fdd

Browse files
authoredNov 8, 2022
fix(compiler-sfc): check import source during binding analysation (#6826)
fix #6825
1 parent fdc5902 commit 4a00fdd

File tree

2 files changed

+56
-13
lines changed

2 files changed

+56
-13
lines changed
 

‎packages/compiler-sfc/__tests__/compileScript.spec.ts

+36
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,42 @@ defineExpose({ foo: 123 })
356356
content.lastIndexOf(`import { x }`)
357357
)
358358
})
359+
360+
describe('import ref/reactive function from other place', () => {
361+
test('import directly', () => {
362+
const { bindings } = compile(`
363+
<script setup>
364+
import { ref, reactive } from './foo'
365+
366+
const foo = ref(1)
367+
const bar = reactive(1)
368+
</script>
369+
`)
370+
expect(bindings).toStrictEqual({
371+
ref: BindingTypes.SETUP_MAYBE_REF,
372+
reactive: BindingTypes.SETUP_MAYBE_REF,
373+
foo: BindingTypes.SETUP_MAYBE_REF,
374+
bar: BindingTypes.SETUP_MAYBE_REF
375+
})
376+
})
377+
378+
test('import w/ alias', () => {
379+
const { bindings } = compile(`
380+
<script setup>
381+
import { ref as _ref, reactive as _reactive } from './foo'
382+
383+
const foo = ref(1)
384+
const bar = reactive(1)
385+
</script>
386+
`)
387+
expect(bindings).toStrictEqual({
388+
_reactive: BindingTypes.SETUP_MAYBE_REF,
389+
_ref: BindingTypes.SETUP_MAYBE_REF,
390+
foo: BindingTypes.SETUP_REF,
391+
bar: BindingTypes.SETUP_REACTIVE_CONST
392+
})
393+
})
394+
})
359395
})
360396

361397
// in dev mode, declared bindings are returned as an object from setup()

‎packages/compiler-sfc/src/compileScript.ts

+20-13
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ export interface SFCScriptCompileOptions {
129129
export interface ImportBinding {
130130
isType: boolean
131131
imported: string
132+
local: string
132133
source: string
133134
isFromSetup: boolean
134135
isUsedInTemplate: boolean
@@ -272,7 +273,6 @@ export function compileScript(
272273
const bindingMetadata: BindingMetadata = {}
273274
const helperImports: Set<string> = new Set()
274275
const userImports: Record<string, ImportBinding> = Object.create(null)
275-
const userImportAlias: Record<string, string> = Object.create(null)
276276
const scriptBindings: Record<string, BindingTypes> = Object.create(null)
277277
const setupBindings: Record<string, BindingTypes> = Object.create(null)
278278

@@ -362,10 +362,6 @@ export function compileScript(
362362
isFromSetup: boolean,
363363
needTemplateUsageCheck: boolean
364364
) {
365-
if (source === 'vue' && imported) {
366-
userImportAlias[imported] = local
367-
}
368-
369365
// template usage check is only needed in non-inline mode, so we can skip
370366
// the work if inlineTemplate is true.
371367
let isUsedInTemplate = needTemplateUsageCheck
@@ -382,6 +378,7 @@ export function compileScript(
382378
userImports[local] = {
383379
isType,
384380
imported: imported || 'default',
381+
local,
385382
source,
386383
isFromSetup,
387384
isUsedInTemplate
@@ -990,7 +987,7 @@ export function compileScript(
990987
}
991988
}
992989
if (node.declaration) {
993-
walkDeclaration(node.declaration, scriptBindings, userImportAlias)
990+
walkDeclaration(node.declaration, scriptBindings, userImports)
994991
}
995992
} else if (
996993
(node.type === 'VariableDeclaration' ||
@@ -999,7 +996,7 @@ export function compileScript(
999996
node.type === 'TSEnumDeclaration') &&
1000997
!node.declare
1001998
) {
1002-
walkDeclaration(node, scriptBindings, userImportAlias)
999+
walkDeclaration(node, scriptBindings, userImports)
10031000
}
10041001
}
10051002

@@ -1199,7 +1196,7 @@ export function compileScript(
11991196
node.type === 'ClassDeclaration') &&
12001197
!node.declare
12011198
) {
1202-
walkDeclaration(node, setupBindings, userImportAlias)
1199+
walkDeclaration(node, setupBindings, userImports)
12031200
}
12041201

12051202
// walk statements & named exports / variable declarations for top level
@@ -1654,8 +1651,17 @@ function registerBinding(
16541651
function walkDeclaration(
16551652
node: Declaration,
16561653
bindings: Record<string, BindingTypes>,
1657-
userImportAlias: Record<string, string>
1654+
userImports: Record<string, ImportBinding>
16581655
) {
1656+
function getUserBinding(name: string) {
1657+
const binding = Object.values(userImports).find(
1658+
binding => binding.source === 'vue' && binding.imported === name
1659+
)
1660+
if (binding) return binding.local
1661+
else if (!userImports[name]) return name
1662+
return undefined
1663+
}
1664+
16591665
if (node.type === 'VariableDeclaration') {
16601666
const isConst = node.kind === 'const'
16611667
// export const foo = ...
@@ -1669,7 +1675,7 @@ function walkDeclaration(
16691675
)
16701676
if (id.type === 'Identifier') {
16711677
let bindingType
1672-
const userReactiveBinding = userImportAlias['reactive'] || 'reactive'
1678+
const userReactiveBinding = getUserBinding('reactive')
16731679
if (isCallOf(init, userReactiveBinding)) {
16741680
// treat reactive() calls as let since it's meant to be mutable
16751681
bindingType = isConst
@@ -1685,7 +1691,7 @@ function walkDeclaration(
16851691
? BindingTypes.SETUP_REACTIVE_CONST
16861692
: BindingTypes.SETUP_CONST
16871693
} else if (isConst) {
1688-
if (isCallOf(init, userImportAlias['ref'] || 'ref')) {
1694+
if (isCallOf(init, getUserBinding('ref'))) {
16891695
bindingType = BindingTypes.SETUP_REF
16901696
} else {
16911697
bindingType = BindingTypes.SETUP_MAYBE_REF
@@ -1982,10 +1988,11 @@ function genRuntimeEmits(emits: Set<string>) {
19821988

19831989
function isCallOf(
19841990
node: Node | null | undefined,
1985-
test: string | ((id: string) => boolean)
1991+
test: string | ((id: string) => boolean) | null | undefined
19861992
): node is CallExpression {
19871993
return !!(
19881994
node &&
1995+
test &&
19891996
node.type === 'CallExpression' &&
19901997
node.callee.type === 'Identifier' &&
19911998
(typeof test === 'string'
@@ -1994,7 +2001,7 @@ function isCallOf(
19942001
)
19952002
}
19962003

1997-
function canNeverBeRef(node: Node, userReactiveImport: string): boolean {
2004+
function canNeverBeRef(node: Node, userReactiveImport?: string): boolean {
19982005
if (isCallOf(node, userReactiveImport)) {
19992006
return true
20002007
}

0 commit comments

Comments
 (0)
Please sign in to comment.