From 24c866f0de4fddec45fd6aa757185d5e74d0e7f3 Mon Sep 17 00:00:00 2001 From: underfin Date: Mon, 15 Mar 2021 23:12:34 +0800 Subject: [PATCH] fix(ssr): fix mistakenly overwriting destructure variables as import bindings (#2417) fix #2409 --- .../node/ssr/__tests__/ssrTransform.spec.ts | 27 +++++++++ packages/vite/src/node/ssr/ssrTransform.ts | 58 ++++++++++++++----- 2 files changed, 69 insertions(+), 16 deletions(-) diff --git a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts index 11469609dc70e8..b20cf84bc36c49 100644 --- a/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts +++ b/packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts @@ -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 } } + " + `) +}) diff --git a/packages/vite/src/node/ssr/ssrTransform.ts b/packages/vite/src/node/ssr/ssrTransform.ts index a3b4179ff93cac..440d43eea47455 100644 --- a/packages/vite/src/node/ssr/ssrTransform.ts +++ b/packages/vite/src/node/ssr/ssrTransform.ts @@ -225,6 +225,23 @@ function walk( const scope: Record = Object.create(null) const scopeMap = new WeakMap<_Node, Set>() + 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') { @@ -261,21 +278,7 @@ 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) } } }) @@ -283,6 +286,21 @@ function walk( } 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) + } + } } }, @@ -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 } @@ -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[]