Skip to content

perf(web): load project icons as one chunk instead of ~1,700 - #20147

Merged
juliusmarminge merged 1 commit into
mainfrom
t3/lucide-single-chunk
Oct 16, 2026
Merged

juliusmarminge merged 1 commit into
mainfrom
t3/lucide-single-chunk

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 16, 2026 •

Copy link
Copy Markdown
Member

lucide-react/dynamic emits one chunk per icon. Project icon overrides used it, so the web build wrote ~1,700 tiny icon chunks (2,343 JS chunks in total).

Change

  • Saved lucide project icons now resolve by name against a single module that lazily imports lucide-react.
  • The resolver also accepts lucide's deprecated alias names, so overrides saved with an older name still render.
  • The icon picker and the project favicon both use it. lucide-react/dynamic is no longer imported.

Results

vp build in apps/web on cups, three runs each, after #20114.

Before After
Build time 40.8 / 42.4 / 41.1s 40.0 / 37.5 / 39.4s
JS chunks 2,343 740
Files in dist 4,653 1,484
dist size 136 MB 125 MB
App load JS (entry + main) 1,267 kB gz 1,260 kB gz
Extra JS to draw a saved lucide icon 56 kB gz 154 kB gz

Bundled dev cold app compile (first request for the app in a fresh vp dev): 10.5s on main, 9.3s on this branch. These were measured in separate sessions, so treat them as "no regression" rather than a speedup. HMR was not measured.

The trade-off is the last row. Projects that use a lucide icon override now load the whole icon set once (137 kB gzip for the icon chunk itself), instead of a 254 kB name index plus one icon. That chunk is only fetched when such an icon is shown or the picker opens. Projects without a lucide icon pay nothing.

Verification

  • projectIconOptions tests now check that every offered name resolves, including saved legacy spellings (arrow-down-0-1, alarm-check).
  • All 1,917 names in lucide's dynamic import map resolve to the same component as before.
  • Browser check with copied real data: the picker search renders icons, and saving alarm-clock-check shows it in the sidebar and header.

Project icon picker searching "alarm clock"
Saved alarm-clock-check icon in the sidebar

Fixes #9544

🤖 Generated with Claude Code


Devin Review

lucide-react/dynamic emits one chunk per icon. Project icon overrides now
resolve names against a single lazily loaded lucide module, cutting web
build output from 2,343 JS chunks to 740.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 16, 2026
@juliusmarminge juliusmarminge added the macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews label Oct 16, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — This production web change replaces per-icon loading with a full Lucide icon-set chunk, affecting payload and loading behavior for project icons and the picker. It also adds a file-level suppression for the restricted-import lint rule, so the change warrants human review.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Team
  • Run ID: 1ca8cc23-28ea-405b-ad36-c17b027cbbac
📥 Commits

Reviewing files that changed from the base of the PR and between 9b150f7 and a18da9a.

📒 Files selected for processing: 6
  • apps/web/src/components/ProjectFavicon.test.tsx
  • apps/web/src/components/ProjectFavicon.tsx
  • apps/web/src/components/settings/ProjectIconPickerDialog.tsx
  • apps/web/src/lib/lucideIconByName.ts
  • apps/web/src/projectIconOptions.test.ts
  • apps/web/src/projectIconOptions.ts
💤 Files with no reviewable changes: 1
  • apps/web/src/components/ProjectFavicon.test.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 8 remain after this review.

📝 Walkthrough

The project icon flows now use a local Lucide icon lookup. It provides canonical icon names, resolves icon components, and returns no match for unknown names. Project icon filtering and rendering use this lookup.

Changes: Lucide icon resolution

Layer / File(s) Summary
Local icon lookup
apps/web/src/lib/lucideIconByName.ts
Adds canonical kebab-case icon names and resolves names to Lucide components. Unknown names return undefined.
Project icon options and rendering
apps/web/src/projectIconOptions.ts, apps/web/src/projectIconOptions.test.ts, apps/web/src/components/ProjectFavicon.tsx, apps/web/src/components/ProjectFavicon.test.tsx, apps/web/src/components/settings/ProjectIconPickerDialog.tsx
Project icon filtering and display use the local lookup. Tests check listed names, selected spellings, and unknown names. The favicon test removes its lucide-react/dynamic mock.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~12 minutes

Change: Refactor

Merge Risk: ⚪ Minimal · up to a18da

No actionable merge-blocking issue remains in the reviewed icon changes.

Pre-merge checks: Passed 4
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title is concise, specific, and accurately describes the main performance change: replacing many project-icon chunks with one chunk.
Description check Passed The description explains the problem, implementation, measured results, trade-off, verification steps, issue reference, and UI evidence. It does not use the required Problem and Scope and approval hea…
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@juliusmarminge
juliusmarminge merged commit b47746b into main Oct 16, 2026
37 of 38 checks passed
@juliusmarminge
juliusmarminge deleted the t3/lucide-single-chunk branch October 16, 2026 04:36
Pipyakas pushed a commit to Pipyakas/t3code that referenced this pull request Oct 18, 2026
…gg#20147)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b47746b)
aorwall added a commit to aorwall/t3code that referenced this pull request Oct 19, 2026
## Summary

This merges `pingdotgg/t3code` at `5c5dcbc60b` into the fork. It
branches from `main` at `59369391d6`, and no other merge PR was open to
stack on.

- Upstream range: 3247 files changed upstream and 3247 landed. The fork
delta is 818 files (`git diff --stat HEAD^2 HEAD`).
- 32 conflicts, each resolved by the verdict `preflight.mjs` printed.
`docs/fork/upstream-merge-log.md` (entry 2026-10-17) records the
details.
- Fork-deleted files that upstream modified stay deleted:
`apps/server/src/cli/pair.ts`, `pair.test.ts`,
`components/preview/useDiscoveredLocalServers.ts`.
- `ChatView.tsx`: took upstream's hook extraction. The fork deltas moved
with upstream's code:
  - `scriptsEditable` → `chat/useProjectScriptEditing.ts`
- `sandbox` panel surface and `onRetargetFile` →
`chat/RightPanelSurfaceContent.tsx`, which also drops upstream's
`configuredPreviewUrls`
  - The inventory entries now point at both files.
- `Sidebar.tsx`: upstream moved partitioning into
`useSidebarThreads`/`partitionSidebarThreads`. The browse filter,
`showsClosed`/`hidesSubtasks`/`isBrowsing`, and the rule that pinned
threads are never settled are restated there.
- Upstream adopted React Compiler and removed `useCallback`/`useMemo`.
Fork lines in `useThreadActions.ts`, `useProjectScriptSettings.ts`,
`MessagesTimeline.tsx`, `PreviewView.tsx`, `DiffPanel.tsx` and
`BranchToolbar.tsx` are restated as plain functions.
- Upstream's new `reactCompiledFiles.test.ts` rejects `try/finally`. Two
fork blocks used it: `startSandboxForScript` in ChatView and the frame
pick handler in PreviewView. Both now call `.finally()` on the promise.
- `pnpm-lock.yaml`: took upstream's copy, stripped `tsc-rs`, and
re-derived it.

## New fork deltas

- Root `vite.config.ts`: upstream's new `t3code/no-low-value-comments`
rule is off for `packages/moatless-api/src/generated/**`, because orval
regenerates those comments. The new `root-vite-config` path policy
covers this, and "Root Vite Lint Delta" in `upstream-merge-inventory.md`
explains it.
- Upstream restored the mobile-app store row in Settings. It is now
gated on `FEATURES.connections`, and `features.ts` maps the `mobile-app`
settings search ID to `connections`.
- Four `// ---- X ----` dividers removed from fork settings panels,
which upstream's comment rule rejects.

## Verification

`verify.mjs`:
- Green: duplicate-adds, tripwires, resolution-check,
unsupported-methods (ADD 0, DROP 0, KEEP 2), lockfile, fmt, lint,
typecheck and build.
- The React Compiler fix came after that run. Since then, web typecheck,
lint and format on the two changed files, the web build, and the full
`@t3tools/web` suite (544/544 files) all pass.
- Each of these test files fails when run alone, and all of them failed
on the 2026-10-16 merge too: `@t3tools/shared` `AgentScope.test.ts`;
`t3` `ServerBrowserPage.test.ts`, `AcpAdapterV2.test.ts`,
`OrchestratorReplayFixtures.integration.test.ts`; `provider-opencode`
`OpenCodeServerLedger.test.ts`; `ssh` `tunnel.test.ts`. This merge
didn't touch any of them.
- The sandbox restarted three times during verification. After the React
Compiler fix, the repo-wide `pnpm typecheck` was not re-run to
completion; only `apps/web` changed, and its typecheck passes.

## Feature classification

### Usable as-is
- React Compiler adoption and the related perf work across `apps/web`,
plus upstream's ChatView hook extraction
- Sidebar crash fix (pingdotgg#20522)
- Reconnect grace period (pingdotgg#20441); fixes for drafts when switching
machines (pingdotgg#20442, pingdotgg#20519)
- Running-status banners on one line (pingdotgg#20194)
- Project icons load as one chunk (pingdotgg#20147)
- PR stacks grouped under their parent PR (pingdotgg#20160); typed search
qualifiers in PR search (pingdotgg#19934)
- Provider status pushes leave unchanged providers identical (pingdotgg#20392)
- Tooltip updates (pingdotgg#20448)
- The `t3code/no-low-value-comments` lint rule and upstream's comment
pruning
- Mobile/Expo updates (not a fork target)

### Unsupported in Moatless / needs implementation
- pingdotgg#20432: pairing grants access, and T3 Connect management is on by
default. Pairing and Connect stay decided out, and the tripwires still
pass.
- pingdotgg#20422: mobile-app store row in Settings. The T3 mobile app pairs with
a T3 server, so the row is gated behind `FEATURES.connections`.

### Backend behavior to consider reproducing in Moatless
- pingdotgg#20184: follow-up messages sent during `/compact` or `/logout` are
queued. When `canSteer` is false the client now sends `queue`, so the
Moatless backend should accept a queued follow-up while compaction runs.
- pingdotgg#19750: after a restart, threads whose background subagent work was
cut off are woken.
- pingdotgg#19751: background subagents keep T3 tools after the parent turn ends.
Pending subagent work carries `providerInstanceId`.
- pingdotgg#15945: a slow but healthy Codex is no longer reported Unavailable.

`docs/fork/gaps.md` → "Runtime fixes upstream made to its own server"
now lists all four.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---
Moatless task:
https://moatless.soaplabstest.com/tasks/38d3e8f3-9a5a-4aa3-af58-4b8a67b97a86
Pipyakas pushed a commit to Pipyakas/t3code that referenced this pull request Oct 19, 2026
…gg#20147)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
(cherry picked from commit b47746b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

macroscope-review Opt PRs made by unvouched contributors in for Macroscope review. Vouched contributors auto-reviews size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: ERR_INSUFFICIENT_RESOURCES error on local dev

1 participant