Skip to content

Commit

Permalink
fix(ssr): capture scope declaration correctly (#6281)
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Dec 28, 2021
1 parent eb08ec5 commit 60ce7f9
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 36 deletions.
61 changes: 61 additions & 0 deletions packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts
Expand Up @@ -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()
"
`)
})
59 changes: 23 additions & 36 deletions packages/vite/src/node/ssr/ssrTransform.ts
Expand Up @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -266,33 +266,32 @@ 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)
}
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)
Expand All @@ -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
Expand Down Expand Up @@ -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[]) {
Expand Down Expand Up @@ -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(
Expand All @@ -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
}

0 comments on commit 60ce7f9

Please sign in to comment.