Skip to content
Prev Previous commit
Next Next commit
get the test to pass
  • Loading branch information
aleclarson committed Dec 19, 2024
commit 2281311221afeaa052c84fab4cf88b412bbb6eed
61 changes: 32 additions & 29 deletions packages/vite/src/node/ssr/ssrTransform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,51 +126,54 @@ async function ssrTransformScript(
) {
const source = importNode.source.value as string
deps.add(source)
const importId = `__vite_ssr_import_${uid++}__`

// Reduce metadata to undefined if it's all default values
if (
metadata &&
(metadata.importedNames == null || metadata.importedNames.length === 0)
) {
metadata = undefined
}
const metadataStr = metadata ? `, ${JSON.stringify(metadata)}` : ''
const metadataArg =
(metadata?.importedNames?.length ?? 0) > 0
? `, ${JSON.stringify(metadata)}`
: ''

// Track how many lines the original import statement spans, so we can preserve the line offset.
let linesSpanned = 1
for (let i = importNode.start; i < importNode.end; i++) {
if (code[i] === '\n') {
linesSpanned++
}
}
const importId = `__vite_ssr_import_${uid++}__`
const transformedImport = `const ${importId} = await ${ssrImportKey}(${JSON.stringify(
source,
)}${metadataArg});`

s.update(
importNode.start,
importNode.end,
`const ${importId} = await ${ssrImportKey}(${JSON.stringify(
source,
)}${metadataStr});${'\n'.repeat(linesSpanned - 1)}`,
)
s.update(importNode.start, importNode.end, transformedImport)

// Check for non-whitespace characters between the last import and the
// current one.
// current one, to determine if hoisting is needed.
// TODO: Account for comments between imports.
const nonWhitespaceRegex = /\S/g
nonWhitespaceRegex.lastIndex = index
nonWhitespaceRegex.exec(code)

// TODO: Account for comments between imports.
if (importNode.start > nonWhitespaceRegex.lastIndex) {
// By moving the import to the top of the module, we ensure that it's
// imported before it's used.
// Imports are moved to the top of the file (AKA “hoisting”) to ensure any
// non-import statements before them are executed after the import. This
// aligns SSR imports with native ESM import behavior.
s.move(importNode.start, importNode.end, index)
} else {
// Only update hoistIndex when not hoisting the current import. This
// Only update hoistIndex when *not* hoisting the current import. This
// ensures that once any import in this module has been hoisted, all
// remaining imports will also be hoisted.
// remaining imports will also be hoisted. This is inherently true because
// we work from the top of the file downward.
hoistIndex = importNode.end
}

// Track how many lines the original import statement spans, so we can
// preserve the line offset.
let linesSpanned = 1
for (let i = importNode.start; i < importNode.end; i++) {
if (code[i] === '\n') {
linesSpanned++
}
}
if (linesSpanned > 1) {
// This leaves behind any extra newlines that were removed during
// transformation, in the position of the original import statement
// (before any hoisting).
s.prependRight(importNode.end, '\n'.repeat(linesSpanned - 1))
}

return importId
}

Expand Down