Skip to content

fix: improve types for NormalModule#20721

Open
alexander-akait wants to merge 1 commit into
mainfrom
refactor-types-improve-templates-for-normal-module
Open

fix: improve types for NormalModule#20721
alexander-akait wants to merge 1 commit into
mainfrom
refactor-types-improve-templates-for-normal-module

Conversation

@alexander-akait
Copy link
Copy Markdown
Member

Summary

this is a part of future improvement when we will have right parser and parser options, generator and generator options in parse/generate step (and so the right module), also it will help in future AssetModule/JsonModule and etc improvements

Also in future we will split builtMeta and builtInfo by module types, now we store all properties into two types, but for example js module will never have css related properties

What kind of change does this PR introduce?

fix

Did you add tests for your changes?

Existing

Does this PR introduce a breaking change?

No

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

Noting

Use of AI

No

Copilot AI review requested due to automatic review settings March 27, 2026 14:33
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 27, 2026

⚠️ No Changeset found

Latest commit: c7da642

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

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

@github-actions
Copy link
Copy Markdown
Contributor

This PR is packaged and the instant preview is available (c7da642).

Install it locally:

  • npm
npm i -D webpack@https://pkg.pr.new/webpack@c7da642
  • yarn
yarn add -D webpack@https://pkg.pr.new/webpack@c7da642
  • pnpm
pnpm add -D webpack@https://pkg.pr.new/webpack@c7da642

@github-actions
Copy link
Copy Markdown
Contributor

Types Coverage

Coverage after merging refactor-types-improve-templates-for-normal-module into main will be
98.94%
Coverage Report
FileStmtsBranchesFuncsLinesUncovered Lines
bin
   webpack.js98.77%100%100%98.77%91
examples
   build-common.js100%100%100%100%
   buildAll.js100%100%100%100%
   examples.js100%100%100%100%
   template-common.js98.21%100%100%98.21%72
examples/custom-javascript-parser
   test.filter.js100%100%100%100%
examples/custom-javascript-parser/internals
   acorn-parse.js100%100%100%100%
   meriyah-parse.js100%100%100%100%
   oxc-parse.js91.30%100%100%91.30%140, 142–143, 145, 147, 153–154, 161, 168, 90
examples/markdown
   webpack.config.mjs100%100%100%100%
examples/typescript
   test.filter.js50%100%100%50%5
examples/virtual-modules
   test.filter.js100%100%100%100%
examples/wasm-bindgen-esm
   test.filter.js100%100%100%100%
examples/wasm-complex
   test.filter.js100%100%100%100%
examples/wasm-simple
   test.filter.js100%100%100%100%
lib
   APIPlugin.js100%100%100%100%
   AbstractMethodError.js100%100%100%100%
   AsyncDependenciesBlock.js100%100%100%100%
   AsyncDependencyToInitialChunkError.js100%100%100%100%
   AutomaticPrefetchPlugin.js100%100%100%100%
   BannerPlugin.js100%100%100%100%
   Cache.js98.21%100%100%98.21%87
   CacheFacade.js100%100%100%100%
   CaseSensitiveModulesWarning.js100%100%100%100%
   Chunk.js99.72%100%100%99.72%37
   ChunkGraph.js100%100%100%100%
   ChunkGroup.js100%100%100%100%
   ChunkRenderError.js100%100%100%100%
   ChunkTemplate.js100%100%100%100%
   CleanPlugin.js98.72%100%100%98.72%196, 216, 371
   CodeGenerationError.js100%100%100%100%
   CodeGenerationResults.js100%100%100%100%
   CommentCompilationWarning.js100%100%100%100%
   CompatibilityPlugin.js100%100%100%100%
   Compilation.js98.54%100%100%98.54%1511, 1800, 1807, 1815, 1837, 2713, 3131, 3779, 3808, 3860–3861, 3865, 3870, 3886–3887, 3901–3902, 3907–3908, 4370, 4396, 470, 475, 5079, 5159, 5174, 5199–5200, 5202, 5518, 5523, 5529, 5532, 5544, 5546, 5550, 5566, 5581, 5612, 5666, 5690, 5800, 681–682
   Compiler.js99.56%100%100%99.56%1091–1092, 1100
   ConcatenationScope.js98.59%100%100%98.59%166
   ConcurrentCompilationError.js100%100%100%100%
   ConditionalInitFragment.js100%100%100%100%
   ConstPlugin.js100%100%100%100%
   ContextExclusionPlugin.js100%100%100%100%
   ContextModule.js100%100%100%100%
   ContextModuleFactory.js97.75%100%100%97.75%253, 385, 410, 435, 439, 450
   ContextReplacementPlugin.js100%100%100%100%
   CssModule.js81.32%100%100%81.32%172, 177–192
   DefinePlugin.js98.92%100%100%98.92%153–154, 170, 189, 263
   DelegatedModule.js95.24%100%100%95.24%240–244
   DelegatedModuleFactoryPlugin.js98.15%100%100%98.15%103
   DelegatedPlugin.js100%100%100%100%
   DependenciesBlock.js100%100%100%100%
   Dependency.js98.13%100%100%98.13%351, 381
   DependencyTemplate.js100%100%100%100%
   DependencyTemplates.js100%100%100%100%
   DllEntryPlugin.js100%100%100%100%
   DllModule.js100%100%100%100%
   DllModuleFactory.js100%100%100%100%
   DllPlugin.js100%100%100%100%
   DllReferencePlugin.js100%100%100%100%
   DotenvPlugin.js97.88%100%100%97.88%235, 375, 388–389
   DynamicEntryPlugin.js100%100%100%100%
   EntryOptionPlugin.js100%100%100%100%
   EntryPlugin.js100%100%100%100%
   Entrypoint.js100%100%100%100%
   EnvironmentNotSupportAsyncWarning.js100%100%100%100%
   EnvironmentPlugin.js97.14%100%100%97.14%48
   ErrorHelpers.js100%100%100%100%
   EvalDevToolModulePlugin.js100%100%100%100%
   EvalSourceMapDevToolPlugin.js100%100%100%100%
   ExportsInfo.js100%100%100%100%
   ExportsInfoApiPlugin.js100%100%100%100%
   ExternalModule.js98.89%100%100%98.89%385–389, 526
   ExternalModuleFactoryPlugin.js100%100%100%100%
   ExternalsPlugin.js100%100%100%100%
   FalseIIFEUmdWarning.js100%100%100%100%
   FileSystemInfo.js99.49%100%100%99.49%168, 2142–2143, 2146, 2157, 2168, 2179, 261, 3497, 3512, 3536
   FlagAllModulesAsUsedPlugin.js100%100%100%100%
   FlagDependencyExportsPlugin.js98.74%100%100%98.74%396, 398, 402
   FlagDependencyUsagePlugin.js100%100%100%100%
   FlagEntryExportAsUsedPlugin.js100%100%100%100%
   Generator.js100%100%100%100%
   GraphHelpers.js100%100%100%100%
   HarmonyLinkingError.js100%100%100%100%
   HookWebpackError.js100%100%100%100%
   HotModuleReplacementPlugin.js100%100%100%100%
   HotUpdateChunk.js100%100%100%100%
   IgnoreErrorModuleFactory.js100%100%100%100%
   IgnorePlugin.js100%100%100%100%
   IgnoreWarningsPlugin.js100%100%100%100%
   InitFragment.js100%100%100%100%
   InvalidDependenciesModuleWarning.js100%100%100%100%
   JavascriptMetaInfoPlugin.js100%100%100%100%
   LibManifestPlugin.js97.14%100%100%97.14%114, 117
   LibraryTemplatePlugin.js100%100%100%100%
   LoaderOptionsPlugin.js100%100%100%100%
   LoaderTargetPlugin.js100%100%100%100%
   MainTemplate.js100%100%100%100%
   ManifestPlugin.js100%100%100%100%
   Module.js98.50%100%100%98.50%1186, 1191, 1249, 1262, 1319, 1327
   ModuleBuildError.js100%100%100%100%
   ModuleDependencyError.js100%100%100%100%
   ModuleDependencyWarning.js100%100%100%100%
   ModuleError.js100%100%100%100%
   ModuleFactory.js100%100%100%100%
   ModuleFilenameHelpers.js98.85%100%100%98.85%105, 107
   ModuleGraph.js99.73%100%100%99.73%942
   ModuleGraphConnection.js100%100%100%100%
   ModuleHashingError.js100%100%100%100%
   ModuleInfoHeaderPlugin.js100%100%100%100%
   ModuleNotFoundError.js100%100%100%100%
   ModuleParseError.js100%100%100%100%
   ModuleProfile.js100%100%100%100%
   ModuleRestoreError.js100%100%100%100%
   ModuleSourceTypeConstants.js100%100%100%100%
   ModuleStoreError.js100%100%100%100%
   ModuleTemplate.js100%100%100%100%
   ModuleTypeConstants.js100%100%100%100%
   ModuleWarning.js100%100%100%100%
   MultiCompiler.js99.69%100%100%99.69%619
   MultiStats.js100%100%100%100%
   MultiWatching.js100%100%100%100%
   NoEmitOnErrorsPlugin.js100%100%100%100%
   NoModeWarning.js100%100%100%100%
   NodeStuffInWebError.js100%100%100%100%
   NodeStuffPlugin.js100%100%100%100%
   NormalModule.js97.67%100%100%97.67%1013, 1047, 1063, 1150, 1779, 1784–1794, 1797, 214, 737, 755, 772
   NormalModuleFactory.js99.46%100%100%99.46%1032, 1337, 447, 459
   NormalModuleReplacementPlugin.js100%100%100%100%
   NullFactory.js100%100%100%100%
   OptimizationStages.js100%100%100%100%
   OptionsApply.js100%100%100%100%
   Parser.js100%100%100%100%
   PlatformPlugin.js100%100%100%100%
   PrefetchPlugin.js100%100%100%100%
   ProgressPlugin.js98.75%100%100%98.75%431–432, 437, 439, 503
   ProvidePlugin.js100%100%100%100%
   RawModule.js100%100%100%100%
   RecordIdsPlugin.js100%100%100%100%
   RequestShortener.js100%100%100%100%
   RequireJsStuffPlugin.js100%100%100%100%
   ResolverFactory.js100%100%100%100%
   RuntimeGlobals.js100%100%100%100%
   RuntimeModule.js100%100%100%100%
   RuntimePlugin.js100%100%100%100%
   RuntimeTemplate.js100%100%100%100%
   SelfModuleFactory.js100%100%100%100%
   SingleEntryPlugin.js100%100%100%100%
   SizeFormatHelpers.js100%100%100%100%
   SourceMapDevToolModuleOptionsPlugin.js100%100%100%100%
   SourceMapDevToolPlugin.js99.16%100%100%99.16%265–266, 608
   Stats.js100%100%100%100%
   Template.js100%100%100%100%
   TemplatedPathPlugin.js98.85%100%100%98.85%128–129
   UnhandledSchemeError.js100%100%100%100%
   UnsupportedFeatureWarning.js100%100%100%100%
   UseStrictPlugin.js100%100%100%100%
   WarnCaseSensitiveModulesPlugin.js100%100%100%100%
   WarnDeprecatedOptionPlugin.js100%100%100%100%
   WarnNoModeSetPlugin.js100%100%100%100%
   WatchIgnorePlugin.js100%100%100%100%
   Watching.js100%100%100%100%
   WebpackError.js96.97%100%100%96.97%43
   WebpackIsIncludedPlugin.js100%100%100%100%
   WebpackOptionsApply.js100%100%100%100%
   WebpackOptionsDefaulter.js100%100%100%100%
   buildChunkGraph.js99.87%100%100%99.87%317
   cli.js98.71%100%100%98.71%109, 453, 485, 527, 787
   formatLocation.js100%100%100%100%
   index.js100%100%100%100%
   validateSchema.js94.67%100%100%94.67%86, 88, 97, 99
   webpack.js97.22%100%100%97.22%186, 208, 210
lib/asset
   AssetBytesGenerator.js100%100%100%100%
   AssetBytesParser.js100%100%100%100%
   AssetGenerator.js100%100%100%100%
   AssetModulesPlugin.js97.77%100%100%97.77%282, 306, 309, 361, 39
   AssetParser.js100%100%100%100%
   AssetSourceGenerator.js100%100%100%100%
   AssetSourceParser.js100%100%100%100%
   RawDataUrlModule.js100%100%100%100%
lib/async-modules
   AsyncModuleHelpers.js100%100%100%100%
   AwaitDependenciesInitFragment.js100%100%100%100%
   InferAsyncModulesPlugin.js100%100%100%100%
lib/cache
   AddBuildDependenciesPlugin.js100%100%100%100%
   AddManagedPathsPlugin.js100%100%100%100%
   IdleFileCachePlugin.js97.92%100%100%97.92%70, 82, 90
   MemoryCachePlugin.js95.83%100%100%95.83%33
   MemoryWithGcCachePlugin.js93.15%100%100%93.15%104, 111–112, 120, 87
   PackFileCacheStrategy.js96.40%100%100%96.40%

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refines webpack’s type surface around NormalModule by introducing generics for parser/generator types and updating related APIs/hooks to reference the parameterized NormalModule, with the goal of enabling future module-type-specific typing improvements.

Changes:

  • Make NormalModule generic over parser/parserOptions and generator/generatorOptions, and thread that through many NormalModule-consuming type signatures.
  • Add JSDoc generics to NormalModuleFactory.getParser/createParser/getGenerator/createGenerator and adjust implementations with casts.
  • Specialize CssModule’s relationship to NormalModule with concrete parser/generator types (JS JSDoc + types.d.ts).

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 3 comments.

File Description
types.d.ts Introduces generic NormalModule and updates numerous signatures/hooks to use the parameterized form.
lib/NormalModuleFactory.js Adds JSDoc templates for parser/generator factory methods and returns typed casts.
lib/NormalModule.js Adds generics to NormalModule and its create-data typedef; updates internal casts accordingly.
lib/CssModule.js Adds typed @extends and create-data typing to bind CssModule to specific parser/generator types.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/NormalModule.js
Comment on lines +266 to +268
* @property {PO | undefined} parserOptions the options of the parser used
* @property {G} generator the generator used
* @property {GO | undefined} generatorOptions the options of the generator used
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

In the NormalModuleCreateData typedef, parserOptions/generatorOptions are modeled as {PO | undefined} and {GO | undefined} instead of being marked optional (e.g. {PO=} / {GO=} like other typedef object properties in this repo). This can force object literals to explicitly include these properties (often as undefined) under checkJs/strict and makes the typedef inconsistent with established optional-property JSDoc style here.

Suggested change
* @property {PO | undefined} parserOptions the options of the parser used
* @property {G} generator the generator used
* @property {GO | undefined} generatorOptions the options of the generator used
* @property {PO=} parserOptions the options of the parser used
* @property {G} generator the generator used
* @property {GO=} generatorOptions the options of the generator used

Copilot uses AI. Check for mistakes.
Comment thread lib/NormalModule.js
Comment on lines +578 to +589
this.parserOptions =
/** @type {PO} */
(unsafeCacheData.parserOptions);
this.parser =
/** @type {P} */
(normalModuleFactory.getParser(this.type, this.parserOptions));
this.generatorOptions =
/** @type {GO} */
(unsafeCacheData.generatorOptions);
this.generator =
/** @type {G} */
(normalModuleFactory.getGenerator(this.type, this.generatorOptions));
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

In _restoreFromUnsafeCache, the casts force unsafeCacheData.parserOptions/generatorOptions to PO/GO, but these values can be undefined (and the instance fields are typed as PO | undefined / GO | undefined). Casting to PO | undefined / GO | undefined keeps the JSDoc types accurate under checkJs/strict and avoids masking incorrect assumptions about these fields always being present.

Copilot uses AI. Check for mistakes.
Comment on lines 1359 to 1444
@@ -1376,21 +1377,24 @@ If changing the source code is not an option there is also a resolve options cal
cache.set(parserOptions, parser);
}

return parser;
return /** @type {P} */ (parser);
}

/**
* @template {Parser} [P=Parser]
* @param {string} type type
* @param {ParserOptions} parserOptions parser options
* @returns {Parser} parser
* @returns {P} parser
*/
createParser(type, parserOptions = {}) {
parserOptions = mergeGlobalOptions(
this._globalParserOptions,
type,
parserOptions
);
const parser = this.hooks.createParser.for(type).call(parserOptions);
const parser =
/** @type {P} */
(this.hooks.createParser.for(type).call(parserOptions));
if (!parser) {
throw new Error(`No parser registered for ${type}`);
}
@@ -1399,9 +1403,10 @@ If changing the source code is not an option there is also a resolve options cal
}

/**
* @template {Generator} [G=Generator]
* @param {string} type type of generator
* @param {GeneratorOptions} generatorOptions generator options
* @returns {Generator} generator
* @returns {G} generator
*/
getGenerator(type, generatorOptions = EMPTY_GENERATOR_OPTIONS) {
let cache = this.generatorCache.get(type);
@@ -1418,23 +1423,24 @@ If changing the source code is not an option there is also a resolve options cal
cache.set(generatorOptions, generator);
}

return generator;
return /** @type {G} */ (generator);
}

/**
* @template {Generator} [G=Generator]
* @param {string} type type of generator
* @param {GeneratorOptions} generatorOptions generator options
* @returns {Generator} generator
* @returns {G} generator
*/
createGenerator(type, generatorOptions = {}) {
generatorOptions = mergeGlobalOptions(
this._globalGeneratorOptions,
type,
generatorOptions
);
const generator = this.hooks.createGenerator
.for(type)
.call(generatorOptions);
const generator =
/** @type {G} */
(this.hooks.createGenerator.for(type).call(generatorOptions));
if (!generator) {
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

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

The @template-based return typing for getParser/createParser and getGenerator/createGenerator lets callers pick an arbitrary subtype for P/G, but the runtime selection is based only on the type string. This is effectively a typed cast and can hide real type mismatches (e.g., requesting CssParser for a JS module type). Consider returning the base Parser/Generator types here (or deriving the generic from type via a mapping) rather than letting callers specify it freely.

Copilot uses AI. Check for mistakes.
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 27, 2026

Merging this PR will degrade performance by 31.73%

⚡ 1 improved benchmark
❌ 2 regressed benchmarks
✅ 141 untouched benchmarks

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development-rebuild","mode":"development","watch":true}' 264.4 KB 387.2 KB -31.73%
Memory benchmark "lodash", scenario '{"name":"mode-development","mode":"development"}' 4.1 MB 5.3 MB -22.63%
Memory benchmark "asset-modules-source", scenario '{"name":"mode-development","mode":"development"}' 934.6 KB 502.4 KB +86.01%

Comparing refactor-types-improve-templates-for-normal-module (c7da642) with main (5e7dc11)

Open in CodSpeed

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