Skip to content

Commit ed29dee

Browse files
authored
fix(ssr): fix execution order of re-export (#19841)
1 parent 3db608a commit ed29dee

File tree

11 files changed

+98
-24
lines changed

11 files changed

+98
-24
lines changed

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

+10-10
Original file line numberDiff line numberDiff line change
@@ -234,8 +234,8 @@ test('export then import minified', async () => {
234234
`export * from 'vue';import {createApp} from 'vue';`,
235235
),
236236
).toMatchInlineSnapshot(`
237-
"const __vite_ssr_import_0__ = await __vite_ssr_import__("vue", {"importedNames":["createApp"]});const __vite_ssr_import_1__ = await __vite_ssr_import__("vue");__vite_ssr_exportAll__(__vite_ssr_import_1__);
238-
"
237+
"const __vite_ssr_import_0__ = await __vite_ssr_import__("vue");__vite_ssr_exportAll__(__vite_ssr_import_0__);
238+
const __vite_ssr_import_1__ = await __vite_ssr_import__("vue", {"importedNames":["createApp"]});"
239239
`)
240240
})
241241

@@ -1264,14 +1264,14 @@ export * from './b'
12641264
console.log(foo + 2)
12651265
`),
12661266
).toMatchInlineSnapshot(`
1267-
"const __vite_ssr_import_0__ = await __vite_ssr_import__("./foo", {"importedNames":["foo"]});
1268-
console.log(__vite_ssr_import_0__.foo + 1);
1269-
const __vite_ssr_import_1__ = await __vite_ssr_import__("./a");__vite_ssr_exportAll__(__vite_ssr_import_1__);
1267+
"const __vite_ssr_import_0__ = await __vite_ssr_import__("./a");__vite_ssr_exportAll__(__vite_ssr_import_0__);
1268+
;const __vite_ssr_import_1__ = await __vite_ssr_import__("./foo", {"importedNames":["foo"]});const __vite_ssr_import_2__ = await __vite_ssr_import__("./b");__vite_ssr_exportAll__(__vite_ssr_import_2__);
12701269
;
1270+
console.log(__vite_ssr_import_1__.foo + 1);
12711271
1272-
const __vite_ssr_import_2__ = await __vite_ssr_import__("./b");__vite_ssr_exportAll__(__vite_ssr_import_2__);
1273-
;
1274-
console.log(__vite_ssr_import_0__.foo + 2)
1272+
1273+
1274+
console.log(__vite_ssr_import_1__.foo + 2)
12751275
"
12761276
`)
12771277
})
@@ -1288,9 +1288,9 @@ console.log(bar)
12881288
"Object.defineProperty(__vite_ssr_exports__, "default", { enumerable: true, configurable: true, get(){ return __vite_ssr_export_default__ }});
12891289
Object.defineProperty(__vite_ssr_exports__, "bar", { enumerable: true, configurable: true, get(){ return __vite_ssr_import_1__ }});
12901290
1291-
const __vite_ssr_import_0__ = await __vite_ssr_import__("./foo", {"importedNames":["foo"]});
1291+
const __vite_ssr_import_0__ = await __vite_ssr_import__("./foo", {"importedNames":["foo"]});const __vite_ssr_import_1__ = await __vite_ssr_import__("./bar");;
12921292
const __vite_ssr_export_default__ = (0,__vite_ssr_import_0__.foo)();
1293-
const __vite_ssr_import_1__ = await __vite_ssr_import__("./bar");;
1293+
12941294
console.log(bar)
12951295
"
12961296
`)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export { IonTypes } from './IonTypes.js';
2+
import * as dom from './dom/index.js';
3+
export { dom };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const IonTypes = {
2+
BLOB: 'Blob',
3+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
reproduction from https://github.com/vitest-dev/vitest/issues/4143#issuecomment-1724526796
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import { IonTypes } from '../Ion.js';
2+
export const Blob = IonTypes.BLOB;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { Blob } from './Blob.js';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
console.log('dep1');
2+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
console.log('dep2');
2+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './dep1.js';
2+
import './dep2.js'

packages/vite/src/node/ssr/runtime/__tests__/server-runtime.spec.ts

+30
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,36 @@ describe('module runner initialization', async () => {
302302
)
303303
})
304304

305+
it(`cyclic with mixed import and re-export`, async ({ runner }) => {
306+
const mod = await runner.import('/fixtures/cyclic2/test7/Ion.js')
307+
expect(mod).toMatchInlineSnapshot(`
308+
{
309+
"IonTypes": {
310+
"BLOB": "Blob",
311+
},
312+
"dom": {
313+
"Blob": "Blob",
314+
},
315+
}
316+
`)
317+
})
318+
319+
it(`execution order with mixed import and re-export`, async ({
320+
runner,
321+
onTestFinished,
322+
}) => {
323+
const spy = vi.spyOn(console, 'log')
324+
onTestFinished(() => spy.mockRestore())
325+
326+
await runner.import('/fixtures/execution-order-re-export/index.js')
327+
expect(spy.mock.calls.map((v) => v[0])).toMatchInlineSnapshot(`
328+
[
329+
"dep1",
330+
"dep2",
331+
]
332+
`)
333+
})
334+
305335
it(`live binding (export default function f)`, async ({ runner }) => {
306336
const mod = await runner.import('/fixtures/live-binding/test1/index.js')
307337
expect(mod.default).toMatchInlineSnapshot(`

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

+42-14
Original file line numberDiff line numberDiff line change
@@ -186,27 +186,63 @@ async function ssrTransformScript(
186186
)
187187
}
188188

189-
const imports: RollupAstNode<ImportDeclaration>[] = []
189+
const imports: (
190+
| RollupAstNode<ImportDeclaration>
191+
| RollupAstNode<ExportNamedDeclaration>
192+
| RollupAstNode<ExportAllDeclaration>
193+
)[] = []
190194
const exports: (
191195
| RollupAstNode<ExportNamedDeclaration>
192196
| RollupAstNode<ExportDefaultDeclaration>
193197
| RollupAstNode<ExportAllDeclaration>
194198
)[] = []
199+
const reExportImportIdMap = new Map<
200+
RollupAstNode<ExportNamedDeclaration> | RollupAstNode<ExportAllDeclaration>,
201+
string
202+
>()
195203

196204
for (const node of ast.body as Node[]) {
197205
if (node.type === 'ImportDeclaration') {
198206
imports.push(node)
207+
} else if (node.type === 'ExportDefaultDeclaration') {
208+
exports.push(node)
199209
} else if (
200210
node.type === 'ExportNamedDeclaration' ||
201-
node.type === 'ExportDefaultDeclaration' ||
202211
node.type === 'ExportAllDeclaration'
203212
) {
213+
imports.push(node)
204214
exports.push(node)
205215
}
206216
}
207217

208-
// 1. check all import statements and record id -> importName map
218+
// 1. check all import statements, hoist imports, and record id -> importName map
209219
for (const node of imports) {
220+
// hoist re-export's import at the same time as normal imports to preserve execution order
221+
if (node.type === 'ExportNamedDeclaration') {
222+
if (node.source) {
223+
// export { foo, bar } from './foo'
224+
const importId = defineImport(
225+
hoistIndex,
226+
node as RollupAstNode<ExportNamedDeclaration & { source: Literal }>,
227+
{
228+
importedNames: node.specifiers.map(
229+
(s) => getIdentifierNameOrLiteralValue(s.local) as string,
230+
),
231+
},
232+
)
233+
reExportImportIdMap.set(node, importId)
234+
}
235+
continue
236+
}
237+
if (node.type === 'ExportAllDeclaration') {
238+
if (node.source) {
239+
// export * from './foo'
240+
const importId = defineImport(hoistIndex, node)
241+
reExportImportIdMap.set(node, importId)
242+
}
243+
continue
244+
}
245+
210246
// import foo from 'foo' --> foo -> __import_foo__.default
211247
// import { baz } from 'foo' --> baz -> __import_foo__.baz
212248
// import * as ok from 'foo' --> ok -> __import_foo__
@@ -263,18 +299,9 @@ async function ssrTransformScript(
263299
}
264300
s.remove(node.start, (node.declaration as Node).start)
265301
} else {
266-
s.remove(node.start, node.end)
267302
if (node.source) {
268303
// export { foo, bar } from './foo'
269-
const importId = defineImport(
270-
node.start,
271-
node as RollupAstNode<ExportNamedDeclaration & { source: Literal }>,
272-
{
273-
importedNames: node.specifiers.map(
274-
(s) => getIdentifierNameOrLiteralValue(s.local) as string,
275-
),
276-
},
277-
)
304+
const importId = reExportImportIdMap.get(node)!
278305
for (const spec of node.specifiers) {
279306
const exportedAs = getIdentifierNameOrLiteralValue(
280307
spec.exported,
@@ -290,6 +317,7 @@ async function ssrTransformScript(
290317
}
291318
}
292319
} else {
320+
s.remove(node.start, node.end)
293321
// export { foo, bar }
294322
for (const spec of node.specifiers) {
295323
// spec.local can be Literal only when it has "from 'something'"
@@ -333,7 +361,7 @@ async function ssrTransformScript(
333361

334362
// export * from './foo'
335363
if (node.type === 'ExportAllDeclaration') {
336-
const importId = defineImport(node.start, node)
364+
const importId = reExportImportIdMap.get(node)!
337365
if (node.exported) {
338366
const exportedAs = getIdentifierNameOrLiteralValue(
339367
node.exported,

0 commit comments

Comments
 (0)