feat: make IgniteUI.Blazor.Lite trim-compatible - #359
Open
damyanpetev wants to merge 8 commits into
Open
Conversation
Comment on lines
+452
to
+470
| foreach (var f in enumType.GetFields()) | ||
| { | ||
| if (f.IsPublic && !f.IsSpecialName) | ||
| { | ||
| foreach (var attr in f.GetCustomAttributes(true)) | ||
| { | ||
| if (attr.GetType().Name == "WCEnumNameAttribute") | ||
| { | ||
| if (wcEnumTransform == null) | ||
| { | ||
| wcEnumTransform = new Dictionary<string, string>(); | ||
| } | ||
| var wc = (WCEnumNameAttribute)attr; | ||
| var wcEnumName = Camelize(wc.Name); | ||
| wcEnumTransform.Add(f.Name.ToLower(), wcEnumName); | ||
| } | ||
| } | ||
| } | ||
| } |
Comment on lines
+456
to
+468
| foreach (var attr in f.GetCustomAttributes(true)) | ||
| { | ||
| if (attr.GetType().Name == "WCEnumNameAttribute") | ||
| { | ||
| if (wcEnumTransform == null) | ||
| { | ||
| wcEnumTransform = new Dictionary<string, string>(); | ||
| } | ||
| var wc = (WCEnumNameAttribute)attr; | ||
| var wcEnumName = Camelize(wc.Name); | ||
| wcEnumTransform.Add(f.Name.ToLower(), wcEnumName); | ||
| } | ||
| } |
damyanpetev
force-pushed
the
dpetev/trimmable
branch
from
August 21, 2026 15:39
40f6ca4 to
018b664
Compare
damyanpetev
force-pushed
the
dpetev/trimmable
branch
from
August 27, 2026 08:13
219f679 to
e32b65d
Compare
damyanpetev
force-pushed
the
dpetev/trimmable
branch
from
August 27, 2026 08:59
e32b65d to
f72cb76
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes IgniteUI.Blazor.Lite safe to consume from trimmed Blazor WebAssembly publishes by eliminating (or narrowly suppressing with justification) ILLink/trim-analyzer warnings. It introduces trim-safe JSON interop via System.Text.Json source generation, adds a trim-safe mechanism for Type-based module preloading, and adds docs + automated publish-smoke browser checks to prevent regressions.
Changes:
- Switch JSON interop to source-generated
JsonTypeInfoviaIgbJsonContext, updatingBaseRendererControlto use typedJsonSerializeroverloads. - Introduce trim-safe module preloading via new
IIgbModule+ self-referencing[IgbModule<TSelf>], and apply it across*Moduletypes. - Add trimming docs and regression guards:
.editorconfiganalyzer gates, publish-smoke app, and Playwright-based trimmed publish integration test.
Reviewed changes
Copilot reviewed 104 out of 104 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| tests/IgniteUI.Blazor.Tests/ServiceRegistrationTests.cs | Adds drift-guard test ensuring every module has a self-referencing [IgbModule<TSelf>]. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/wwwroot/index.html | Adds minimal WASM smoke app host page referencing Ignite UI static assets. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/README.md | Documents why/when/how to verify trimming via publish + browser checklist. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/Properties/launchSettings.json | Adds dev launch profile for the publish-smoke app. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/Program.cs | Registers Ignite UI + modules and exercises Type-based module preloading under trimming. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/IgniteUI.Blazor.Lite.PublishSmoke.csproj | Adds multi-TFM WASM app configured to fail publish on any ILLink warnings. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/App.razor | Implements in-app UI checks for enums, data-source reflection, module preload, and event payloads. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/_Imports.razor | Adds imports required by the smoke app (incl. trimming annotations). |
| tests/IgniteUI.Blazor.Lite.IntegrationTests/TrimmedPublishSmokeTest.cs | Adds Playwright automated browser checks over trimmed publish output. |
| tests/IgniteUI.Blazor.Lite.IntegrationTests/Infrastructure/TrimmedPublishServer.cs | Adds server to publish-on-demand and serve trimmed output as static files for browser tests. |
| src/IgniteUI.Blazor.Lite.csproj | Enables IsTrimmable=true for the library build. |
| src/componentsBase/Utils.cs | Adds trim suppression for enum-field reflection used by WC enum-name mapping. |
| src/componentsBase/UnmarshalledDataSource.cs | Adds trimming suppressions/annotations for app-provided data item type reflection boundary. |
| src/componentsBase/RuntimeHelper.cs | Adds trimming suppressions around framework runtime probing for net8-only paths. |
| src/componentsBase/JsonDataSourceSchema.cs | Adds trimming suppressions around reflection over app data item types and dictionary indexer. |
| src/componentsBase/IgbModule.cs | Adds IIgbModule and the [IgbModule<TSelf>] attribute retention mechanism. |
| src/componentsBase/IgbJsonContext.cs | Adds source-generated JSON context for the closed set of interop “wire shapes”. |
| src/componentsBase/IgbComponentRendererContainer.cs | Annotates ComponentType with DAM and suppresses IL2078 on the property flow. |
| src/componentsBase/DynamicContentHolder.cs | Annotates dynamic Type flows used with RenderTreeBuilder.OpenComponent(Type). |
| src/componentsBase/BaseRendererControl.cs | Reworks JSON serialize/deserialize to use JsonTypeInfo and adds focused trim suppressions/helpers. |
| src/components/Blazor/TreeModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/TreeItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/TooltipModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ToggleButtonModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/ToastModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/TileModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/TileManagerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ThemeProviderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/TextareaModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/TabsModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/TabModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SwitchModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/StepperModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/StepModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SplitterModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/SnackbarModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/SliderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/SliderLabelModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SliderBaseModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SelectModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/SelectItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SelectHeaderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/SelectGroupModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/RippleModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/RatingSymbolModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/RatingModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/RangeSliderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/RadioModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/RadioGroupModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/NavDrawerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/NavDrawerItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/NavDrawerHeaderItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/NavbarModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/MaskInputModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ListModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ListItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/ListHeaderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/LinearProgressModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/InputModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/IconModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/IconButtonModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/HighlightModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ExpansionPanelModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DropdownModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DropdownItemModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/DropdownHeaderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/DropdownGroupModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/DividerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DialogModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DateTimeInputModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DateRangePickerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/DateRangePicker.cs | Replaces JSON round-trip in Change handler with direct Start/End copy for trim/perf. |
| src/components/Blazor/DatePickerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ComboModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CircularProgressModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CircularGradientModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ChipModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CheckboxModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CheckboxBaseModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/ChatModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CarouselSlideModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CarouselModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CarouselIndicatorModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CardModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CardMediaModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CardHeaderModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CardContentModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CardActionsModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/CalendarModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/CalendarBaseModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule (obsolete no-op module). |
| src/components/Blazor/ButtonModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/ButtonGroupModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/BannerModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/BadgeModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/AvatarModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| src/components/Blazor/AccordionModule.cs | Applies [IgbModule<TSelf>] and implements IIgbModule. |
| README.md | Adds consumer-facing note + link to trimming guidance. |
| IgniteUI.Blazor.Lite.slnx | Adds PublishSmoke project to the solution. |
| docs/TRIMMING.md | Adds trimming guidance for consumers and contributor policy. |
| Directory.Packages.props | Adds per-TFM WebAssembly package versions for the smoke app. |
| .github/workflows/ci.yml | Adds theme copy step and publishes smoke app per TFM in CI. |
| .github/CONTRIBUTING.md | Updates contributor guidance to mention trimming analyzer gate and policy doc. |
| .editorconfig | Enforces trimming/single-file analyzer categories as errors repo-wide. |
| .agents/skills/igniteui-blazor-lite-trimming/SKILL.md | Adds an agent skill describing trimming rules and verification steps. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+70
to
+73
| using var process = Process.Start(publish)!; | ||
| var stderr = process.StandardError.ReadToEndAsync(); | ||
| var output = process.StandardOutput.ReadToEnd() + stderr.GetAwaiter().GetResult(); | ||
| process.WaitForExit(); |
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.
Closes #348
What & why
Enabling
<IsTrimmable>true</IsTrimmable>surfaced 48 unique trim-analysis warnings per TFM (net8/net9/net10), concentrated in the JSON interop layer and the reflective data-source/module plumbing. This PR resolves all of them — real fixes where possible, narrowly-justified suppressions only where the reflected members are provably preserved (framework/library reflection) or belong to app-supplied data types with a documented preservation requirement — so the library is safe to consume from apps published with trimming (the Blazor WebAssembly publish default).Based on
dpetev/event-callback-compare-fix: itsEventCallbackExtensions.EqualsCompatreplaces the old reflectiveCompareEventCallbacksand is already trim-clean under the new analyzer gate with no annotations (typeof(EventCallback<TValue>).GetFieldis statically analyzable).Changes
Real fixes
IgbJsonContext(src/componentsBase/IgbJsonContext.cs) covers the closed set of wire shapes (Dictionary<string,object>, its array,object,object[],string,string[],int[],double[]); all ~25JsonSerializercall sites inBaseRendererControlnow use typedJsonTypeInfooverloads — the IL2026s are gone for real, not suppressed. Deserializedobjectvalues still surface asJsonElement, identical to the reflection-based behavior.DateRangePickerChange handler: theSerialize(args.Detail) → Deserialize<IgbDateRangeValue>round-trip (with a per-eventJsonSerializerOptionsallocation) is replaced by a directStart/Endcopy — the two types share the exact shape.IIgbModuleinterface (static abstract Register) implemented by all 75*Moduleclasses, each also carrying a self-referencing[IgbModule<TSelf>]whose[DynamicallyAccessedMembers(PublicMethods)]generic parameter makes the trimmer preserve the module'sRegisterwhenever the type itself is kept — custom attributes live and die with their type, so this works fortypeofargs, arrays, and runtime-computedTypes alike, while unreferenced modules still trim fully (verified empirically: preloading an otherwise-unreferenced module through the untouchedparams Type[]overload silently no-ops without the attribute, works with it; a drift-guard test asserts every module's attribute references itself). Alternative designs were built and verified, then dropped: anIgbModuleRefimplicit-conversion wrapper and[OverloadResolutionPriority]dual overloads (call-site tracing can't cover arrays/computedTypes; the wrapper brokeType[]array call sites) and a fluentAdd<T>()collection builder (reflection-free but API shape not wanted — kept as a possible future addition).Annotations (DynamicallyAccessedMembers)
BaseRendererControlclass:PublicProperties— inherited by every component, satisfies theBuildSequenceInfoproperty walk; costs nothing real since rendered components already getAllviaOpenComponent<T>.Utils.TryGetWCEnumName/ObjectToParam(…, Type, …)chain: deliberately unannotated — DAM on method parameters of component base classes surfaces IL2111 in every consuming app (see suppression table); enum origins aretypeofliterals or boxed library enum fields at every call site.IgbComponentRendererContainer.ComponentType(property only; the backing field is deliberately unannotated — field DAM surfaces IL2110, see suppression table) andDynamicContentInfo.ControlType/TypedDynamicContent(Type):All, as required byRenderTreeBuilder.OpenComponent(Type).UnmarshalledDataSource.GetIListTypeArg/GetIEnumerableTypeArg:Interfaces.Suppression inventory (each
[UnconditionalSuppressMessage], with justification)BaseRendererControl.SendJsonSyncDotNetObjectReference<WebCallback>(a library type; only its id is serialized),ElementReference[]; the return is consumed asJsonElementand re-parsed only via the source-generatedIgbJsonContext— no user types cross the JS interop boundary.BaseRendererControl.GetWCEnumTransform(helper extracted fromBuildSequenceInfo)Utils.TryGetWCEnumNameOpenComponent<T>roots component members "via reflection".IgniteUIBlazorctor (moduleRegisterloop)[IgbModule<TSelf>], preservingRegisterwhenever the type is kept, so the lookup succeeds however theTypeflowed here; third-party module types must be preserved by the app — documented in docs/TRIMMING.md.IgniteUIBlazor.IsRuntimeValidRemoteJSRuntime.IsInitialized; in supported trim scenarios (WASM, MAUI BlazorWebView) the type doesn't exist and the probe correctly finds nothing. A stringDynamicDependencycan't be used (IL2035 when the Server assembly is absent).RuntimeHelperctorInvokeUnmarshalledprobe (API removed from the framework in net9+, binary-verified), preserved via the existingDynamicDependency; absence degrades to the raw-pointerInvokeVoidpath that is the only path on net9+. IL2026: theDynamicDependencymarks the runtime's RUC members (net10GetValue/SetValue/…), which the probe filters out by name and never invokes.IgbComponentRendererContainer.ComponentTypeJSDataSourceSchema.GetPropertiesFromType/GetFieldsFromTypeJSDataSourceSchema.CreateFromDictionaryDictionary<string, object>indexer (both call sites guard on that type), which the library also uses statically — always preserved alongside this code.UnmarshalledDataSource.ExtractSchema/ExtractSchemaFromTypeGuards & docs
dotnet_analyzer_diagnostic.category-Trimming.severity = error(pluscategory-SingleFile) in the repo.editorconfig— category bulk-config covers current and future IL2xxx codes, inert where the trim analyzer is off. Verified: removing a suppression fails the build witherror IL2070. Suppression policy: docs/TRIMMING.md contributor section.docs/TRIMMING.md(linked from README): consumer guidance — preserving data item types (including nested complex types), module preloading, AOT status.tests/IgniteUI.Blazor.Lite.PublishSmoke: Blazor WASM app publishing the library trimmed (ILLinkTreatWarningsAsErrors, single-warn off, own trim analyzer on) with a browser checklist in its README; in the solution and published by CI after the library build. Named publish-scoped so the future AOT pass reuses it.npm run copythemesstep the release workflow already had — CI builds had no component themes insrc/wwwroot(gitignored, npm-produced), whichTrimmedPublishSmokeTest's clean-load fact caught as a theme-CSS 404 on its first CI run.TrimmedPublishSmokeTest(IntegrationTests,Category=TrimmedPublish): the browser checklist as Playwright facts over the trimmed net10.0 publish output — module preload survival, camelCase enum tokens, reflected data source,igcChangepayload round-trip, clean load (no console errors/failed requests). Served by a minimal static-file host on a dynamic port (Infrastructure/TrimmedPublishServer.cs) that publishes the smoke app on demand; CI runs it via the existing unfiltered integration-test step, hitting the already-published fast path. Silent trims now fail CI instead of waiting for a manual check.Verification
dotnet build(all 3 TFMs, rebuild): 0 IL diagnostics with the.editorconfigerror gate active.dotnet test: 959 passed / 0 failed on each of net8.0, net9.0, net10.0.dotnet publishof PublishSmoke: 0 ILLink warnings (linker analysis warnings stay suppressed per the Blazor default — the framework's own assemblies emit them).variant="outlined",shape="circle"— enum fields survive trimming) and attribute-mapped (selection="single-required"—[WCEnumName]field attributes survive too), the combo binds a 3-item reflected POCO list preserved per the docs/TRIMMING.md pattern, and a dispatchedigcChangeround-trips through the new date-range copy path into rendered output. These checks now run automatically asTrimmedPublishSmokeTest; the full integration suite (77 tests including the 5 new facts) passes.IgbChatModule), through theType-based path with no other rooting: without[IgbModule<TSelf>]the preload silently losesRegister; with it, preserved. Plain type-level[DynamicallyAccessedMembers](on the interface or the module class) was also tested and does not work: class-level DAM only activates for instantiated types (that's why it works on app data-item classes and onBaseRendererControl) or annotatedGetType()flows — module classes are never instantiated, onlytypeof-referenced, hence the generic-attribute form whose DAM rides the attribute's type argument instead. The smoke app exercises the attribute-protectedTypepath permanently.Behavioral notes
GatherSimpleAttributespreviously deserialized with no options (defaultMaxDepth64); it now honorsSettings.JsonSerializerOptions.MaxDepth(library default 32) like its sibling call sites.AddIgniteUIBlazoroverloads are unchanged — no source or binary breaking changes to module registration;IIgbModuleand[IgbModule<TSelf>]are purely additive.IgbDateRangeValuein the Change handler triggers two BL0005 analyzer warnings (parameter set outside component) — same class of pre-existing warnings asChat.cs/Tabs.cs.MarshalByValueFactory.CreateInstance's static switch constructs every marshal-by-value type, so all event-args types survive trimming and pull in thin shells of their component types (e.g.IgbTabkeepsType+ 4 property accessors in an app that never uses tabs). Bounded — unused components don't survive in full — and reclaiming it needs pay-for-play event-args registration, deferred to the interop rework.🤖 Generated with Claude Code