feat: vite/ESM build, zero-hook initializer, public api.js module - #404
feat: vite/ESM build, zero-hook initializer, public api.js module#404damyanpetev wants to merge 8 commits into
api.js module#404Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The updated docs/samples use absolute /_content/... module specifiers that don’t align with the import-map prefix strategy described in the PR and should be made consistent.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR modernizes the IgniteUI.Blazor.Lite static-web-assets pipeline and runtime initialization by switching the JS build to Vite + native ESM, adding a public _content/IgniteUI.Blazor/api.js module for *Script registration + lit-html templating, and removing the legacy bootstrap chain that breaks under .NET static-asset fingerprinting.
Changes:
- Replace webpack bootstrap flow with a Vite build that emits native ESM chunks plus a flat-import Blazor initializer module.
- Introduce public
api.js+api.d.tsexports (registerScript/removeScript/html) and route legacy window globals through deprecated shims + a queueingapp.bundle.jsstub. - Update docs/tests/templates/hosts to remove the redundant
<script src="_content/IgniteUI.Blazor/app.bundle.js">tag for Lite and to validate output invariants vianode --test.
File summaries
| File | Description |
|---|---|
| webpack.config.js | Removes the webpack-based bootstrap/build pipeline. |
| vite.config.mts | Adds Vite/Rolldown configuration to emit ESM bundles, fixed-name public modules, and a flat-import initializer. |
| tsconfig.json | Updates TS target/module resolution for bundler-style ESM output and tighter browser-only typing. |
| tsconfig.api.json | Adds a dedicated config to emit api.d.ts next to built api.js. |
| tests/js/static-web-assets.test.mjs | Adds node-based tests to pin wwwroot output invariants and legacy stub behavior. |
| tests/IgniteUI.Blazor.Lite.TestBed/wwwroot/app.js | Updates testbed script registration sample to use the public module API. |
| tests/IgniteUI.Blazor.Lite.TestBed/Components/App.razor | Removes redundant app.bundle.js tag from the Lite testbed host. |
| tests/IgniteUI.Blazor.Lite.PublishSmoke/wwwroot/index.html | Removes redundant app.bundle.js tag from the publish smoke host. |
| templates/README.md | Updates template guidance to no longer require the Lite script tag. |
| templates/IgniteUI.Blazor.Templates/templates/project/igb-blazor/IgniteBlazorApp.1/Components/App.razor | Removes redundant app.bundle.js tag from the template host. |
| stories/wwwroot/js/Chat.stories.js | Migrates story template registration from window globals to api.js imports. |
| stories/wwwroot/index.html | Removes redundant app.bundle.js tag from stories host page. |
| stories/Components/Stories/Welcome.md | Updates getting-started doc to remove script tag requirement. |
| stories/Components/Pages/IFramePage.razor | Removes redundant app.bundle.js tag and aligns guidance formatting. |
| src/src/public_path.ts | Removes webpack public-path global logic. |
| src/src/index.ts | Moves script registry lookup to api.ts, removes window globals, and fixes global → globalThis. |
| src/src/app.bundle.ts | Adds legacy classic-script stub that queues deprecated global calls until api.js loads. |
| src/src/api.ts | Adds the public API module (registerScript/removeScript/html) plus deprecated global shims + queue replay. |
| src/IgniteUI.Blazor.Lite.csproj | Updates the (commented) prebuild sample to run npm run build only. |
| src/components/Blazor/Accordion.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Banner.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/ButtonBase.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/ButtonGroup.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Calendar.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Carousel.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Chat.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/ChatRenderers.cs | Updates template XML docs to reference api.js registerScript + html usage. |
| src/components/Blazor/CheckboxBase.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Chip.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Combo.cs | Updates template + handler XML docs to reference api.js registerScript + html usage. |
| src/components/Blazor/DatePicker.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/DateRangePicker.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/DateTimeInput.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Dialog.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Dropdown.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/ExpansionPanel.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Input.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/InputBase.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/MaskInput.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/NavDrawer.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Radio.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/RadioGroup.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/RangeSlider.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Rating.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Select.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Slider.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Snackbar.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Splitter.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Stepper.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Tabs.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Textarea.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Tile.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/TileManager.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Tooltip.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| src/components/Blazor/Tree.cs | Updates *Script XML docs to reference api.js registerScript usage. |
| skills/README.md | Expands skills index to note client-side *Script coverage. |
| skills/igniteui-blazor-theming/SKILL.md | Removes script-tag guidance from theming skill. |
| skills/igniteui-blazor-theming/references/common-patterns.md | Removes script-tag guidance from theming reference. |
| skills/igniteui-blazor-grids/SKILL.md | Updates grid skill guidance (Lite vs full product script-tag requirements). |
| skills/igniteui-blazor-grids/references/types.md | Updates FormatterScript guidance to reference registerScript. |
| skills/igniteui-blazor-grids/references/features.md | Updates export scripting example to use api.js. |
| skills/igniteui-blazor-generate-from-image-design/SKILL.md | Removes Lite script-tag requirement from image-design workflow. |
| skills/igniteui-blazor-components/SKILL.md | Updates setup guidance: Lite self-loads; adds *Script guidance and links. |
| skills/igniteui-blazor-components/references/setup.md | Clarifies theme-only requirement for Lite, and full-product caveats in Web Apps. |
| skills/igniteui-blazor-components/references/client-scripts.md | Adds new reference doc for registering *Script handlers/templates via api.js. |
| skills/AGENTS.md | Updates agent setup guidance to reflect Lite self-loading + full-product caveats. |
| README.md | Updates repo README: removes Lite script-tag setup and updates local build instructions. |
| package.json | Replaces webpack scripts with tsc --noEmit + vite build, adds node --test asset checks. |
| Directory.Build.targets | Updates comment to explain empty sentinel and non-MSBuild JS asset build. |
| CHANGELOG.md | Documents new public API, ESM build, deprecations, and fingerprinting fix. |
| .github/workflows/igniteui-blazor-lite-release.yml | Updates release workflow to run the new build (no separate theme copy). |
| .github/workflows/ci.yml | Updates CI to run new build and adds npm test asset verification. |
| .env.development | Adds a dev env file for NODE_ENV. |
Review details
Suppressed comments (1)
skills/igniteui-blazor-components/references/client-scripts.md:33
- Same import-map concern as above: the classic-script example uses an absolute specifier (
'/_content/…'), so an import-map prefix for"./_content/IgniteUI.Blazor/"would not apply. Using document.baseURI keeps it path-base-safe and aligns the specifier with the recommended prefix style.
- Other exports: `removeScript(name)`, and `html` — the lit-html template tag, the same instance the components render with. Typings ship at `_content/IgniteUI.Blazor/api.d.ts`.
- From a classic (non-module) script use a dynamic import: `const { registerScript, html } = await import('/_content/IgniteUI.Blazor/api.js');`
- The `igRegisterScript` / `igRemoveScript` / `igTemplating.html` window globals still work with the same signatures, but are deprecated and warn in the console.
- Files reviewed: 72/74 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
63d0f00 to
67700fb
Compare
There was a problem hiding this comment.
🔵 Needs a closer look
Large cross-cutting changes to the JS build/bootstrapping and public JS API warrant human validation across hosting models and compatibility paths.
Review details
- Files reviewed: 72/74 changed files
- Comments generated: 3
- Review effort level: Lite
There was a problem hiding this comment.
🟡 Changes recommended
Legacy queue replay changes call ordering, while the public API and development type-checking also need correction.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
Previously missed (1) — in code that hasn't changed since the last review.
src/src/api.ts:40
- This registry accessor is emitted in
api.d.tsand therefore becomes part of the supported public module surface, although the changelog and client-script documentation expose onlyregisterScript,removeScript, andhtml. Keep lookup internal (for example via a shared internal registry module), or explicitly document and commit to this API before release.
- Files reviewed: 72/74 changed files
- Comments generated: 2
- Review effort level: Balanced
e6429ef to
e4950c7
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Public typings expose an internal registry type, and the new script guidance includes unsupported full-product and parse-time-global scenarios.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
skills/igniteui-blazor-components/references/client-scripts.md:34
- Without the legacy
app.bundle.jstag,api.jsis not imported until Blazor starts, so a classic script that calls these globals during page parsing seesigRegisterScriptas undefined. Qualify the compatibility statement so users removing the now-optional tag do not break existing parse-time registrations.
- The `igRegisterScript` / `igRemoveScript` / `igTemplating.html` window globals still work with the same signatures, but are deprecated and warn in the console.
- Files reviewed: 72/74 changed files
- Comments generated: 4
- Review effort level: Balanced
e4950c7 to
5637115
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The client-script documentation incorrectly promises order-independent module execution, which can race Blazor startup and permanently miss registrations.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 71/73 changed files
- Comments generated: 1
- Review effort level: Balanced
5637115 to
4ee87c3
Compare
There was a problem hiding this comment.
🟡 Changes recommended
The Vite dependency requires Node 22.12+, conflicting with the documented Node 22+ prerequisite.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 71/73 changed files
- Comments generated: 1
- Review effort level: Balanced
|
|
||
| - **Packages**: `IgniteUI.Blazor.Lite` for general-purpose components and `IgniteUI.Blazor.GridLite` for the lightweight grid (both MIT, NuGet.org); `IgniteUI.Blazor` — publicly available for evaluation as `IgniteUI.Blazor.Trial` — for feature-rich grids, charts, maps, gauges, and Dock Manager. If the project already references the full `IgniteUI.Blazor`, do not add Lite or GridLite unless the user explicitly chooses to switch package strategy. If no Ignite UI package is present, add the one that matches the chosen strategy. | ||
| - **Setup**: `builder.Services.AddIgniteUIBlazor()` in `Program.cs`, `@using IgniteUI.Blazor.Controls` in `_Imports.razor`, one theme stylesheet, and `_content/IgniteUI.Blazor/app.bundle.js` before the Blazor framework script in the host page. Missing the script tag renders the app blank. | ||
| - **Setup**: `builder.Services.AddIgniteUIBlazor()` in `Program.cs`, `@using IgniteUI.Blazor.Controls` in `_Imports.razor`, and one theme stylesheet in the host page. `IgniteUI.Blazor.Lite` loads its scripts itself (JS initializer); the full `IgniteUI.Blazor`/`.Trial` also needs `_content/IgniteUI.Blazor/app.bundle.js` before the Blazor script in Blazor Web Apps — never wrapped in `@Assets[...]`. |
There was a problem hiding this comment.
Explain why the licensed package needs it. Just a short reason.
| | CSS — full grids | **both** `_content/IgniteUI.Blazor/themes/light/bootstrap.css` **and** `_content/IgniteUI.Blazor/themes/grid/light/bootstrap.css` | | ||
| | CSS — Grid Lite | `_content/IgniteUI.Blazor.GridLite/css/themes/light/bootstrap.css` only — not the two above | | ||
| | Script | `_content/IgniteUI.Blazor/app.bundle.js` before the Blazor framework script | | ||
| | Script | None for `IgniteUI.Blazor.GridLite`; full grids (`IgniteUI.Blazor`/`.Trial`) need `_content/IgniteUI.Blazor/app.bundle.js` before the Blazor framework script in Blazor Web Apps — never wrapped in `@Assets[...]` | |
There was a problem hiding this comment.
This place also needs a short answer to "Why?".
| There are no separate DV packages. If a required package is missing from the project, identify the right package and version and **ask before editing the `.csproj`**. | ||
|
|
||
| Register every `Igb*Module` you use in `Program.cs`, add `@using IgniteUI.Blazor.Controls` to `_Imports.razor`, and confirm the theme stylesheet and `app.bundle.js` are in the host page — see the components skill's [`setup.md`](../igniteui-blazor-components/references/setup.md). | ||
| Register every `Igb*Module` you use in `Program.cs`, add `@using IgniteUI.Blazor.Controls` to `_Imports.razor`, and confirm the theme stylesheet is in the host page (on `IgniteUI.Blazor`/`.Trial` in a Blazor Web App, also the `_content/IgniteUI.Blazor/app.bundle.js` script tag before the Blazor script; `IgniteUI.Blazor.Lite` needs no tag) — see the components skill's [`setup.md`](../igniteui-blazor-components/references/setup.md). |
There was a problem hiding this comment.
This differs from the explanation in our dotnet/skills skill: https://github.com/dotnet/skills/pull/1111/changes#diff-6fbe289f6bfc3d6caa7652f7b348ca92b9af9e27c0dd5b3f6ce96cc49794a22bR44
In this one:
- List the modules in the licensed package that components don't function without.
- For the rest, explain that the modules are for eager loading, but if not includes would be lazy-loaded.
|
|
||
| - **Registration.** `builder.Services.AddIgniteUIBlazor()` in `Program.cs` is required. Passing `typeof(Igb<Name>Module)` arguments eagerly pre-loads exactly those modules; with no arguments every module is available. In `IgniteUI.Blazor.Lite` each component also registers its own module on first render, so the explicit list is a bundle-size optimization rather than a correctness requirement. | ||
| - **Runtime script.** `<script src="_content/IgniteUI.Blazor/app.bundle.js"></script>` must appear before the Blazor framework script in the host page. Missing it means no web components register and the app renders blank. | ||
| - **Runtime script.** `IgniteUI.Blazor.Lite` loads its component bundle itself (JS initializer, every hosting model). The full `IgniteUI.Blazor`/`IgniteUI.Blazor.Trial` needs `<script src="_content/IgniteUI.Blazor/app.bundle.js"></script>` before the Blazor framework script in **Blazor Web Apps** — never wrapped in `@Assets[...]` (fingerprinting it renders the app blank). |
There was a problem hiding this comment.
Is this applicable when not using a grid or chart component, since we haven't yet ripped the rest of the components out of IgniteUI.Blazor and haven't made IgniteUI.Blazor.Lite a dependency yet?
| Both tags are required: without the stylesheet components render unstyled, without `app.bundle.js` they do not render at all. `app.bundle.js` must come **before** the Blazor framework script. | ||
| **`IgniteUI.Blazor.Lite` (≥ 0.1.0) loads its component bundle itself** — a JS initializer runs during Blazor startup on every hosting model: Blazor Server, standalone WASM, Blazor Web App (`blazor.web.js`, any render mode), and BlazorWebView/Hybrid. | ||
|
|
||
| **The full product (`IgniteUI.Blazor` / `IgniteUI.Blazor.Trial`, ≤ 26.1.x) still needs the tag in Blazor Web Apps** — it ships a classic-only initializer that `blazor.web.js` ignores. There the tag must come **before** the Blazor framework script; classic Blazor Server and standalone WASM apps on the full product may omit it. |
There was a problem hiding this comment.
So, if I get this correctly, we will drop this requirement in 26.2?
|
|
||
| Host page is `wwwroot/index.html` (WASM/MAUI), `Pages/_Host.cshtml` (Server), or `Components/App.razor` (Web App). | ||
|
|
||
| The theme stylesheet is the only required tag — without it components render unstyled. |
There was a problem hiding this comment.
This statement The theme stylesheet is the only required tag goes in conflict with the next statement that IgniteUI.Blazor also requires a script tag with the app.bundle.js referenced.
| }); | ||
| ``` | ||
|
|
||
| `html` is the Lit HTML template tag: `${}` interpolates values, `@click=${fn}` binds listeners, and so on. Ignite UI web components (`<igc-avatar>`, `<igc-icon-button>`, …) work inside a template; if the component is not used as a Blazor component elsewhere in the app, register its module explicitly with `AddIgniteUIBlazor(typeof(IgbAvatarModule), …)` in `Program.cs`. |
There was a problem hiding this comment.
Why should I register its module explicitly?
I approved only the changes in a single commit
kdinev
left a comment
There was a problem hiding this comment.
I've submitted multiple review comments. Please take a look.
Fixes #233. Addresses the bootstrap audit in #256.
Why
app.bundle.js→app.bootstrap.js→app.<hash>.bundle.jschain located its chunks by regexing its own script URL. Under .NET 9+ fingerprinting (@Assets[...]) that silently no-ops and the app renders blank (Ignite UI for Blazor stops working with .NET 9 Assets helper (no error but components not registered) #233).igRegisterScriptwas a window global with no defined safe-point, and a script resolving before registration was dropped silently.What changed
Build: webpack → vite, native ESM output.
igniteui-corechunk (runtime plus all component metadata), our interop code asapp,igniteui-webcomponentsas the single lazy chunk. A commented knob invite.config.mtssplits the metadata into lazy per-component chunks instead._content/IgniteUI.Blazor/lit-html.js), and every lit-html import in the graph goes through it, so an app mixing lit-based libraries can dedupe to one copy with a single import-map entry.build.licenseemitsTHIRD-PARTY-LICENSES.mdalongside the static assets.tsc --noEmitjoins the build as the type-check gate (vite only transpiles), withtypes: []so Node-only globals are compile errors. That surfaced one real bug: the in-process (WASM) data path referenced Node'sglobal, which webpack had polyfilled; it isglobalThisnow.npm run buildproduces the completewwwroot, themes included; the separatecopythemesscript and CI step are gone.webpack.config.js, the webpack dependencies,public_path.tsand the undocumentedigPublicPath/InfragisticsBlazorglobals are removed.Loading: the JS initializer is the sole loader.
IgniteUI.Blazor.Lite.lib.module.jsis generated as a flat list of static imports covering the app entry's closure andapi.js. It exports no hooks: Blazor awaits the module import, the module system awaits the imports. The graph loads in one hop instead of three.app.bootstrap.jsis deleted.app.bundle.jsremains as a static shim for existing tags: it loads nothing and queuesigRegisterScript/igRemoveScriptcalls made while the page parses, whichapi.jsreplays when it loads.Public ES module
_content/IgniteUI.Blazor/api.js(typings inapi.d.ts):registerScript(name, fn, shouldCall = false)/removeScript(name). The default flips from the global'strue: every*Scriptparameter in Lite except the value-supplyingDataScript/ItemsScriptwants the function itself, and every example (ours and the public grid docs) passedfalseexplicitly. The deprecated global keepstrue.html, lit-html's template tag, the same instance the components render with.*Scriptname that is not registered when the component resolves it now logs a warning naming the script.Docs and tests.
@Assetswarning is scoped to the full product, whose loader still breaks under fingerprinting.*Scriptregistration moves out of setup into its own components-skill reference (client-scripts.md). All*Scriptexamples, including the 137 XML doc comments, use the module import, and every in-repo host follows the no-tag path.npm test(node --test, run in CI after the asset build) pins the builtwwwrootinvariants: no URL inspection, a plain-import initializer, real exports onapi.jsandlit-html.js, no internals inapi.d.ts, legal notices present, the twoshouldCalldefaults, and the legacy stub's queue behaviour vianode:vm.Compatibility
@Assets[...], and the deprecated globals keep working with a console notice.*Scriptafter its component rendered remains unsupported (now warns); order-independent registration is a separate follow-up.igPublicPathcould have done, is a standard import map prefix entry such as{"imports": {"./_content/IgniteUI.Blazor/": "https://cdn.example.com/ig/"}}, which relocates the whole graph, initializer included.Verification
igTemplating.htmlat render time, one deprecation warning per API.@Assets-tag matrix and module-registration cases confirmed.npm testgreen.🤖 Generated with Claude Code