Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/vite/src/node/ssr/__tests__/ssrTransform.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
import { assert, expect, test } from 'vitest'
import type { SourceMap } from 'rollup'
import { TraceMap, originalPositionFor } from '@jridgewell/trace-mapping'
import { transformWithEsbuild } from '../../plugins/esbuild'
import { ssrTransform } from '../ssrTransform'

Expand Down Expand Up @@ -442,6 +443,25 @@ test('sourcemap source', async () => {
expect(map?.sourcesContent).toStrictEqual(['export const a = 1 /* */'])
})

test('sourcemap is correct for hoisted imports', async () => {
const map = (
await ssrTransform(
`\n\n\nimport { foo } from 'vue';`,
null,
'input.js',
'export const a = 1 /* */',
)
)?.map

const traceMap = new TraceMap(map as any)
expect(originalPositionFor(traceMap, { line: 1, column: 0 })).toStrictEqual({
source: 'input.js',
line: 4,
column: 0,
name: null,
})
})

test('sourcemap with multiple sources', async () => {
const code = readFixture('bundle.js')
const map = readFixture('bundle.js.map')
Expand Down
56 changes: 36 additions & 20 deletions packages/vite/src/node/ssr/ssrTransform.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from 'node:path'
import MagicString from 'magic-string'
import type { SourceMap } from 'rollup'
import type { RollupAstNode, SourceMap } from 'rollup'
import type {
ExportAllDeclaration,
ExportDefaultDeclaration,
Expand Down Expand Up @@ -98,13 +98,21 @@ async function ssrTransformScript(
const declaredConst = new Set<string>()

// hoist at the start of the file, after the hashbang
const hoistIndex = hashbangRE.exec(code)?.[0].length ?? 0
let hoistIndex = hashbangRE.exec(code)?.[0].length ?? 0

function defineImport(
index: number,
source: string,
importNode: (
| ImportDeclaration
| (ExportNamedDeclaration & { source: Literal })
| ExportAllDeclaration
) & {
start: number
end: number
},
metadata?: DefineImportMetadata,
) {
const source = importNode.source.value as string
deps.add(source)
const importId = `__vite_ssr_import_${uid++}__`

Expand All @@ -119,12 +127,22 @@ async function ssrTransformScript(

// There will be an error if the module is called before it is imported,
// so the module import statement is hoisted to the top
s.appendLeft(
index,
s.update(
importNode.start,
importNode.end,
`const ${importId} = await ${ssrImportKey}(${JSON.stringify(
source,
)}${metadataStr});\n`,
)

if (importNode.start !== index) {
s.move(importNode.start, importNode.end, index)
}

if (index === hoistIndex) {
hoistIndex = importNode.end
}

return importId
}

Expand All @@ -136,12 +154,12 @@ async function ssrTransformScript(
)
}

const imports: (ImportDeclaration & { start: number; end: number })[] = []
const exports: ((
| ExportNamedDeclaration
| ExportDefaultDeclaration
| ExportAllDeclaration
) & { start: number; end: number })[] = []
const imports: RollupAstNode<ImportDeclaration>[] = []
const exports: (
| RollupAstNode<ExportNamedDeclaration>
| RollupAstNode<ExportDefaultDeclaration>
| RollupAstNode<ExportAllDeclaration>
)[] = []

for (const node of ast.body as Node[]) {
if (node.type === 'ImportDeclaration') {
Expand All @@ -160,7 +178,7 @@ async function ssrTransformScript(
// import foo from 'foo' --> foo -> __import_foo__.default
// import { baz } from 'foo' --> baz -> __import_foo__.baz
// import * as ok from 'foo' --> ok -> __import_foo__
const importId = defineImport(hoistIndex, node.source.value as string, {
const importId = defineImport(hoistIndex, node, {
importedNames: node.specifiers
.map((s) => {
if (s.type === 'ImportSpecifier')
Expand All @@ -169,7 +187,6 @@ async function ssrTransformScript(
})
.filter(isDefined),
})
s.remove(node.start, node.end)
for (const spec of node.specifiers) {
if (spec.type === 'ImportSpecifier') {
if (spec.imported.type === 'Identifier') {
Expand Down Expand Up @@ -219,7 +236,7 @@ async function ssrTransformScript(
// export { foo, bar } from './foo'
const importId = defineImport(
node.start,
node.source.value as string,
node as RollupAstNode<ExportNamedDeclaration & { source: Literal }>,
{
importedNames: node.specifiers.map(
(s) => getIdentifierNameOrLiteralValue(s.local) as string,
Expand All @@ -233,13 +250,13 @@ async function ssrTransformScript(

if (spec.local.type === 'Identifier') {
defineExport(
node.start,
node.end,
exportedAs,
`${importId}.${spec.local.name}`,
)
} else {
defineExport(
node.start,
node.end,
exportedAs,
`${importId}[${JSON.stringify(spec.local.value as string)}]`,
)
Expand Down Expand Up @@ -290,15 +307,14 @@ async function ssrTransformScript(

// export * from './foo'
if (node.type === 'ExportAllDeclaration') {
s.remove(node.start, node.end)
const importId = defineImport(node.start, node.source.value as string)
const importId = defineImport(node.start, node)
if (node.exported) {
const exportedAs = getIdentifierNameOrLiteralValue(
node.exported,
) as string
defineExport(node.start, exportedAs, `${importId}`)
defineExport(node.end, exportedAs, `${importId}`)
} else {
s.appendLeft(node.start, `${ssrExportAllKey}(${importId});\n`)
s.appendLeft(node.end, `${ssrExportAllKey}(${importId});\n`)
}
}
}
Expand Down