Skip to content

Commit

Permalink
Re-throw module.error when instantiating runtime modules (vercel/turb…
Browse files Browse the repository at this point in the history
…orepo#4918)

### Description

Runtime modules can be executed multiple times within the same context.
However, when such a module encounters a runtime error during execution,
this error is cached in module.error and not properly re-thrown when the
module is required again from `getOrInstantiateRuntimeModule`, which
means that on later runs we’ll silently fail to instantiate the module,
and run into any errors that expects a global side-effect from the
module.

link WEB-1045
  • Loading branch information
alexkirsz committed May 15, 2023
1 parent 7b12255 commit 84c42b7
Show file tree
Hide file tree
Showing 36 changed files with 1,044 additions and 720 deletions.
49 changes: 29 additions & 20 deletions crates/turbopack-dev/js/src/runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,8 +482,9 @@ function instantiateModule(id, source) {
break;
}

runModuleExecutionHooks(module, (refresh) => {
try {
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
runModuleExecutionHooks(module, (refresh) => {
moduleFactory.call(module.exports, {
e: module.exports,
r: commonJsRequire.bind(null, module),
Expand All @@ -501,11 +502,11 @@ function instantiateModule(id, source) {
k: refresh,
__dirname: module.id.replace(/(^|\/)[\/]+$/, ""),
});
} catch (error) {
module.error = error;
throw error;
}
});
});
} catch (error) {
module.error = error;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
Expand All @@ -530,21 +531,26 @@ function runModuleExecutionHooks(module, executeModule) {
? globalThis.$RefreshInterceptModuleExecution$(module.id)
: () => {};

executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});
try {
executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});

if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
}
} catch (e) {
throw e;
} finally {
// Always cleanup the intercept, even if module execution failed.
cleanupReactRefreshIntercept();
}

cleanupReactRefreshIntercept();
}

/**
Expand Down Expand Up @@ -1418,6 +1424,9 @@ function instantiateRuntimeModule(moduleId, chunkPath) {
function getOrInstantiateRuntimeModule(moduleId, chunkPath) {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,9 @@ function instantiateModule(id, source) {
break;
}

runModuleExecutionHooks(module, (refresh) => {
try {
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
runModuleExecutionHooks(module, (refresh) => {
moduleFactory.call(module.exports, {
e: module.exports,
r: commonJsRequire.bind(null, module),
Expand All @@ -510,11 +511,11 @@ function instantiateModule(id, source) {
k: refresh,
__dirname: module.id.replace(/(^|\/)[\/]+$/, ""),
});
} catch (error) {
module.error = error;
throw error;
}
});
});
} catch (error) {
module.error = error;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
Expand All @@ -539,21 +540,26 @@ function runModuleExecutionHooks(module, executeModule) {
? globalThis.$RefreshInterceptModuleExecution$(module.id)
: () => {};

executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});
try {
executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});

if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
}
} catch (e) {
throw e;
} finally {
// Always cleanup the intercept, even if module execution failed.
cleanupReactRefreshIntercept();
}

cleanupReactRefreshIntercept();
}

/**
Expand Down Expand Up @@ -1427,6 +1433,9 @@ function instantiateRuntimeModule(moduleId, chunkPath) {
function getOrInstantiateRuntimeModule(moduleId, chunkPath) {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,9 @@ function instantiateModule(id, source) {
break;
}

runModuleExecutionHooks(module, (refresh) => {
try {
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
runModuleExecutionHooks(module, (refresh) => {
moduleFactory.call(module.exports, {
e: module.exports,
r: commonJsRequire.bind(null, module),
Expand All @@ -510,11 +511,11 @@ function instantiateModule(id, source) {
k: refresh,
__dirname: module.id.replace(/(^|\/)[\/]+$/, ""),
});
} catch (error) {
module.error = error;
throw error;
}
});
});
} catch (error) {
module.error = error;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
Expand All @@ -539,21 +540,26 @@ function runModuleExecutionHooks(module, executeModule) {
? globalThis.$RefreshInterceptModuleExecution$(module.id)
: () => {};

executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});
try {
executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});

if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
}
} catch (e) {
throw e;
} finally {
// Always cleanup the intercept, even if module execution failed.
cleanupReactRefreshIntercept();
}

cleanupReactRefreshIntercept();
}

/**
Expand Down Expand Up @@ -1427,6 +1433,9 @@ function instantiateRuntimeModule(moduleId, chunkPath) {
function getOrInstantiateRuntimeModule(moduleId, chunkPath) {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,9 @@ function instantiateModule(id, source) {
break;
}

runModuleExecutionHooks(module, (refresh) => {
try {
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
runModuleExecutionHooks(module, (refresh) => {
moduleFactory.call(module.exports, {
e: module.exports,
r: commonJsRequire.bind(null, module),
Expand All @@ -510,11 +511,11 @@ function instantiateModule(id, source) {
k: refresh,
__dirname: module.id.replace(/(^|\/)[\/]+$/, ""),
});
} catch (error) {
module.error = error;
throw error;
}
});
});
} catch (error) {
module.error = error;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
Expand All @@ -539,21 +540,26 @@ function runModuleExecutionHooks(module, executeModule) {
? globalThis.$RefreshInterceptModuleExecution$(module.id)
: () => {};

executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});
try {
executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});

if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
}
} catch (e) {
throw e;
} finally {
// Always cleanup the intercept, even if module execution failed.
cleanupReactRefreshIntercept();
}

cleanupReactRefreshIntercept();
}

/**
Expand Down Expand Up @@ -1427,6 +1433,9 @@ function instantiateRuntimeModule(moduleId, chunkPath) {
function getOrInstantiateRuntimeModule(moduleId, chunkPath) {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,8 +491,9 @@ function instantiateModule(id, source) {
break;
}

runModuleExecutionHooks(module, (refresh) => {
try {
// NOTE(alexkirsz) This can fail when the module encounters a runtime error.
try {
runModuleExecutionHooks(module, (refresh) => {
moduleFactory.call(module.exports, {
e: module.exports,
r: commonJsRequire.bind(null, module),
Expand All @@ -510,11 +511,11 @@ function instantiateModule(id, source) {
k: refresh,
__dirname: module.id.replace(/(^|\/)[\/]+$/, ""),
});
} catch (error) {
module.error = error;
throw error;
}
});
});
} catch (error) {
module.error = error;
throw error;
}

module.loaded = true;
if (module.namespaceObject && module.exports !== module.namespaceObject) {
Expand All @@ -539,21 +540,26 @@ function runModuleExecutionHooks(module, executeModule) {
? globalThis.$RefreshInterceptModuleExecution$(module.id)
: () => {};

executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});
try {
executeModule({
register: globalThis.$RefreshReg$,
signature: globalThis.$RefreshSig$,
});

if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
if ("$RefreshHelpers$" in globalThis) {
// This pattern can also be used to register the exports of
// a module with the React Refresh runtime.
registerExportsAndSetupBoundaryForReactRefresh(
module,
globalThis.$RefreshHelpers$
);
}
} catch (e) {
throw e;
} finally {
// Always cleanup the intercept, even if module execution failed.
cleanupReactRefreshIntercept();
}

cleanupReactRefreshIntercept();
}

/**
Expand Down Expand Up @@ -1427,6 +1433,9 @@ function instantiateRuntimeModule(moduleId, chunkPath) {
function getOrInstantiateRuntimeModule(moduleId, chunkPath) {
const module = moduleCache[moduleId];
if (module) {
if (module.error) {
throw module.error;
}
return module;
}

Expand Down
Loading

0 comments on commit 84c42b7

Please sign in to comment.