Skip to content

Commit 33baff5

Browse files
authored
fix(ssr): hoist import statements to the top (vitejs#12274)
1 parent 2b2ba61 commit 33baff5

File tree

2 files changed

+50
-37
lines changed

2 files changed

+50
-37
lines changed

packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts

+42-31
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ test('export * from', async () => {
103103
),
104104
).toMatchInlineSnapshot(`
105105
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
106-
__vite_ssr_exportAll__(__vite_ssr_import_0__);
107106
const __vite_ssr_import_1__ = await __vite_ssr_import__(\\"react\\");
107+
__vite_ssr_exportAll__(__vite_ssr_import_0__);
108108
__vite_ssr_exportAll__(__vite_ssr_import_1__);"
109109
`)
110110
})
@@ -130,9 +130,20 @@ test('export then import minified', async () => {
130130
`export * from 'vue';import {createApp} from 'vue';`,
131131
),
132132
).toMatchInlineSnapshot(`
133-
"const __vite_ssr_import_1__ = await __vite_ssr_import__(\\"vue\\");
134-
__vite_ssr_exportAll__(__vite_ssr_import_1__);const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
135-
"
133+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
134+
const __vite_ssr_import_1__ = await __vite_ssr_import__(\\"vue\\");
135+
__vite_ssr_exportAll__(__vite_ssr_import_1__);"
136+
`)
137+
})
138+
139+
test('hoist import to top', async () => {
140+
expect(
141+
await ssrTransformSimpleCode(
142+
`path.resolve('server.js');import path from 'node:path';`,
143+
),
144+
).toMatchInlineSnapshot(`
145+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"node:path\\");
146+
__vite_ssr_import_0__.default.resolve('server.js');"
136147
`)
137148
})
138149

@@ -369,8 +380,8 @@ function c({ _ = bar() + foo() }) {}
369380
`,
370381
),
371382
).toMatchInlineSnapshot(`
372-
"
373-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
383+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
384+
374385
375386
const a = ({ _ = __vite_ssr_import_0__.foo() }) => {}
376387
function b({ _ = __vite_ssr_import_0__.bar() }) {}
@@ -391,8 +402,8 @@ const a = () => {
391402
`,
392403
),
393404
).toMatchInlineSnapshot(`
394-
"
395-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
405+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
406+
396407
397408
const a = () => {
398409
const { type: n = 'bar' } = {}
@@ -414,8 +425,8 @@ const foo = {}
414425
`,
415426
),
416427
).toMatchInlineSnapshot(`
417-
"
418-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
428+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
429+
419430
420431
const foo = {}
421432
@@ -457,8 +468,8 @@ objRest()
457468
`,
458469
),
459470
).toMatchInlineSnapshot(`
460-
"
461-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
471+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
472+
462473
463474
464475
function a() {
@@ -507,8 +518,8 @@ const obj = {
507518
`,
508519
),
509520
).toMatchInlineSnapshot(`
510-
"
511-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
521+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
522+
512523
513524
514525
const bar = 'bar'
@@ -539,8 +550,8 @@ class A {
539550
`,
540551
),
541552
).toMatchInlineSnapshot(`
542-
"
543-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
553+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
554+
544555
545556
546557
const add = __vite_ssr_import_0__.add;
@@ -571,8 +582,8 @@ class A {
571582
`,
572583
),
573584
).toMatchInlineSnapshot(`
574-
"
575-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
585+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\");
586+
576587
577588
578589
const bar = 'bar'
@@ -617,8 +628,8 @@ bbb()
617628
`,
618629
),
619630
).toMatchInlineSnapshot(`
620-
"
621-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
631+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"vue\\");
632+
622633
623634
624635
function foobar() {
@@ -662,15 +673,15 @@ test('jsx', async () => {
662673
const result = await transformWithEsbuild(code, id)
663674
expect(await ssrTransformSimpleCode(result.code, '/foo.jsx'))
664675
.toMatchInlineSnapshot(`
665-
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"react\\");
676+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"react\\");
677+
const __vite_ssr_import_1__ = await __vite_ssr_import__(\\"foo\\");
666678
667-
const __vite_ssr_import_1__ = await __vite_ssr_import__(\\"foo\\");
668679
669-
function Bar({ Slot: Slot2 = /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(__vite_ssr_import_1__.Foo, null) }) {
670-
return /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(__vite_ssr_import_0__.default.Fragment, null, /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(Slot2, null));
671-
}
672-
"
673-
`)
680+
function Bar({ Slot: Slot2 = /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(__vite_ssr_import_1__.Foo, null) }) {
681+
return /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(__vite_ssr_import_0__.default.Fragment, null, /* @__PURE__ */ __vite_ssr_import_0__.default.createElement(Slot2, null));
682+
}
683+
"
684+
`)
674685
})
675686

676687
test('continuous exports', async () => {
@@ -801,8 +812,8 @@ function test() {
801812
return [foo, bar]
802813
}`),
803814
).toMatchInlineSnapshot(`
804-
"
805-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foobar\\");
815+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foobar\\");
816+
806817
807818
function test() {
808819
if (true) {
@@ -828,8 +839,8 @@ function test() {
828839
return bar;
829840
}`),
830841
).toMatchInlineSnapshot(`
831-
"
832-
const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foobar\\");
842+
"const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foobar\\");
843+
833844
834845
function test() {
835846
[__vite_ssr_import_0__.foo];

packages/vite/src/node/ssr/ssrTransform.ts

+8-6
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,13 @@ async function ssrTransformScript(
9494
const idToImportMap = new Map<string, string>()
9595
const declaredConst = new Set<string>()
9696

97-
function defineImport(node: Node, source: string) {
97+
function defineImport(source: string) {
9898
deps.add(source)
9999
const importId = `__vite_ssr_import_${uid++}__`
100-
s.appendRight(
101-
node.start,
100+
// There will be an error if the module is called before it is imported,
101+
// so the module import statement is hoisted to the top
102+
s.appendLeft(
103+
0,
102104
`const ${importId} = await ${ssrImportKey}(${JSON.stringify(source)});\n`,
103105
)
104106
return importId
@@ -118,8 +120,8 @@ async function ssrTransformScript(
118120
// import { baz } from 'foo' --> baz -> __import_foo__.baz
119121
// import * as ok from 'foo' --> ok -> __import_foo__
120122
if (node.type === 'ImportDeclaration') {
123+
const importId = defineImport(node.source.value as string)
121124
s.remove(node.start, node.end)
122-
const importId = defineImport(node, node.source.value as string)
123125
for (const spec of node.specifiers) {
124126
if (spec.type === 'ImportSpecifier') {
125127
idToImportMap.set(
@@ -161,7 +163,7 @@ async function ssrTransformScript(
161163
s.remove(node.start, node.end)
162164
if (node.source) {
163165
// export { foo, bar } from './foo'
164-
const importId = defineImport(node, node.source.value as string)
166+
const importId = defineImport(node.source.value as string)
165167
for (const spec of node.specifiers) {
166168
defineExport(
167169
node.end,
@@ -210,7 +212,7 @@ async function ssrTransformScript(
210212
// export * from './foo'
211213
if (node.type === 'ExportAllDeclaration') {
212214
s.remove(node.start, node.end)
213-
const importId = defineImport(node, node.source.value as string)
215+
const importId = defineImport(node.source.value as string)
214216
if (node.exported) {
215217
defineExport(node.end, node.exported.name, `${importId}`)
216218
} else {

0 commit comments

Comments
 (0)