From 02d68f847fd166cf769b6361205a8436a4692578 Mon Sep 17 00:00:00 2001 From: Marukome0743 Date: Fri, 17 Apr 2026 23:15:51 +0900 Subject: [PATCH] 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 #1880, facebook/docusaurus#11545 --- .cspell.json | 3 ++- index.js | 6 ++++++ spec/basic.spec.js | 12 ++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/.cspell.json b/.cspell.json index 1352c7ac5..a4b3b91e9 100644 --- a/.cspell.json +++ b/.cspell.json @@ -28,7 +28,8 @@ "specialattribute", "dircompare", "wagoid", - "autocrlf" + "autocrlf", + "Rspack" ], "ignorePaths": [ "CHANGELOG.md", diff --git a/index.js b/index.js index 28fc0ede4..34df47f5e 100644 --- a/index.js +++ b/index.js @@ -640,11 +640,17 @@ class HtmlWebpackPlugin { delete globalClone.eval; delete globalClone.Function; // Not using `...global` as it throws when localStorage is not explicitly enabled in Node 25+ + // Provide a CommonJS-style `module`/`exports` pair so templates compiled as CommonJS + // (e.g. Rspack's child compilation output, which wraps the result in `module.exports = ...`) + // can assign to them instead of failing with `module is not defined`. + const sandboxModule = { exports: {} }; const vmContext = vm.createContext( Object.assign(globalClone, { HTML_WEBPACK_PLUGIN: true, // Copying nonstandard globals like `require` explicitly as they may be absent from `global` require: require, + module: sandboxModule, + exports: sandboxModule.exports, htmlWebpackPluginPublicPath: publicPath, __filename: templateWithoutLoaders, __dirname: path.dirname(templateWithoutLoaders), diff --git a/spec/basic.spec.js b/spec/basic.spec.js index 648c7944f..b9952df28 100644 --- a/spec/basic.spec.js +++ b/spec/basic.spec.js @@ -3853,4 +3853,16 @@ describe("HtmlWebpackPlugin", () => { done, ); }); + + describe("evaluateCompilationResult", () => { + it("evaluates templates wrapped in a CommonJS `module.exports = ...` expression", () => { + const plugin = new HtmlWebpackPlugin(); + const source = 'module.exports = "ok";'; + return plugin + .evaluateCompilationResult(source, "", "template.js") + .then((result) => { + expect(result).toBe("ok"); + }); + }); + }); });