Skip to content

Commit

Permalink
fix(ssr): fix mistakenly overwriting destructure variables as import …
Browse files Browse the repository at this point in the history
…bindings (vitejs#2417)

fix vitejs#2409
  • Loading branch information
underfin committed Mar 15, 2021
1 parent e034ee2 commit 24c866f
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 16 deletions.
27 changes: 27 additions & 0 deletions packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,30 @@ test('sourcemap source', async () => {
(await ssrTransform(`export const a = 1`, null, 'input.js')).map.sources
).toStrictEqual(['input.js'])
})

test('overwrite bindings', async () => {
expect(
(
await ssrTransform(
`import { inject } from 'vue';` +
`const a = { inject }\n` +
`const b = { test: inject }\n` +
`function c() { const { test: inject } = { test: true }; console.log(inject) }\n` +
`const d = inject \n` +
`function f() { console.log(inject) }\n` +
`function e() { const { inject } = { inject: true } }\n`,
null,
null
)
).code
).toMatchInlineSnapshot(`
"const __vite_ssr_import_0__ = __vite_ssr_import__(\\"vue\\")
const a = { inject: __vite_ssr_import_0__.inject }
const b = { test: __vite_ssr_import_0__.inject }
function c() { const { test: inject } = { test: true }; console.log(inject) }
const d = __vite_ssr_import_0__.inject
function f() { console.log(__vite_ssr_import_0__.inject) }
function e() { const { inject } = { inject: true } }
"
`)
})
58 changes: 42 additions & 16 deletions packages/vite/src/node/ssr/ssrTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,23 @@ function walk(
const scope: Record<string, number> = Object.create(null)
const scopeMap = new WeakMap<_Node, Set<string>>()

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)
}

;(eswalk as any)(root, {
enter(node: Node, parent: Node | null) {
if (node.type === 'ImportDeclaration') {
Expand Down Expand Up @@ -261,28 +278,29 @@ function walk(
parent.right === child
)
) {
const { name } = child
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)
setScope(node, child.name)
}
}
})
)
} else if (node.type === 'Property' && parent!.type === 'ObjectPattern') {
// mark property in destructure pattern
;(node as any).inPattern = true
} else if (node.type === 'VariableDeclarator') {
const parentFunction = findParentFunction(parentStack)
if (parentFunction) {
if (node.id.type === 'ObjectPattern') {
node.id.properties.forEach((property) => {
if (property.type === 'RestElement') {
setScope(parentFunction, (property.argument as Identifier).name)
} else {
setScope(parentFunction, (property.value as Identifier).name)
}
})
} else {
setScope(parentFunction, (node.id as Identifier).name)
}
}
}
},

Expand Down Expand Up @@ -329,7 +347,7 @@ function isRefIdentifier(id: Identifier, parent: _Node, parentStack: _Node[]) {

// property key
// this also covers object destructure pattern
if (isStaticPropertyKey(id, parent)) {
if (isStaticPropertyKey(id, parent) || (parent as any).inPattern) {
return false
}

Expand Down Expand Up @@ -372,6 +390,14 @@ function isFunction(node: _Node): node is FunctionNode {
return /Function(?:Expression|Declaration)$|Method$/.test(node.type)
}

function findParentFunction(parentStack: _Node[]): FunctionNode | undefined {
for (const node of parentStack) {
if (isFunction(node)) {
return node
}
}
}

function isInDestructureAssignment(
parent: _Node,
parentStack: _Node[]
Expand Down

0 comments on commit 24c866f

Please sign in to comment.