Skip to content

Commit

Permalink
fix: store backwards compatible ssrModule and ssrError (#18031)
Browse files Browse the repository at this point in the history
  • Loading branch information
sheremet-va authored Sep 4, 2024
1 parent 242f550 commit cf8ced5
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 37 deletions.
46 changes: 23 additions & 23 deletions packages/vite/src/module-runner/runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class ModuleRunner {
if (!('externalize' in fetchResult)) {
return exports
}
const { id, type } = fetchResult
const { url: id, type } = fetchResult
if (type !== 'module' && type !== 'commonjs') return exports
analyzeImportedModDifference(exports, id, type, metadata)
return exports
Expand All @@ -143,23 +143,23 @@ export class ModuleRunner {

private isCircularImport(
importers: Set<string>,
moduleId: string,
moduleUrl: string,
visited = new Set<string>(),
) {
for (const importer of importers) {
if (visited.has(importer)) {
continue
}
visited.add(importer)
if (importer === moduleId) {
if (importer === moduleUrl) {
return true
}
const mod = this.moduleCache.getByModuleId(
importer,
) as Required<ModuleCache>
if (
mod.importers.size &&
this.isCircularImport(mod.importers, moduleId, visited)
this.isCircularImport(mod.importers, moduleUrl, visited)
) {
return true
}
Expand All @@ -175,7 +175,7 @@ export class ModuleRunner {
): Promise<any> {
const mod = mod_ as Required<ModuleCache>
const meta = mod.meta!
const moduleId = meta.id
const moduleUrl = meta.url

const { importers } = mod

Expand All @@ -185,9 +185,9 @@ export class ModuleRunner {

// check circular dependency
if (
callstack.includes(moduleId) ||
callstack.includes(moduleUrl) ||
this.isCircularModule(mod) ||
this.isCircularImport(importers, moduleId)
this.isCircularImport(importers, moduleUrl)
) {
if (mod.exports) return this.processImport(mod.exports, meta, metadata)
}
Expand All @@ -196,13 +196,13 @@ export class ModuleRunner {
if (this.debug) {
debugTimer = setTimeout(() => {
const getStack = () =>
`stack:\n${[...callstack, moduleId]
`stack:\n${[...callstack, moduleUrl]
.reverse()
.map((p) => ` - ${p}`)
.join('\n')}`

this.debug!(
`[module runner] module ${moduleId} takes over 2s to load.\n${getStack()}`,
`[module runner] module ${moduleUrl} takes over 2s to load.\n${getStack()}`,
)
}, 2000)
}
Expand Down Expand Up @@ -284,24 +284,24 @@ export class ModuleRunner {
const query = idQuery ? `?${idQuery}` : ''
const file = 'file' in fetchedModule ? fetchedModule.file : undefined
const fileId = file ? `${file}${query}` : url
const moduleId = this.moduleCache.normalize(fileId)
const mod = this.moduleCache.getByModuleId(moduleId)
const moduleUrl = this.moduleCache.normalize(fileId)
const mod = this.moduleCache.getByModuleId(moduleUrl)

if ('invalidate' in fetchedModule && fetchedModule.invalidate) {
this.moduleCache.invalidateModule(mod)
}

fetchedModule.id = moduleId
fetchedModule.url = moduleUrl
mod.meta = fetchedModule

if (file) {
const fileModules = this.fileToIdMap.get(file) || []
fileModules.push(moduleId)
fileModules.push(moduleUrl)
this.fileToIdMap.set(file, fileModules)
}

this.urlToIdMap.set(url, moduleId)
this.urlToIdMap.set(unwrapId(url), moduleId)
this.urlToIdMap.set(url, moduleUrl)
this.urlToIdMap.set(unwrapId(url), moduleUrl)
return mod
}

Expand All @@ -312,15 +312,15 @@ export class ModuleRunner {
_callstack: string[],
): Promise<any> {
const fetchResult = mod.meta!
const moduleId = fetchResult.id
const callstack = [..._callstack, moduleId]
const moduleUrl = fetchResult.url
const callstack = [..._callstack, moduleUrl]

const request = async (dep: string, metadata?: SSRImportMetadata) => {
const importer = ('file' in fetchResult && fetchResult.file) || moduleId
const importer = ('file' in fetchResult && fetchResult.file) || moduleUrl
const fetchedModule = await this.cachedModule(dep, importer)
const resolvedId = fetchedModule.meta!.id
const resolvedId = fetchedModule.meta!.url
const depMod = this.moduleCache.getByModuleId(resolvedId)
depMod.importers!.add(moduleId)
depMod.importers!.add(moduleUrl)
mod.imports!.add(resolvedId)

return this.cachedRequest(dep, fetchedModule, callstack, metadata)
Expand Down Expand Up @@ -354,7 +354,7 @@ export class ModuleRunner {
)
}

const modulePath = cleanUrl(file || moduleId)
const modulePath = cleanUrl(file || moduleUrl)
// disambiguate the `<UNIT>:/` on windows: see nodejs/node#31710
const href = posixPathToFileHref(modulePath)
const filename = modulePath
Expand Down Expand Up @@ -391,8 +391,8 @@ export class ModuleRunner {
if (!this.hmrClient) {
throw new Error(`[module runner] HMR client was destroyed.`)
}
this.debug?.('[module runner] creating hmr context for', moduleId)
hotContext ||= new HMRContext(this.hmrClient, moduleId)
this.debug?.('[module runner] creating hmr context for', moduleUrl)
hotContext ||= new HMRContext(this.hmrClient, moduleUrl)
return hotContext
},
set: (value) => {
Expand Down
6 changes: 5 additions & 1 deletion packages/vite/src/module-runner/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,14 +116,18 @@ export interface ViteFetchResult {
* Will be equal to `null` for virtual modules
*/
file: string | null
/**
* Module ID in the server module graph.
*/
serverId: string
/**
* Invalidate module on the client side.
*/
invalidate: boolean
}

export type ResolvedResult = (ExternalFetchResult | ViteFetchResult) & {
id: string
url: string
}

export type FetchFunction = (
Expand Down
1 change: 1 addition & 0 deletions packages/vite/src/node/ssr/fetchModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export async function fetchModule(
return {
code: result.code,
file: mod.file,
serverId: mod.id!,
invalidate: !cached,
}
}
Expand Down
62 changes: 49 additions & 13 deletions packages/vite/src/node/ssr/ssrModuleLoader.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import colors from 'picocolors'
import type { ModuleRunner } from 'vite/module-runner'
import type { ModuleCache } from 'vite/module-runner'
import { ESModulesEvaluator, ModuleRunner } from 'vite/module-runner'
import type { ViteDevServer } from '../server'
import { unwrapId } from '../../shared/utils'
import { ssrFixStacktrace } from './ssrStacktrace'
import { createServerModuleRunner } from './runtime/serverModuleRunner'

type SSRModule = Record<string, any>

Expand All @@ -12,13 +12,7 @@ export async function ssrLoadModule(
server: ViteDevServer,
fixStacktrace?: boolean,
): Promise<SSRModule> {
server._ssrCompatModuleRunner ||= createServerModuleRunner(
server.environments.ssr,
{
sourcemapInterceptor: false,
hmr: false,
},
)
server._ssrCompatModuleRunner ||= new SSRCompatModuleRunner(server)
url = unwrapId(url)

return instantiateModule(
Expand All @@ -43,11 +37,8 @@ async function instantiateModule(
}

try {
const exports = await runner.import(url)
mod.ssrModule = exports
return exports
return await runner.import(url)
} catch (e: any) {
mod.ssrError = e
if (e.stack && fixStacktrace) {
ssrFixStacktrace(e, environment.moduleGraph)
}
Expand All @@ -64,3 +55,48 @@ async function instantiateModule(
throw e
}
}

class SSRCompatModuleRunner extends ModuleRunner {
constructor(private server: ViteDevServer) {
super(
{
root: server.environments.ssr.config.root,
transport: {
fetchModule: (id, importer, options) =>
server.environments.ssr.fetchModule(id, importer, options),
},
sourcemapInterceptor: false,
hmr: false,
},
new ESModulesEvaluator(),
)
}

protected override async directRequest(
id: string,
mod: ModuleCache,
_callstack: string[],
): Promise<any> {
const serverId = mod.meta && 'serverId' in mod.meta && mod.meta.serverId
// serverId doesn't exist for external modules
if (!serverId) {
return super.directRequest(id, mod, _callstack)
}

const viteMod =
this.server.environments.ssr.moduleGraph.getModuleById(serverId)

if (!viteMod) {
return super.directRequest(id, mod, _callstack)
}

try {
const exports = await super.directRequest(id, mod, _callstack)
viteMod.ssrModule = exports
return exports
} catch (err) {
viteMod.ssrError = err
throw err
}
}
}

0 comments on commit cf8ced5

Please sign in to comment.