Skip to content

Build the browser from its source; retire the library build (react consolidation 3d, 3e) - #145

Merged
imanimanyara merged 13 commits into
mainfrom
feat/absorb-react-icon-browser
Nov 12, 2026
Merged

imanimanyara merged 13 commits into
mainfrom
feat/absorb-react-icon-browser

Conversation

@imanimanyara

Copy link
Copy Markdown
Contributor

Summary

React consolidation steps 3d and 3e: the browser UI's source moves from ichava/react-icon-browser into this repository, the committed bundle is built from it, and the library build and vendoring are deprecated in place.

3d

  • Toolchain first (c9e4838): TypeScript 6 and Tailwind ^4.3. TypeScript 6 deprecates baseUrl, so tsconfig.json declares @/ relative to itself instead.
  • Snapshot import (16cc904): react-icon-browser main at 3cdbd1bc8689bd29772b50bbe3a4585112497fd2, with no history. 728 of its 758 files come in:
    • src/ goes to resources/js/.
    • The other root files go to .dev/imported/react-icon-browser/, which is export-ignored.
    • .github/ is left out, and so are the 20 Metronic paths.
  • Collisions. Two came in, not one:
    • test/setup.ts, merged by hand. Its content is react-icon-browser's file, which is icon-browser's plus the locale preload.
    • App.tsx against app.tsx. They are one file on a case-insensitive file system. The standalone root becomes StandaloneApp.tsx.
  • Build from source.
    • lib/browser.ts re-exports @/index, and app.tsx imports @/styles/theme.css.
    • vite.inertia.config.ts compiles theme.css with @tailwindcss/vite. It then scopes that one module to [data-ichava-theme] with the kernel's scopeTokens and scopeSheet, as the library build did. ichava.scss and pages.css keep their :root and body rules.
    • The fonts are emitted from resources/assets/fonts.
    • ichava.scss no longer scans the browser's source or .dev. Without that it generated 647 browser classes a second time, globally.
  • Kernel. @ichava/js-ui-kernel is pinned to bc5120c9314c31fc31c6c99140effaed9cc33f92, ichava.com's pin.
    • The ten shared files are deprecated re-exports. They were identical to the kernel apart from import specifiers.
    • Tabs and dropdown stay local.
    • kernelPin.test.ts pins the commit.
  • Tests ported.
    • Paths move from src/, scripts/ and public/ to resources/js/, .dev/browser/ and .dev/browser/public/.
    • proLicence.test.ts reads the root LICENSE.
    • noDeprecations allows exactly the ten kernel re-exports.
    • typecheck:inertia now extends tsconfig.base.json, react-icon-browser's strict settings. That needed three !s in two adapter tests.
    • ESLint takes react-icon-browser's two blocks, and lint runs with --max-warnings 0.
  • Prepaint. Prepaint.php still inlines resources/vendor/react-icon-browser/prepaint.html. npm run build:prepaint writes that file from resources/js/boot/prepaint.html, and a test fails while the two differ. They are identical today.
  • Archive.
    • The browser's tests and resources/js/test are export-ignored.
    • The utility scoper moves beside the Vite config, as vite.utility-scope.mjs, because a host rebuilding from the archive has no .dev/.

3e. sync:react-icon-browser, build:lib and check:consumers print where the work moved and exit 0. resources/vendor/react-icon-browser stays, with a DEPRECATED.md. Nothing is deleted.

Untitled UI PRO (owner's F-1 decision, 2026-11-12)

All 12 PRO files react-icon-browser holds are reachable from resources/js/index.ts, the surface this package renders. So all 12 are used, and nothing unused came in. I measured this with an esbuild metafile from index.ts; the standalone App.tsx, main.tsx and components/boot/* came back unreachable, as expected.

Folder Files Used by
application/command-menus command-menu.tsx and 6 base components components/command/CommandPalette.tsx
application/modal-layouts modal-layouts.tsx Settings, auth, profile, tour, confirm and team modals (8 importers)
application/notifications notification-card.tsx ui/Toaster.tsx, notifications/NotificationsPopover.tsx
application/tree-view tree-view.tsx, tree-view-utils.ts layout/CategoryTree.tsx
shared-assets banners/notice-banner.tsx consent/ConsentBanner.tsx
  • Each file keeps its PRO header.
  • LICENSE lists the five folders and says they are included as part of the product, not as a kit.
  • docs/architecture.md#untitled-ui-pro-components records the same.
  • proLicence.test.ts checks both halves.

Before and after (local, Node 26, fresh npm install --no-package-lock)

Check Before After
Pest 438 passed 438 passed
Vitest 119 passed (18 files) 999 passed, 3 skipped (1,002) in 135 files: 875 + 3 from react-icon-browser, 119 icon-browser, 5 new guards
typecheck:inertia exit 0 exit 0, under the stricter base config
lint exit 0 exit 0, with --max-warnings 0
build:prod exit 0 exit 0; two builds in a row are byte-identical
inertia-app.css 169,051 B (26,071 gzip) 181,335 B (27,420 gzip)
JS in public/assets/js 36 files, 1,527,471 B (444,608 gzip); entry 922,218 B 55 files, 1,537,163 B (454,717 gzip); entry 498,589 B
Composer archive (git archive) 510 files 749 files

What the archive gained:

  • 237 browser source files;
  • 4 font source files;
  • tsconfig.base.json and the 2 scoper files;
  • 19 more bundle chunks, because building from source splits the entry.

It lost 19 adapter test files, now export-ignored.

CSS against the old build:

  • Global classes: none added. One removed, invert, which only an adapter test's text named.
  • Scoped classes: 112 added, because the browser's stylesheet now scans this repository. Two removed, dark:block and dark:hidden, which only a Metronic baseline SVG named.
  • :root rules, @font-face, keyframes and [data-ichava-theme] counts are unchanged.

Proven red: the noDeprecations ceiling, the prepaint equality check and the kernel pin, each with a planted defect, then reverted.

Not changed: no spec files moved into a Playwright runner, so the visual baselines were not re-seeded. react-icon-browser's e2e suite sits inert under .dev/imported/.

Not done here

  • The vendored LICENSE, and the imported .dev/imported/react-icon-browser/LICENSE, still say the source stays in a private repository. Both are superseded by the root LICENSE (.dev/imported/README.md says so). Editing the vendored copy would break its manifest.
  • schemaTypes.test.ts still pins the schema digest through the imported schema/source.json. A future schema bump here will need that record updated.
  • react-icon-browser's other checks are not npm scripts here yet (step 2.6): boundaries, check:public-api, check:dead-classes, the e2e and visual suites, and typecheck:domain.
  • check:config-drift cannot fetch from GitHub in my sandbox. Compared locally against the kernel at bc5120c, 4 of 4 files are identical.

TypeScript 6 (the npm:@typescript/typescript6 alias) and Tailwind ^4.3 match react-icon-browser, whose source moves into this repository next. TypeScript 6 deprecates baseUrl, so the @/ path is declared relative to tsconfig.json instead; it resolves to the same directory. typecheck:inertia, lint, Vitest (119) and build:prod pass, and the committed bundle is unchanged.
A verbatim snapshot of ichava/react-icon-browser at 3cdbd1bc8689bd29772b50bbe3a4585112497fd2 (main), with no history; that repository keeps it. 728 of its 758 tracked files:

- src/ goes to resources/js/ (351 files).
- Two files collide with this repository's own and wait in the holding folder: src/test/setup.ts (differs from resources/js/test/setup.ts, merged by hand next) and src/App.tsx (case-only collision with resources/js/app.tsx, the Inertia entry, on a case-insensitive file system).
- Everything else (root files, configs, scripts, schema, docs, e2e, public) goes to .dev/imported/react-icon-browser/, which is export-ignored, to be moved out or retired by the commits that follow.

Left out: .github/ (10 files, inert here; its jobs are ported separately) and the 20 Metronic paths (19 public/baseline/icon-sets-metronic__*.svg and the svg-baseline Metronic snapshot), which are private to KeenThemes' licence.

The 12 Untitled UI PRO components all come in: each is reachable from the library entry (src/index.ts) that this package renders, and each keeps its PRO header.
Verbatim moves, so the path changes in the next commits are reviewable on their own:

- scripts/ becomes .dev/browser/ (build plugins, checks and generators).
- public/fonts/ (Geist, Geist Mono, their OFL licence and README) becomes resources/assets/fonts/, the asset home for fonts.
- public/data, public/assets and public/baseline (the standalone app's fixture catalogue and sample SVGs, which the tests read) become .dev/browser/public/.
- src/App.tsx, the standalone demo's root, becomes resources/js/StandaloneApp.tsx: App.tsx and the Inertia entry app.tsx are one file on a case-insensitive file system.
- tsconfig.base.json moves to the root, as in ichava.com.
react-icon-browser's src/test/setup.ts was the one path both trees held. Its first seven lines are icon-browser's file exactly; it adds the preload of every locale catalogue, which the browser's suites need (they assert translated copy synchronously) and icon-browser's do not mind. So the merged file is the browser's, with a note saying so.
The Inertia build and Vitest now read the browser's source instead of the vendored library:

- lib/browser.ts re-exports @/index (the browser's public surface) and app.tsx imports @/styles/theme.css. main.tsx imports the standalone root from its new name.
- vite.inertia.config.ts compiles theme.css with @tailwindcss/vite and scopes it to [data-ichava-theme] the way the library build did (the kernel's scopeTokens, then .dev/browser's scopeSheet), on that module alone, so ichava.scss and pages.css keep their :root and body rules. The Geist fonts are emitted from resources/assets/fonts with the url() rewrite the library build used. __ICHAVA_BROWSER_VERSION__ comes from package.json in both configs.
- ichava.scss no longer scans the browser's source or .dev, or it would regenerate the browser's classes globally against its own theme.
- package.json takes the browser's dependencies; the file: link to resources/vendor/react-icon-browser goes.
- typecheck:inertia extends tsconfig.base.json (the kernel's, as react-icon-browser used it), so the browser keeps its strict settings and the adapter meets them too (three index checks in two tests). check:config-drift covers tsconfig.base.json. ESLint takes react-icon-browser's two blocks, and lint now allows no warnings.
- The browser's tests and tooling are repointed from react-icon-browser's layout (src/, scripts/, public/) to this one (resources/js/, .dev/browser/, .dev/browser/public/); the standalone pages and their npm scripts are read from the imported root files. noPersonalContact spells its pattern in pieces so NoPersonalAuthorTest does not find it in the test.
- Prepaint.php still inlines resources/vendor/react-icon-browser/prepaint.html. npm run build:prepaint writes it from resources/js/boot/prepaint.html, and a Vitest test fails while they differ (they are identical today).
- FontAssetsTest compares the bundle's fonts with resources/assets/fonts and theme.css.

Vitest: 994 passed, 3 skipped (997 = react-icon-browser's 875 + 3 and icon-browser's 119). Pest: 438 passed.
The kernel is pinned to bc5120c9314c31fc31c6c99140effaed9cc33f92, ichava.com's pin, which adds the ./react subpath (js-ui-kernel#22). The ten files whose code moved there (cx, is-react-component, the four avatar base components, radio-buttons, toggle, featured-icon and uui-theme.css) were identical to the kernel's copies apart from import specifiers; each is now a deprecated re-export, so every import keeps working until the owner approves removing it. tabs and dropdown stay local, as decided.

- theme.css points Tailwind at the kernel's components.
- brand-bridge.mjs reads Untitled UI's theme from the kernel.
- noDeprecations allows exactly those ten files, so any other @deprecated still fails.
- kernelPin.test.ts pins the commit and checks the ./react exports.
A host that rebuilds the bundle from the Composer archive (ichava:build:prod) gets vite.inertia.config.ts but not .dev/, which is export-ignored, so the utility scoper the config imports moves beside it as vite.utility-scope.mjs (a verbatim move; the dormant check-lib-build.mjs follows it). The browser's tests and resources/js/test are export-ignored, so the archive grows by the source alone, and .dev/imported/README.md says what the holding folder is and that its LICENSE is superseded by the root one.
LICENSE names the five PRO folders under resources/js and says they are individual components included as part of this product under the Untitled UI licence, not a kit (owner, F-1, 2026-11-12); proLicence.test.ts reads that list. docs/architecture.md describes the in-repo source, the kernel's shared UI, how the stylesheet is built and scoped, each PRO component and what uses it, and the deprecated vendored build. README, CONTRIBUTING, the release, installation, configuration, host-integration and payload-schema pages and the changelog follow.
react consolidation 3e. npm run sync:react-icon-browser, build:lib and check:consumers print where the work moved and exit 0; the sync keeps its vendoredLicense export. resources/vendor/react-icon-browser stays, unbuilt, with a DEPRECATED.md saying its prepaint.html is the one file still read and npm run build:prepaint writes it; vendoredLibrary.test.ts checks the notice and keeps it out of the manifest comparison. Nothing is deleted; each item has a row in the react consolidation audit, and removing any needs the owner's yes.
npm run build:prod after a fresh npm install --no-package-lock (Node 26, as committed-build.yml runs it on 24). Two builds in a row are byte-identical. inertia-app.css: 169,051 bytes before, 181,251 after. Against the old CSS: no global class added; one removed (invert, which only an adapter test named); 112 scoped utilities added (the browser's stylesheet now scans this repository rather than react-icon-browser's) and two removed (dark:block and dark:hidden, which only a Metronic baseline SVG named). :root rules, font faces, keyframes and [data-ichava-theme] scopes are unchanged in number.
…archive

Completes the previous commit, which staged only the move: vite.inertia.config.ts and the dormant check-lib-build.mjs import the scoper from its new place, typecheck:inertia reads its declarations, .gitattributes export-ignores the browser's tests and resources/js/test (and the vendored directory's DEPRECATED.md), and .dev/imported/README.md says what the holding folder is and that its LICENSE is superseded by the root one.
Copilot AI balanced review requested due to automatic review settings November 12, 2026 21:10

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has insufficient remaining quota. Try requesting a review at a lower effort level.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

The react-icon-browser import brought .dev/browser/public/baseline/ (34 SVGs, 15 of them from the private icon-sets-bundled pack) and a rendering of that pack. They are generated locally by sample-svg-archetypes.mjs for the svg-baseline check, which is not wired up here, so removing them breaks nothing. The folder and private-pack snapshots are ignored, and noPrivateContent.test.ts fails if any baseline path or bundled or Metronic SVG or rendering is tracked again (seen failing with the 34 files present).
Tailwind had read m-52 out of SVG path data in one of the removed baseline files, so the committed stylesheet carried a .m-52 rule no source uses. A fresh build drops it; nothing else changes.
@imanimanyara
imanimanyara merged commit 8cbbd8c into main Nov 12, 2026
15 checks passed
@imanimanyara
imanimanyara deleted the feat/absorb-react-icon-browser branch November 12, 2026 21:54
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