Skip to content

Commit 64d5ce7

Browse files
fix: minify from a webpack bundle with Node.js's own require
Inside a webpack bundle, module is webpack's module object, which has no require, so minify reported that webpack was missing. Use the require webpack keeps as __non_webpack_require__ there, and module.require outside a bundle. The bundled test now also minifies a check from the bundle. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYPkbvwyRWt2SHgXDoYRdo
1 parent 4385103 commit 64d5ce7

4 files changed

Lines changed: 42 additions & 11 deletions

File tree

‎.changeset/precompile-bundle.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
"schema-utils": patch
33
---
44

5-
Bundle `schema-utils` without errors or warnings: `precompile` requires the `ajv` helpers it inlines by name and loads webpack's minifier without a request a bundler parses.
5+
Bundle `schema-utils` without errors or warnings: `precompile` requires the `ajv` helpers it inlines by name and loads webpack's minifier with Node.js's own `require`, so `minify` works from a webpack bundle too.

‎src/precompile.js‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,20 @@ async function minify(code, esm) {
269269
let minifier;
270270

271271
// webpack's own minifier, which writes what terser writes without loading it - the packages
272-
// shipping a check already have webpack. Required through an alias of `module` so a bundler
273-
// that bundles `schema-utils` neither bundles webpack nor warns about a request it cannot
274-
// resolve, while Node.js resolves it like any `require` here.
272+
// shipping a check already have webpack. A bundler that bundles `schema-utils` must neither
273+
// bundle webpack nor warn about a request it cannot resolve, so webpack is loaded with Node.js's
274+
// own `require`: the one webpack keeps as `__non_webpack_require__` inside a webpack bundle, and
275+
// `module.require` through an alias of `module` outside one.
276+
/* global __non_webpack_require__ */
277+
// prettier-ignore
278+
// @ts-expect-error a free variable only a webpack bundle defines
279+
const nodeRequire = typeof __non_webpack_require__ === "function" ? __non_webpack_require__ : undefined;
275280
const self = module;
276281

277282
try {
278-
minifier = await self.require("webpack").javascript.syntax.printer.load();
283+
minifier = await (nodeRequire || self.require.bind(self))(
284+
"webpack",
285+
).javascript.syntax.printer.load();
279286
} catch (err) {
280287
throw new Error(
281288
"Install webpack 5.112.0 or later to minify a precompiled check",
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
const { precompile } = require("../../src");
2+
3+
precompile({ type: "string", minLength: 1 }, { minify: true }).then(
4+
(code) => {
5+
const check = { exports: {} };
6+
7+
// eslint-disable-next-line no-new-func
8+
new Function("module", code)(check);
9+
process.stdout.write(JSON.stringify([check.exports(""), check.exports("a")]));
10+
},
11+
);

‎test/precompile.test.js‎

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -602,23 +602,27 @@ describe("precompile", () => {
602602
describe("bundled", () => {
603603
// `schema-utils` is bundled by tools that ship it inside their own code, which reaches
604604
// `precompile` through the `precompile` export even though it only runs at build time
605-
it("should bundle without errors or warnings", (done) => {
605+
it("should bundle without errors or warnings and minify from the bundle", (done) => {
606606
const webpack = require("webpack");
607607

608-
const outputPath = fs.mkdtempSync(path.join(os.tmpdir(), "schema-utils-"));
608+
// Inside the package, so the bundle finds webpack the way any installed bundle does
609+
const localPath = path.resolve(__dirname, "../local");
610+
611+
fs.mkdirSync(localPath, { recursive: true });
612+
613+
const outputPath = fs.mkdtempSync(path.join(localPath, "bundle-"));
609614

610615
webpack(
611616
{
612617
mode: "none",
613618
target: "node",
614-
context: path.resolve(__dirname, ".."),
615-
entry: "./src/index.js",
619+
context: __dirname,
620+
entry: "./fixtures/bundled-precompile.js",
616621
output: { path: outputPath },
617622
},
618623
(err, stats) => {
619-
remove(outputPath);
620-
621624
if (err) {
625+
remove(outputPath);
622626
done(err);
623627

624628
return;
@@ -633,9 +637,18 @@ describe("bundled", () => {
633637

634638
expect(errors.map(({ message }) => message)).toEqual([]);
635639
expect(warnings.map(({ message }) => message)).toEqual([]);
640+
expect(
641+
JSON.parse(
642+
execFileSync(process.execPath, [
643+
path.join(outputPath, "main.js"),
644+
]).toString(),
645+
),
646+
).toEqual([false, true]);
636647
done();
637648
} catch (error) {
638649
done(error);
650+
} finally {
651+
remove(outputPath);
639652
}
640653
},
641654
);

0 commit comments

Comments
 (0)