mirror of
https://github.com/vitejs/vite.git
synced 2024-11-22 07:09:05 +00:00
fix(ssr): capture scope declaration correctly (#6281)
This commit is contained in:
parent
eb08ec5a83
commit
60ce7f9a1d
@ -529,3 +529,64 @@ class A {
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
||||
test('delcare scope', async () => {
|
||||
expect(
|
||||
(
|
||||
await ssrTransform(
|
||||
`
|
||||
import { aaa, bbb, ccc, ddd } from 'vue'
|
||||
|
||||
function foobar() {
|
||||
ddd()
|
||||
|
||||
const aaa = () => {
|
||||
bbb(ccc)
|
||||
ddd()
|
||||
}
|
||||
const bbb = () => {
|
||||
console.log('hi')
|
||||
}
|
||||
const ccc = 1
|
||||
function ddd() {}
|
||||
|
||||
aaa()
|
||||
bbb()
|
||||
ccc()
|
||||
}
|
||||
|
||||
aaa()
|
||||
bbb()
|
||||
`,
|
||||
null,
|
||||
null
|
||||
)
|
||||
).code
|
||||
).toMatchInlineSnapshot(`
|
||||
"
|
||||
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
|
||||
|
||||
|
||||
function foobar() {
|
||||
ddd()
|
||||
|
||||
const aaa = () => {
|
||||
bbb(ccc)
|
||||
ddd()
|
||||
}
|
||||
const bbb = () => {
|
||||
console.log('hi')
|
||||
}
|
||||
const ccc = 1
|
||||
function ddd() {}
|
||||
|
||||
aaa()
|
||||
bbb()
|
||||
ccc()
|
||||
}
|
||||
|
||||
__vite_ssr_import_0__.aaa()
|
||||
__vite_ssr_import_0__.bbb()
|
||||
"
|
||||
`)
|
||||
})
|
||||
|
@ -180,7 +180,7 @@ export async function ssrTransform(
|
||||
// 3. convert references to import bindings & import.meta references
|
||||
walk(ast, {
|
||||
onIdentifier(id, parent, parentStack) {
|
||||
const grandparent = parentStack[parentStack.length - 2]
|
||||
const grandparent = parentStack[1]
|
||||
const binding = idToImportMap.get(id.name)
|
||||
if (!binding) {
|
||||
return
|
||||
@ -203,7 +203,7 @@ export async function ssrTransform(
|
||||
if (!declaredConst.has(id.name)) {
|
||||
declaredConst.add(id.name)
|
||||
// locate the top-most node containing the class declaration
|
||||
const topNode = parentStack[1]
|
||||
const topNode = parentStack[parentStack.length - 2]
|
||||
s.prependRight(topNode.start, `const ${id.name} = ${binding};\n`)
|
||||
}
|
||||
} else {
|
||||
@ -266,19 +266,14 @@ function walk(
|
||||
{ onIdentifier, onImportMeta, onDynamicImport }: Visitors
|
||||
) {
|
||||
const parentStack: Node[] = []
|
||||
const scope: Record<string, number> = Object.create(null)
|
||||
const scopeMap = new WeakMap<_Node, Set<string>>()
|
||||
const identifiers: [id: any, stack: Node[]][] = []
|
||||
|
||||
const setScope = (node: FunctionNode, name: string) => {
|
||||
let scopeIds = scopeMap.get(node)
|
||||
if (scopeIds && scopeIds.has(name)) {
|
||||
return
|
||||
}
|
||||
if (name in scope) {
|
||||
scope[name]++
|
||||
} else {
|
||||
scope[name] = 1
|
||||
}
|
||||
if (!scopeIds) {
|
||||
scopeIds = new Set()
|
||||
scopeMap.set(node, scopeIds)
|
||||
@ -286,13 +281,17 @@ function walk(
|
||||
scopeIds.add(name)
|
||||
}
|
||||
|
||||
function isInScope(name: string, parents: Node[]) {
|
||||
return parents.some((node) => node && scopeMap.get(node)?.has(name))
|
||||
}
|
||||
|
||||
;(eswalk as any)(root, {
|
||||
enter(node: Node, parent: Node | null) {
|
||||
if (node.type === 'ImportDeclaration') {
|
||||
return this.skip()
|
||||
}
|
||||
|
||||
parent && parentStack.push(parent)
|
||||
parent && parentStack.unshift(parent)
|
||||
|
||||
if (node.type === 'MetaProperty' && node.meta.name === 'import') {
|
||||
onImportMeta(node)
|
||||
@ -301,8 +300,12 @@ function walk(
|
||||
}
|
||||
|
||||
if (node.type === 'Identifier') {
|
||||
if (!scope[node.name] && isRefIdentifier(node, parent!, parentStack)) {
|
||||
onIdentifier(node, parent!, parentStack)
|
||||
if (
|
||||
!isInScope(node.name, parentStack) &&
|
||||
isRefIdentifier(node, parent!, parentStack)
|
||||
) {
|
||||
// record the identifier, for DFS -> BFS
|
||||
identifiers.push([node, parentStack.slice(0)])
|
||||
}
|
||||
} else if (isFunction(node)) {
|
||||
// If it is a function declaration, it could be shadowing an import
|
||||
@ -372,18 +375,15 @@ function walk(
|
||||
},
|
||||
|
||||
leave(node: Node, parent: Node | null) {
|
||||
parent && parentStack.pop()
|
||||
const scopeIds = scopeMap.get(node)
|
||||
if (scopeIds) {
|
||||
scopeIds.forEach((id: string) => {
|
||||
scope[id]--
|
||||
if (scope[id] === 0) {
|
||||
delete scope[id]
|
||||
}
|
||||
})
|
||||
}
|
||||
parent && parentStack.shift()
|
||||
}
|
||||
})
|
||||
|
||||
// emit the identifier events in BFS so the hoisted declarations
|
||||
// can be captured correctly
|
||||
identifiers.forEach(([node, stack]) => {
|
||||
if (!isInScope(node.name, stack)) onIdentifier(node, stack[0], stack)
|
||||
})
|
||||
}
|
||||
|
||||
function isRefIdentifier(id: Identifier, parent: _Node, parentStack: _Node[]) {
|
||||
@ -459,12 +459,7 @@ function isFunction(node: _Node): node is FunctionNode {
|
||||
}
|
||||
|
||||
function findParentFunction(parentStack: _Node[]): FunctionNode | undefined {
|
||||
for (let i = parentStack.length - 1; i >= 0; i--) {
|
||||
const node = parentStack[i]
|
||||
if (isFunction(node)) {
|
||||
return node
|
||||
}
|
||||
}
|
||||
return parentStack.find((i) => isFunction(i)) as FunctionNode
|
||||
}
|
||||
|
||||
function isInDestructuringAssignment(
|
||||
@ -475,15 +470,7 @@ function isInDestructuringAssignment(
|
||||
parent &&
|
||||
(parent.type === 'Property' || parent.type === 'ArrayPattern')
|
||||
) {
|
||||
let i = parentStack.length
|
||||
while (i--) {
|
||||
const p = parentStack[i]
|
||||
if (p.type === 'AssignmentExpression') {
|
||||
return true
|
||||
} else if (p.type !== 'Property' && !p.type.endsWith('Pattern')) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return parentStack.some((i) => i.type === 'AssignmentExpression')
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user