Skip to content

feat: validate the options from webpack's validate hook - #313

Merged
alexander-akait merged 1 commit into
mainfrom
feat/validate-hook
Sep 7, 2026
Merged

feat: validate the options from webpack's validate hook#313
alexander-akait merged 1 commit into
mainfrom
feat/validate-hook

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

Summary

webpack 5.106 added compiler.hooks.validate, and webpack's own plugins — BannerPlugin, IgnorePlugin, ProgressPlugin, SourceMapDevToolPlugin and the rest — tap it to check their options through compiler.validate. The plugin validated in its constructor instead, which meant it could not honour the one thing the hook exists for: compiler.validate returns immediately when compiler.options.validate === false, so the user's validate: false now turns the plugin's schema check off along with webpack's.

compiler.hooks.validate.tap(this.key, () => {
  validateOptions(compiler, this.given, this.options.checks);
});

Both schema passes move together — the plugin schema and the per-entry one merged with the adapter's.

One thing the change forced. apply runs before hooks.validate.call(), so resolving each check eagerly in apply meant normalization reached a rejected value first: { use: "eslint", extensions: 42 } threw TypeError: extension.replace is not a function rather than naming the option. Resolution is now deferred to the first build, past the hook, and the schema message is what surfaces.

Behaviour, measured on all four combinations:

options validate default validate: false
{} options misses the property 'checks' builds
{ checks: [] } options.checks should be a non-empty array builds
{ checks: [{ use: "eslint", extensions: 42 }] } options.checks[0].extensions should be one of these builds
valid builds builds

Schema errors now arrive from webpack() rather than from new DiagnosticsPlugin(). An unknown use, and an adapter without name/create, still throw at construction — the schema cannot express either, so they are not validation.

peerDependencies stays at webpack: ^5.0.0. Where the hook is absent the plugin validates from apply exactly as before, through schema-utils — 5.106 is a few weeks old and requiring it would be a steep toll for a lint plugin.

What kind of change does this PR introduce?

feat.

Did you add tests for your changes?

Yes, three in test/unified/unified.test.js: the rejected option value, validate: false skipping both a structural and a value error, and — with a stub compiler carrying no validate hook — the pre-5.106 path validating from apply. That last one is the only cover the fallback branch can get, since CI runs webpack 5.110. The two existing cases move from construction to build time. 135 passing; src/index.js and src/options.js are both at 100% of lines.

Does this PR introduce a breaking change?

Not for a released version — nothing has shipped under this name. Worth noting in review that anyone who caught a constructor throw would now catch it from webpack() instead.

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

A line under ## Options saying where validation runs and that validate: false covers it. The changeset is a minor.

Use of AI

Written with Claude Code, driven interactively. I pointed out webpack has a hook for this; Claude found compiler.hooks.validate and compiler.validate, made the change, and caught that apply running before the hook turned a schema error into a TypeError — which is why check resolution is deferred. I reviewed the result.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GzZci4NQeiqwdrVfd7dGXy


Generated by Claude Code

webpack 5.106 added `compiler.hooks.validate`, and its own plugins tap it to
check their options through `compiler.validate`. Doing the same puts the
report where webpack reports the rest of the configuration, and honours
`validate: false`, which validating in the constructor could not.

Resolving each check moves to the first build, because `apply` runs before
the hook does: resolving eagerly meant a rejected option value crashed
normalization before validation could name it. Where webpack predates the
hook the plugin validates from `apply`, as it did before.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GzZci4NQeiqwdrVfd7dGXy
@alexander-akait
alexander-akait merged commit 12039d7 into main Sep 7, 2026
13 checks passed
@alexander-akait
alexander-akait deleted the feat/validate-hook branch September 7, 2026 17:01
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