Skip to content

Commit 02d68f8

Browse files
committed
fix: provide module/exports in VM sandbox for Node.js 25+ compatibility
Templates whose child compilation output is a CommonJS module (for example Rspack's HtmlWebpackPlugin child compilation, which wraps the evaluated template in `module.exports = ...`) were failing at evaluation time with `ReferenceError: module is not defined` under Node.js 25+. In 5.6.5 the VM context was switched away from a `...global` spread because spreading `global` on Node 25 throws once `localStorage` is touched without `--localstorage-file`. The replacement clone only exposes the standard globals plus `require`, so any CommonJS-wrapped source that assigned to `module.exports` hit the ReferenceError. Provide a throwaway `module = { exports: {} }` pair (plus `exports` aliasing it) in the sandbox so CommonJS-style outputs can evaluate without assuming the host Node version populates them. Refs: PR jantimon#1880, facebook/docusaurus#11545
1 parent 0d1ff98 commit 02d68f8

3 files changed

Lines changed: 20 additions & 1 deletion

File tree

.cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"specialattribute",
2929
"dircompare",
3030
"wagoid",
31-
"autocrlf"
31+
"autocrlf",
32+
"Rspack"
3233
],
3334
"ignorePaths": [
3435
"CHANGELOG.md",

index.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -640,11 +640,17 @@ class HtmlWebpackPlugin {
640640
delete globalClone.eval;
641641
delete globalClone.Function;
642642
// Not using `...global` as it throws when localStorage is not explicitly enabled in Node 25+
643+
// Provide a CommonJS-style `module`/`exports` pair so templates compiled as CommonJS
644+
// (e.g. Rspack's child compilation output, which wraps the result in `module.exports = ...`)
645+
// can assign to them instead of failing with `module is not defined`.
646+
const sandboxModule = { exports: {} };
643647
const vmContext = vm.createContext(
644648
Object.assign(globalClone, {
645649
HTML_WEBPACK_PLUGIN: true,
646650
// Copying nonstandard globals like `require` explicitly as they may be absent from `global`
647651
require: require,
652+
module: sandboxModule,
653+
exports: sandboxModule.exports,
648654
htmlWebpackPluginPublicPath: publicPath,
649655
__filename: templateWithoutLoaders,
650656
__dirname: path.dirname(templateWithoutLoaders),

spec/basic.spec.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3853,4 +3853,16 @@ describe("HtmlWebpackPlugin", () => {
38533853
done,
38543854
);
38553855
});
3856+
3857+
describe("evaluateCompilationResult", () => {
3858+
it("evaluates templates wrapped in a CommonJS `module.exports = ...` expression", () => {
3859+
const plugin = new HtmlWebpackPlugin();
3860+
const source = 'module.exports = "<!DOCTYPE html><title>ok</title>";';
3861+
return plugin
3862+
.evaluateCompilationResult(source, "", "template.js")
3863+
.then((result) => {
3864+
expect(result).toBe("<!DOCTYPE html><title>ok</title>");
3865+
});
3866+
});
3867+
});
38563868
});

0 commit comments

Comments
 (0)