feat: validate the options from webpack's validate hook - #313
Merged
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
webpack 5.106 added
compiler.hooks.validate, and webpack's own plugins —BannerPlugin,IgnorePlugin,ProgressPlugin,SourceMapDevToolPluginand the rest — tap it to check their options throughcompiler.validate. The plugin validated in its constructor instead, which meant it could not honour the one thing the hook exists for:compiler.validatereturns immediately whencompiler.options.validate === false, so the user'svalidate: falsenow turns the plugin's schema check off along with webpack's.Both schema passes move together — the plugin schema and the per-entry one merged with the adapter's.
One thing the change forced.
applyruns beforehooks.validate.call(), so resolving each check eagerly inapplymeant normalization reached a rejected value first:{ use: "eslint", extensions: 42 }threwTypeError: extension.replace is not a functionrather 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:
validatedefaultvalidate: false{}options misses the property 'checks'{ checks: [] }options.checks should be a non-empty array{ checks: [{ use: "eslint", extensions: 42 }] }options.checks[0].extensions should be one of theseSchema errors now arrive from
webpack()rather than fromnew DiagnosticsPlugin(). An unknownuse, and an adapter withoutname/create, still throw at construction — the schema cannot express either, so they are not validation.peerDependenciesstays atwebpack: ^5.0.0. Where the hook is absent the plugin validates fromapplyexactly as before, throughschema-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: falseskipping both a structural and a value error, and — with a stub compiler carrying novalidatehook — the pre-5.106 path validating fromapply. 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.jsandsrc/options.jsare 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
## Optionssaying where validation runs and thatvalidate: falsecovers 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.validateandcompiler.validate, made the change, and caught thatapplyrunning before the hook turned a schema error into aTypeError— 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