Skip to content

feat: precompile into an ES module for a "type": "module" package - #233

Merged
alexander-akait merged 2 commits into
mainfrom
feat/precompile-esm
Oct 18, 2026
Merged

alexander-akait merged 2 commits into
mainfrom
feat/precompile-esm

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Oct 18, 2026 •

Copy link
Copy Markdown
Member

Summary

schema-utils precompile writes a CommonJS module. In a package with "type": "module", Node.js loads options.check.js as an ES module, so module.exports throws. That blocks less-loader, sass-loader and stylus-loader from using a precompiled check.

  • CLI: the check is an ES module when the nearest package.json has "type": "module", the way Node.js reads a .js file there. Otherwise it stays CommonJS. A package.json that can't be parsed counts as CommonJS.
  • API: precompile(schema, { esm: true }).
  • Runtime helpers: ajv keeps require for its helpers even in ES module output. These are imported once with import schemaUtilsRuntime from "schema-utils/dist/runtime.js", and only when the check uses one. The .js extension is needed because schema-utils has no exports field, and Node.js won't resolve the path in an ES module without it.
  • No change to CommonJS output. Regenerating minimizer-webpack-plugin's check gives a byte-identical file.

Tests

  • The generated ES module imports the runtime and has no require or module.exports. When no helper is used, there's no import.
  • A check is written next to a "type": "module" package.json, symlinked to this package, and imported by a real Node.js process. This runs on Node.js 14+. It caught the missing .js extension, which would have broken every ES module check that uses a helper.
  • The CLI writes an ES module under "type": "module", CommonJS under "type": "commonjs" in the same run, and CommonJS when package.json can't be read.
  • I generated less-loader's real schema as an ES module and imported it natively. It accepts valid options and rejects invalid ones.

npm run lint and the full suite (1038 tests) pass. Coverage is 100% statements in cli.js and 98.9% in precompile.js.


Generated by Claude Code

Summary by CodeRabbit

  • New Features
    • Generated schema checks can now use ES modules. The precompile API offers an esm option to select the output format; without it, output remains CommonJS.
    • The CLI automatically generates ES modules when the nearest package.json sets "type": "module"; otherwise, it generates CommonJS, including when the package configuration is missing or invalid.
  • Documentation
    • Updated precompilation documentation to describe the output formats and the new esm option.

A check written as CommonJS cannot be loaded from a package with
"type": "module" (less-loader, sass-loader, stylus-loader).
`schema-utils precompile` now writes an ES module there, the way
Node.js reads a .js file, and `precompile` takes an `esm` option.

ajv keeps `require` for its runtime helpers in an ES module, so they
are imported from `schema-utils/dist/runtime.js`, with the extension
Node.js needs in a package without an `exports` field. CommonJS output
is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYPkbvwyRWt2SHgXDoYRdo
@coderabbitai

coderabbitai Bot commented Oct 18, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f9f3b576-d88e-4d56-bf32-da2e51fcf123
📥 Commits

Reviewing files that changed from the base of the PR and between 919e95d and e376425.

📒 Files selected for processing: 1
  • src/cli.js
🚧 Files skipped from review as they are similar to previous changes: 1
  • src/cli.js

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 0 remain after this review.

Walkthrough

precompile now supports ES module output through an optional esm setting. The CLI selects the output format from the nearest package.json. Tests cover generated ES module output, validator execution, and CLI behavior for module, CommonJS, and malformed package files.

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to e3764

No actionable merge-blocking issue is established; the change is mergeable after normal checks.

Pre-merge checks: Passed 5
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: adding ES module output for precompiled schemas in packages with "type": "module".
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 4 files.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 03dda01a-a489-41b9-a5ef-ae26e667c820
📥 Commits

Reviewing files that changed from the base of the PR and between a6e125a and 919e95d.

📒 Files selected for processing: 6
  • .changeset/precompile-esm.md
  • README.md
  • declarations/precompile.d.ts
  • src/cli.js
  • src/precompile.js
  • test/precompile.test.js

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.

Comment thread src/cli.js
@codecov

codecov Bot commented Oct 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.17%. Comparing base (a6e125a) to head (e376425).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #233      +/-   ##
==========================================
+ Coverage   97.11%   97.17%   +0.05%     
==========================================
  Files          13       13              
  Lines        1180     1204      +24     
  Branches      458      466       +8     
==========================================
+ Hits         1146     1170      +24     
  Misses         32       32              
  Partials        2        2              
Flag Coverage Δ
integration 97.17% <100.00%> (+0.05%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@alexander-akait
alexander-akait merged commit d2a27ef into main Oct 18, 2026
33 checks passed
@alexander-akait
alexander-akait deleted the feat/precompile-esm branch October 18, 2026 18:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant