Skip to content

feat: load minimizers by module path in workers - #744

Merged
alexander-akait merged 8 commits into
mainfrom
feat/worker-minimizer-module-paths
Sep 21, 2026
Merged

alexander-akait merged 8 commits into
mainfrom
feat/worker-minimizer-module-paths

Conversation

@alexander-akait

@alexander-akait alexander-akait commented Sep 19, 2026

Copy link
Copy Markdown
Member

Summary

@xiaoxiaojx's #732, brought up to main and finished. Their commit is carried through as theirs; #732 can be closed in favour of this.

A minimizer may now be named by module path — a string, or { path, export } for a named export, the way sass-loader takes its implementation — and the default terser is named that way. A worker then requires it, instead of being handed its source and rebuilding it with new Function, and the helpers a function carries (getTypes, filter, …) survive the crossing rather than being shipped alongside as data.

The saving is per task, so it needs everything that task carries to be transferable. One minimizer written as a function anywhere in the list keeps the whole task on the source path, and so does a function anywhere in the payload — an extractComments callback, or a minimizer's own options holding one — because a required minimizer is handed the payload as it is and a structured clone throws on a function. Without that second rule the default configuration plus extractComments: (astNode, comment) => … fails the build with … could not be cloned.

Generators stay callable-only: nothing requires one in a worker, and the schema takes no module path for one, so the types no longer accept what validation would reject.

What kind of change does this PR introduce?

feat.

Did you add tests for your changes?

Yes. #732 brought test/implementation.test.js and the worker-dispatch cases in test/parallel-option.test.js; this adds the three that were missing — a mixed path-and-function list falling back to transform, a function extractComments doing the same, and a minimizer whose own options hold a function. 744 green.

Does this PR introduce a breaking change?

No. minify keeps taking a function, and every configuration that worked keeps working; what changes is how the default reaches a worker.

If relevant, what needs to be documented once your changes are merged or what have you already documented?

Documented here: the module-path form in the minify section, what forfeits it, and a changeset.

Use of AI

Claude Code was used to bring the branch to main, resolve the conflicts and fix what review found. The clone failure was confirmed by running the default configuration with a function extractComments under parallel: true before and after.


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Minimizers now support module paths and { path, export } references, including named and default exports.
    • Compatible configurations use worker-based minification, while function-based configurations remain supported.
    • Cache handling distinguishes outputs from different minimizer references.
  • Documentation

    • Added guidance for module-based minimizers and worker execution requirements.
  • Type Support

    • Updated schemas and TypeScript declarations for module-path minimizer configurations.

xiaoxiaojx and others added 4 commits September 9, 2026 14:31
The default minimizer is named by module path, the minimizer loop reads the slots this branch introduced, and both hash guards ask the slots how many there are.
Plus the case the test plan left open: one function among several paths leaves the whole task on the source path.
A required minimizer is handed the payload as it is, so an extractComments callback or a function in a minimizer's own options died as could not be cloned; generators stay callable-only, which is all the schema takes.
@changeset-bot

changeset-bot Bot commented Sep 19, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 86c83d3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
minimizer-webpack-plugin Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

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: 7fd996bc-53da-4cbb-b2a4-793a0b448a33

📥 Commits

Reviewing files that changed from the base of the PR and between c557b38 and 86c83d3.

📒 Files selected for processing (4)
  • src/implementation.js
  • src/index.js
  • test/minify-option.test.js
  • types/implementation.d.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/implementation.js
  • types/implementation.d.ts
  • test/minify-option.test.js
  • src/index.js

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.


Walkthrough

The plugin now accepts minimizer functions, module-path strings, and { path, export } references. Workers load referenced implementations directly and use minify when all relevant implementations and options are path-serializable. Configurations containing functions use transform. Minimizer slots preserve configured references and loaded functions for matching, embedded processing, capability checks, and version hashing. Schemas, declarations, documentation, fixtures, and tests were updated.

Priority: ➖ Normal

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
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 primary change: loading minimizers by module path in workers.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 13 functions across 16 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

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/implementation.js

ESLint failed to execute (timeout).

src/index.js

ESLint skipped: the matched ESLint configuration already failed (timeout).

test/minify-option.test.js

ESLint skipped: the matched ESLint configuration already failed (timeout).

  • 1 others

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: 2

Caution

Some comments are outside the diff and can’t be posted inline due to GitHub limitations.

⚠️ Outside diff range comments (1)

🟠 Major · Use loaded minimizer functions for all helper checks. · index.js:1927-1928

src/index.js:1927-1928
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use loaded minimizer functions for all helper checks.

Module reference objects do not expose the helper methods from their loaded exports. The remaining raw-reference checks ignore supported helper behavior.

  • src/index.js#L1927-L1928: pass the corresponding loaded slot function to declaredStage so path minimizers run at their declared stage.
  • src/index.js#L1540-L1544: pass loaded slot functions to declaredFlags so stats register the flags that optimization writes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: ce9187e8-0571-4e10-a734-eace277bc167

📥 Commits

Reviewing files that changed from the base of the PR and between 1cf49b0 and 2575275.

⛔ Files ignored due to path filters (2)
  • test/__snapshots__/parallel-option.test.js.snap is excluded by !**/*.snap
  • test/__snapshots__/validate-options.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (14)
  • .changeset/worker-implementation-path.md
  • README.md
  • src/implementation.js
  • src/index.js
  • src/minify.js
  • src/options.json
  • test/extractComments-option.test.js
  • test/fixtures/minify-default-export.js
  • test/fixtures/minify-default-property.js
  • test/implementation.test.js
  • test/parallel-option.test.js
  • types/implementation.d.ts
  • types/index.d.ts
  • types/minify.d.ts

Included review availability: Your plan provides up to 4 included reviews per hour; 1 remains after this review.

Comment thread src/implementation.js
Comment thread src/index.js Outdated
xiaoxiaojx
xiaoxiaojx previously approved these changes Sep 20, 2026
@xiaoxiaojx

Copy link
Copy Markdown
Member

My original thinking was: if the user passes an implementation, that also means the options and the rest of the payload have to be serializable. If they aren't, throwing is the expected behavior, and the user can change what they pass. What I'm weighing now is whether to fall back silently or throw, so the user can see that the options conflict. Maybe when canMinifyByPath returns false, we should throw and say why it was refused.

The helpers are on the loaded function, so a module reference ran at the default stage and its flag never reached stats; and two paths reporting no version shared one cache entry.
@codecov

codecov Bot commented Sep 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 99.24242% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 97.79%. Comparing base (1cf49b0) to head (86c83d3).

Files with missing lines Patch % Lines
src/implementation.js 98.48% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #744      +/-   ##
==========================================
+ Coverage   97.75%   97.79%   +0.04%     
==========================================
  Files           4        5       +1     
  Lines        1557     1634      +77     
  Branches      588      620      +32     
==========================================
+ Hits         1522     1598      +76     
- Misses         35       36       +1     

☔ 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.

The default minimizer is named by module path, so salting chunk hashes with it made every emitted file depend on where the checkout sits. The path now reaches the cache identity alone.

@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: f6c9610a-c15e-4c79-b492-e5b434552597

📥 Commits

Reviewing files that changed from the base of the PR and between a102dd0 and 51f787f.

📒 Files selected for processing (2)
  • src/index.js
  • test/minify-option.test.js

Included review availability: Your plan provides up to 4 included reviews per hour; 3 remain after this review.

Comment thread src/index.js Outdated
Comment on lines +2454 to +2463
.update(
getSerializeJavascript()(
Array.isArray(this.options.minimizer.implementation)
? this.options.minimizer.implementation.map(getModuleRef)
: getModuleRef(
/** @type {MinimizerImplementationValue<EXPECTED_ANY>} */
(this.options.minimizer.implementation),
),
),
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '1900,2060p' src/index.js
sed -n '2390,2605p' src/index.js
rg -n -C 6 'renderEmbeddedSource|variesOn|embeddedSourceHash|cacheSuffix|identity' src/index.js

Repository: webpack/minimizer-webpack-plugin

Length of output: 29109


Include module references in the embedded-source cache key.

renderEmbeddedSource() uses data as its cache variation input. data contains minimizer versions and options, but not module references. identity contains the module references, but it only reaches asset optimization through cacheSuffix. With filesystem caching, two module-path minimizers with matching versions and options can therefore reuse the same embedded-source cache entry. Pass an identity-based source to renderEmbeddedSource(), and keep data for embeddedSourceHash.

…checkout

Its path is read against the compiler context, so two modules reporting no version are two identities while one module hashes the same wherever it was cloned. A `Map` or `Set` holding a function keeps the task on the source path, which `Object.values` never saw.

@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: 113c2225-9804-495c-991e-3b4c524cf603

📥 Commits

Reviewing files that changed from the base of the PR and between 51f787f and c557b38.

⛔ Files ignored due to path filters (2)
  • test/__snapshots__/MinimizerPlugin.test.js.snap is excluded by !**/*.snap
  • test/__snapshots__/test-option.test.js.snap is excluded by !**/*.snap
📒 Files selected for processing (7)
  • src/implementation.js
  • src/index.js
  • test/embedded-source.test.js
  • test/fixtures/embedded/css-says-one.js
  • test/fixtures/embedded/css-says-two.js
  • test/implementation.test.js
  • test/minify-option.test.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • test/implementation.test.js
  • src/implementation.js

Included review availability: Your plan provides up to 4 included reviews per hour; 2 remain after this review.

Comment thread src/index.js
A bare specifier and a file of that name contextify alike while `require` reaches two different modules, so the identity is taken from what would be loaded.
@alexander-akait
alexander-akait merged commit c8c4bf2 into main Sep 21, 2026
31 checks passed
@alexander-akait
alexander-akait deleted the feat/worker-minimizer-module-paths branch September 21, 2026 06:00
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.

2 participants