Summary
Reduce avoidable output-size overhead from the WinRT interface implementation support introduced in #148, particularly repeated helpers emitted into every supported interface module.
The growth is largely an expected cost of the new functionality, not evidence of accidental full WinUI generation. This issue tracks generation efficiency rather than a correctness regression, and does not propose removing interface implementation support.
Motivation
A same-metadata comparison of v0.1.0-preview.21 and main at bcd0e832af18947051ee5177650392a5f3336ee4, following electron-on-windows-gallery's generation configuration, produced:
| Output |
preview.21 |
main |
Increase |
JavaScript .js |
4,263,692 B |
5,243,826 B |
980,134 B |
TypeScript .d.ts |
926,199 B |
1,177,338 B |
251,139 B |
.dynwinrt-js-types |
309,039 B |
395,431 B |
86,392 B |
.mjs and .json |
288,183 B |
292,560 B |
4,377 B |
| Total |
5,787,113 B |
7,109,155 B |
1,322,042 B (+22.8%) |
These are uncompressed file lengths, not compressed package size, allocated disk space, runtime memory, or native-addon size. The initial observation was approximately 2 MB; this controlled configuration reproduced 1.32 MB (1.26 MiB), not the full 2 MB. File count increased only from 1,312 to 1,324.
Directly identifiable newly emitted implementation blocks account for approximately 1.04 MB:
| Content |
Measured bytes |
| Identical helpers copied into 111 supported interface modules |
295,815 |
| Per-interface plans and delegate adapters |
132,772 |
| Supported implementation factory/dispatch methods |
348,895 |
| Throwing implementation stubs in 131 unsupported interfaces |
59,369 |
| Implementation-related TypeScript declaration blocks |
205,363 |
The helper block is 2,665 bytes per interface and contains __implementationCheck, Field, Array, Reference, Sync, and Handler. Keeping one shared copy would eliminate approximately 293 KB of repeated text before accounting for shared-module and import overhead. The per-interface plans and dispatch code represent additional functionality and cannot simply be deduplicated the same way.
Applications that only call existing Windows APIs still receive the implementation support in their generated interface modules. Other changes also contribute: six additional IMap JS/declaration pairs occupy 70,746 bytes, and the type manifest and imports grow. These figures overlap the implementation-block accounting and should not be added as independent categories.
Relevant source:
Component
dynwinrt-codegen (code generator)
Basic Example
Reproduction configuration:
- WinAppSDK 2.2.0, using its component metadata: Foundation 2.1.0, AI 2.2.3, Widgets 2.0.5, and MachineLearning 2.1.70.
- Windows SDK CPP 10.0.28000.1839 metadata for references.
- Follow the WinApp CLI 0.5.0 policy: Windows SDK CPP, InteractiveExperiences 2.0.15, and WinUI 2.2.1 are reference-only; WebView2 is excluded. Use public metadata paths, not private runtime metadata.
- Bulk-generate the 32 public non-UI WinAppSDK metadata files using
generate --winmd-list <emit-list> --ref-list <ref-list> --output <output>.
- Into the same output, cherry-pick
Windows.ApplicationModel.LimitedAccessFeatures, Windows.Storage.StorageFile, and Windows.Graphics.Imaging.BitmapDecoder, keeping the same metadata available as references.
- Repeat with each generator in a separate fresh output directory, then sum file lengths and compare relative paths.
For example, IStorageFolderQueryOperations.js grew from 21,078 to 46,334 bytes, and ILanguageModel2.js from 27,517 to 50,559 bytes. Most growth is inside existing interface files.
Potential implementation directions, not yet a decided API design:
- Extract the common implementation helpers into one generated internal support module.
- Consider demand-driven helper emission and a more compact representation for unsupported-interface errors without weakening fail-closed behavior.
- Evaluate an optional call-only generation mode or separate implementation entrypoints for consumers that do not implement WinRT interfaces, while preserving existing behavior by default.
Preserve CJS/ESM behavior, custom runtime import names, lazy loading/import-cycle behavior, synchronous handler validation, conversion contracts, and ownership/release semantics. Measure output-size changes using a fixed metadata fixture; do not trade correctness checks for size.
Open Questions
- Should common helpers live in a generated internal module or in a versioned runtime subpath?
- Is a separate implementation entrypoint or explicit call-only option worthwhile beyond helper deduplication?
- How can unsupported-interface diagnostics remain explicit without repeating long error strings and declarations?
- What stable metadata fixture and size budget should guard against future unintentional generated-output growth?
No production code was changed during this investigation.
Summary
Reduce avoidable output-size overhead from the WinRT interface implementation support introduced in #148, particularly repeated helpers emitted into every supported interface module.
The growth is largely an expected cost of the new functionality, not evidence of accidental full WinUI generation. This issue tracks generation efficiency rather than a correctness regression, and does not propose removing interface implementation support.
Motivation
A same-metadata comparison of
v0.1.0-preview.21and main atbcd0e832af18947051ee5177650392a5f3336ee4, following electron-on-windows-gallery's generation configuration, produced:.js.d.ts.dynwinrt-js-types.mjsand.jsonThese are uncompressed file lengths, not compressed package size, allocated disk space, runtime memory, or native-addon size. The initial observation was approximately 2 MB; this controlled configuration reproduced 1.32 MB (1.26 MiB), not the full 2 MB. File count increased only from 1,312 to 1,324.
Directly identifiable newly emitted implementation blocks account for approximately 1.04 MB:
The helper block is 2,665 bytes per interface and contains
__implementationCheck,Field,Array,Reference,Sync, andHandler. Keeping one shared copy would eliminate approximately 293 KB of repeated text before accounting for shared-module and import overhead. The per-interface plans and dispatch code represent additional functionality and cannot simply be deduplicated the same way.Applications that only call existing Windows APIs still receive the implementation support in their generated interface modules. Other changes also contribute: six additional
IMapJS/declaration pairs occupy 70,746 bytes, and the type manifest and imports grow. These figures overlap the implementation-block accounting and should not be added as independent categories.Relevant source:
project_validatedinitializes every supported interface's support code withString::from(HELPERS).Component
dynwinrt-codegen (code generator)
Basic Example
Reproduction configuration:
generate --winmd-list <emit-list> --ref-list <ref-list> --output <output>.Windows.ApplicationModel.LimitedAccessFeatures,Windows.Storage.StorageFile, andWindows.Graphics.Imaging.BitmapDecoder, keeping the same metadata available as references.For example,
IStorageFolderQueryOperations.jsgrew from 21,078 to 46,334 bytes, andILanguageModel2.jsfrom 27,517 to 50,559 bytes. Most growth is inside existing interface files.Potential implementation directions, not yet a decided API design:
Preserve CJS/ESM behavior, custom runtime import names, lazy loading/import-cycle behavior, synchronous handler validation, conversion contracts, and ownership/release semantics. Measure output-size changes using a fixed metadata fixture; do not trade correctness checks for size.
Open Questions
No production code was changed during this investigation.