Skip to content

Commit 99ff614

Browse files
committed
Make loadChunkAsync load chunks synchronously
We still return a promise to satisfy our call signatures but resolution is now synchronously performed by `require`
1 parent 2aef054 commit 99ff614

File tree

1 file changed

+33
-36
lines changed
  • turbopack/crates/turbopack-ecmascript-runtime/js/src/nodejs

1 file changed

+33
-36
lines changed

turbopack/crates/turbopack-ecmascript-runtime/js/src/nodejs/runtime.ts

Lines changed: 33 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ function loadChunk(chunkData: ChunkData, source?: SourceInfo): void {
9595
const loadedChunks = new Set<ChunkPath>()
9696
const unsupportedLoadChunk = Promise.resolve(undefined)
9797
const loadedChunk = Promise.resolve(undefined)
98-
const chunkCache = new Map<ChunkPath, Promise<any> | null>()
98+
// Holds either a rejected promise or `loadedChunk` for success
99+
const chunkCache = new Map<ChunkPath, Promise<void>>()
99100

100101
function clearChunkCache() {
101102
chunkCache.clear()
@@ -143,47 +144,30 @@ function loadChunkPath(chunkPath: ChunkPath, source?: SourceInfo): void {
143144
}
144145
}
145146

146-
async function loadChunkAsyncUncached(
147-
source: SourceInfo,
148-
chunkPath: ChunkPath
149-
): Promise<void> {
147+
function loadChunkUncached(chunkPath: ChunkPath) {
148+
// resolve to an absolute path to simplify `require` handling
150149
const resolved = path.resolve(RUNTIME_ROOT, chunkPath)
151150

152-
try {
153-
// use await to ensure that evaluation happens in another microtask
154-
// Because we are using a resolved absolute path require shouldn't waste time probing node_modules.
155-
const exports = await require(resolved)
156-
const chunkModules: CompressedModuleFactories = exports
157-
for (const [moduleId, moduleFactory] of Object.entries(chunkModules)) {
158-
if (!moduleFactories[moduleId]) {
159-
if (Array.isArray(moduleFactory)) {
160-
const [moduleFactoryFn, otherIds] = moduleFactory
161-
moduleFactories[moduleId] = moduleFactoryFn
162-
for (const otherModuleId of otherIds) {
163-
moduleFactories[otherModuleId] = moduleFactoryFn
164-
}
165-
} else {
166-
moduleFactories[moduleId] = moduleFactory
151+
const chunkModules: CompressedModuleFactories = require(resolved)
152+
for (const [moduleId, moduleFactory] of Object.entries(chunkModules)) {
153+
if (!moduleFactories[moduleId]) {
154+
if (Array.isArray(moduleFactory)) {
155+
const [moduleFactoryFn, otherIds] = moduleFactory
156+
moduleFactories[moduleId] = moduleFactoryFn
157+
for (const otherModuleId of otherIds) {
158+
moduleFactories[otherModuleId] = moduleFactoryFn
167159
}
160+
} else {
161+
moduleFactories[moduleId] = moduleFactory
168162
}
169163
}
170-
} catch (e) {
171-
let errorMessage = `Failed to load chunk ${chunkPath}`
172-
173-
if (source) {
174-
errorMessage += ` from ${stringifySourceInfo(source)}`
175-
}
176-
177-
throw new Error(errorMessage, {
178-
cause: e,
179-
})
180164
}
181165
}
182166

183167
function loadChunkAsync(
184168
source: SourceInfo,
185169
chunkData: ChunkData
186-
): Promise<any> {
170+
): Promise<void> {
187171
const chunkPath = typeof chunkData === 'string' ? chunkData : chunkData.path
188172
if (!isJs(chunkPath)) {
189173
// We only support loading JS chunks in Node.js.
@@ -193,14 +177,27 @@ function loadChunkAsync(
193177

194178
let entry = chunkCache.get(chunkPath)
195179
if (entry === undefined) {
196-
const resolve = chunkCache.set.bind(chunkCache, chunkPath, null)
197-
// A new Promise ensures callers that don't handle rejection will still trigger one unhandled rejection.
198-
// Handling the rejection will not trigger unhandled rejections.
199-
entry = loadChunkAsyncUncached(source, chunkPath).then(resolve)
180+
try {
181+
// Load the chunk synchronously
182+
loadChunkUncached(chunkPath)
183+
entry = loadedChunk
184+
} catch (e) {
185+
let errorMessage = `Failed to load chunk ${chunkPath}`
186+
if (source) {
187+
errorMessage += ` from ${stringifySourceInfo(source)}`
188+
}
189+
190+
// Cache the failure promise, future requests will also get this same rejection
191+
entry = Promise.reject(
192+
new Error(errorMessage, {
193+
cause: e,
194+
})
195+
)
196+
}
200197
chunkCache.set(chunkPath, entry)
201198
}
202199
// TODO: Return an instrumented Promise that React can use instead of relying on referential equality.
203-
return entry === null ? loadedChunk : entry
200+
return entry
204201
}
205202

206203
function loadChunkAsyncByUrl(source: SourceInfo, chunkUrl: string) {

0 commit comments

Comments
 (0)