Skip to content

feat(app-shell): the precise sideEffects array and the gate that keeps it honest - #6735

Merged
os-sales merged 2 commits into
mainfrom
claude/issue-6683-sideeffects-array-and-gate
Aug 29, 2026
Merged

feat(app-shell): the precise sideEffects array and the gate that keeps it honest#6735
os-sales merged 2 commits into
mainfrom
claude/issue-6683-sideeffects-array-and-gate

Conversation

@os-sales

@os-salesos-sales commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

Fixes#6683

Implements the 2026-08-29 ruling in its only accepted shape: the precise sideEffects ARRAY plus the companion gate, as one unit, with the MAX_EAGER_CLOSURE_GZIP_BYTES downward re-baseline in the same commit.

⚠️ Read this first: the ruled effect does NOT re-verify. The array buys 55.3 KiB, not 242.6 KB

The ruling said "Expected effect re-verified at landing: ~242.6 KB gzip off the console eager closure, headroom ~0.9% → ~8%." Measured on this branch, that does not hold, and the reason is measured rather than argued.

eager closure (gzip)KiBeager chunksthe three at-risk registrations
today (9486ac672, this branch's base)3,310,6723233.149 of 5081 chunk each
this PR (f905b0753)3,254,0043177.748 of 5131 chunk each
"sideEffects": false (option C, disproven)3,067,7602995.949 of 5200 chunks each
  • This PR: −56,668 gzipped bytes (−55.3 KiB, 1.71% of the closure).
  • "sideEffects": false on today's tree: −242,912 bytes (−237.2 KiB) — reproducing the card's 242.6 KB within measurement noise, and dropping four live registrations (the three named plus cloud-connection:panel).

The 242.6 KB figure was false's number, not the array's. The card says so; the ruling then carried it forward as the array's expected effect. It cannot be the array's: the difference between the two rows is exactly the closure the ten registering modules anchor — metadata-admin alone is 168.6 KiB and stays eager because views/metadata-admin/index.ts registers previews and inspectors at module top level. Keeping those registrations is the correctness the ruling required; keeping them keeps their import closure eager. ⛔ Nothing here was reshaped to chase the projected number — that would be option C by another name.

Headroom, stated both ways so the tightening is not confused with the win:

measuredceilingheadroomas % of closurevs the 89.0 KiB regression
before3,310,6723,345,00034,328 B (33.5 KiB)1.04%0.38x
after, old ceiling3,254,0043,345,00090,996 B (88.9 KiB)2.73%1.00x — the exit-2 edge
after, this PR's ceiling3,254,0043,300,00045,996 B (44.9 KiB)1.41%0.50x

So headroom goes 0.9%-class → 1.4%-class, not → 8%. It is not "0.9% and any static import trips it" any more, but this card does not end the near-zero-headroom condition. #6681 (~194 KiB of AppContent's other lazy() declarations, metadata-admin the bulk of it) is now the lever that would.

What shipped

1. The array — 23 entries, derived, not copied

packages/app-shell/package.json names its entry forms (./dist/index.js, ./src/index.ts, and ./src/styles.css — a stylesheet a bundler must never drop) plus the ten modules that register at load time, each in both its source and its published spelling. Consumers resolve exports to dist/; the in-repo bundler aliases resolve to src/, and a bundler reads the same manifest for both.

The enumeration was re-derived mechanically by the gate below, never pasted. It returned 10, which matches the card's "measured at 10 today" — stated as an agreement between two independent derivations, not as an input:

@object-ui/app-shell — 10 module(s) with a top-level registration, 432 walked
src/console/cloud-connection/CloudConnectionPanel.tsx
src/console/connect/ConnectAgentWidget.tsx
src/console/diagnostics/CloudAiModelStatus.tsx
src/console/home/CloudOnboardingNext.tsx
src/console/marketplace/InstalledListWidget.tsx
src/services/builtinComponents.tsx
src/views/metadata-admin/index.ts
src/views/record-approvals-renderer.tsx
src/views/record-attachments-renderer.tsx
src/views/studio-design/studio-canvas-preview.tsx

The broad scan finds 15 modules with any top-level effect. The five that are not in the array are named here rather than glossed: src/index.ts (the barrel — in the array as an entry form anyway); three X.displayName = 'X' writes on the module's own binding (ConsoleNotificationBanners, ImpersonationBanner, LocalizedSidebarTrigger), provably module-local; and src/views/RecordDetailView.tsx, whose only effect is a bare import of record-approvals-renderer — a propagation edge, and the barrel bare-imports that module directly anyway. Marking RecordDetailView would have held 47.4 KiB eager for every barrel consumer and bought nothing.

2. scripts/check-side-effects-array.mjs — the ruled companion gate

Workspace-general (it also validates @object-ui/layout's existing array). One rule: the array names exactly the entry forms plus every module in the entry graph that performs a top-level registration, in both spellings. It fails on

  • MISSING — a registering module the array does not name (the silent drop, exit 1);
  • STALE — a name whose module no longer registers anything (exit 1);
  • UNREACHABLE — a registrar that no chain of covered modules reaches from the barrel. Naming a module is not enough: a barrel → pure-helper → registrar chain still loses the registration, because the shakeable helper takes the registrar's only edge with it;
  • an unrecognised top-level effect (exit 2, a verdict about the gauge). This is the load-bearing asymmetry: "I did not recognise that" and "that is not a registration" must not be the same answer. classifyEffect treats any top-level call or new as a registration — deliberately not a register-name test, because a name test under-reads and an under-read here is exactly the silent drop. Registry.add(...) is caught.

Exit codes follow this repo's convention: 0 agree, 1 the array is wrong, 2 no trustworthy enumeration.

3. scripts/check-sdui-registration-pins.mjs — the artifact half

The static gate cannot answer the question the hazard turns on: does a real bundler reading that array still emit the registrations. "sideEffects": false is statically coherent and drops three of them. This gate weighs apps/console/dist/assets/*.js for every registration key the array's modules declare, read through scripts/component-registrations.mjsthe key set is derived from the array, so there is no second list. RULED_CONTROLS is a floor on that derivation (the three keys the ruling names), not the population; a test pins that the two never coincide.

Every zero is loud: no dist/ is exit 2, an empty key set is exit 2, and a negative-control key that must be found in zero chunks is searched on every run, because a matcher that cannot miss reports every key present forever.

4. MAX_EAGER_CLOSURE_GZIP_BYTES: 3,345,000 → 3,300,000

Over a measured 3,254,004 on bd2a7ec50. The array took 56,668 bytes out of the closure — more than the old ceiling's entire 45,102-byte headroom — so leaving the ceiling put would park the aggregate gauge at exactly 1.00x its own sensitivity, one byte of shrink from the exit-2 verdict. Both numbers move in one commit, as that file requires. BASELINE moves with it (48 chunks of 513). The per-chunk ceilings did not move: those three chunks are byte-identical before and after, and their headrooms are 0.21x / 0.04x / 0.05x.

5. Two entries leave DECLARED_LAZY_VIEWS_STILL_EAGER — a recorded win, not a trim

The first build on the array failed, correctly, in the ledger's missing direction:

[declared-lazy-views] 2 pinned view(s) are NO LONGER in the eager closure...
- packages/app-shell/src/views/RecordFormPage.tsx
- packages/app-shell/src/views/ReportView.tsx

Those two were pinned for chunk co-tenancy (#6680) — held eager by a co-tenant in their own chunk, with no import edge to the view. The package-level array makes those co-tenants (providers/expressionUser.ts, views/RuntimeDraftBar.tsx) shakeable in their own right, the chunks they anchored stopped being eager, and both views fell out. The lines are deleted because the build named them; counter-probe 1 (every declared view must be found in some chunk) ran green on the same build, which is what separates "became lazy" from "the matcher stopped matching". After: 7/8 views AppContent declares lazy are genuinely lazy; 1 eager, all pinned. This does not close#6680 — it removes this instance of it; the chunking-policy question that card raises is untouched.

The chunks that moved

 -49030 gz plugin-dashboard (49030 -> 0) -4122 gz ReportView (4122 -> 0)
-9325 gz index (161486 -> 152161) -3662 gz MetadataProvider (3662 -> 0)
-8555 gz metadata-admin (181207 -> 172652) -3128 gz MarketplacePage (3128 -> 0)
-2312 gz RecordFormPage (2312 -> 0) -1620 gz AdapterProvider (1620 -> 0)
-1510 gz ManagedByBadge (1510 -> 0) -607 gz drillUrlFilters (607 -> 0)
-600 gz skeletons (600 -> 0) -574 gz utils (762 -> 188)
+19459 gz src (0 -> 19459) +3625 gz CreateViewDialog (0 -> 3625)
+1828 gz SkeletonDetail (0 -> 1828) +1066 gz RuntimeDraftBar (0 -> 1066)

The new eager src chunk is the ten registering modules being pulled into one place. It is the array's cost, and it is the smaller half of the trade.

Controls, shown RED — a pin that cannot fail is not a pin

Both ablations ran from a committed tree (bd2a7ec50), each under a trap '<restore>' EXIT INT TERM with absolute paths, each confirming the mutation reached disk by anchored grep -c counts and a blob hash that differs from HEAD's, and each proving the restore by observation — git diff HEAD empty andgit hash-object equal to the HEAD blob — never by an editor's exit code. Exit codes were captured before any pipe.

Ablation A — "sideEffects": false (option C reproduced on today's tree).

HEAD blob : 5bde8d042730748b8ccb7d7320db26b33e8aef41
injected '"sideEffects": false' occurrences : 1 (want 1)
remaining 'ConnectAgentWidget' occurrences : 0 (want 0)
mutated blob: 3305b7496d43d8c5e3eedb025ddb5f1ecdbd1432
STATIC_GATE_EXIT=0 BUILD_EXIT=0 PINS_EXIT=2 BUDGET_EXIT=2
restored blob: 5bde8d042730748b8ccb7d7320db26b33e8aef41
git diff HEAD bytes for the target: 0 (want 0)
RESTORE OK: blob identical to HEAD and git diff HEAD is empty.

Chunk counts read off that build's dist/:

keywith "sideEffects": falseon this PR
mcp:connect-agent0 chunks1 chunk
cloud:onboarding-next0 chunks1 chunk
cloud:ai-model-status0 chunks1 chunk
cloud-connection:panel0 chunks1 chunk
marketplace:installed-list1 chunk1 chunk

The registration pin gate exits 2, naming all three ruled controls: "Either a sideEffects array stopped naming the module that registers the key — which is the silent drop, and must be fixed rather than re-pinned — or the reader has stopped seeing it." The budget gate exits 2 as well: the closure fell to 2995.9 KiB and the aggregate ceiling drifted to 2.55x the regression — the objectui#5924 sensitivity verdict working.

⚠️ Reported rather than smoothed: the static gate exits 0 here. "sideEffects": false takes the package out of this gate's population by construction — that direction belongs to side-effects-declaration-consistency.test.ts's "no sideEffects: false package has a load-time side effect", which is red on that manifest. Two gates, two populations, and the boundary is stated so nobody reads the 0 as approval.

Ablation B — the array with ONE control module removed (the shape the dispatch asked for: both spellings of ConnectAgentWidget deleted, 23 entries → 21).

'ConnectAgentWidget' before: 2 (want 2) after: 0 (want 0)
mutated blob: a2dc376d69b2f6ed799439fc502a8c6e895e79b4
STATIC_GATE_EXIT=1 BUILD_EXIT=0 PINS_EXIT=2 BUDGET_EXIT=0
restored blob: 5bde8d042730748b8ccb7d7320db26b33e8aef41 | 'ConnectAgentWidget' back to: 2 | git diff HEAD bytes: 0
❌ @object-ui/app-shell: `sideEffects` disagrees with the derived enumeration.
MISSING "./dist/console/connect/ConnectAgentWidget.js" — this module registers at load time ...
MISSING "./src/console/connect/ConnectAgentWidget.tsx" — this module registers at load time ...

and the build that came out of it, read chunk by chunk — surgical, exactly the excluded module and nothing else:

keyarray minus one moduleon this PR
mcp:connect-agent0 chunks1 chunk
cloud:onboarding-next1 chunk1 chunk
cloud:ai-model-status1 chunk1 chunk
cloud-connection:panel1 chunk1 chunk
marketplace:installed-list1 chunk1 chunk

⚠️ Note the pin gate's code here is 2, not 1. Because the key set is derived from the array, a module leaving the array also removes its key from the pinned set, so the RULED_CONTROLS floor fires before the chunk count is read. That ordering is deliberate and is the louder verdict — the ruling's own instruction is that this must be fixed rather than re-pinned. The exit-1 path ("named, and still absent from the bundle") is the array-honoured-but-bundler-dropped case, covered by fixture in check-sdui-registration-pins.test.ts.

Gate discrimination, established rather than assumed.check-side-effects-array.test.ts (23 cases) fails the gate on: a missing registrar, a missing published spelling, a missing entry form, a stale name, a name that exists nowhere, an unrecognised top-level effect, a glob, an unresolved specifier, a spelling map that does not round-trip, a registrar reachable only through a shakeable module, and an empty population — each with the partner case that passes. Against the real manifest it asserts both directions in one test: removing ConnectAgentWidget makes evaluatePackage red while the shipped manifest stays green.

Gate verdicts — every exit code captured before any pipe, on f905b0753 after the final commit

gateexitits own verdict line
check:eager-closure0Console eager closure is 3177.7 KB gzipped across 48 of 513 chunks (budget: 3222.7 KB, headroom: 44.9 KB).
check:sdui-registration-pins0All 12 registration(s) a sideEffects array promises are present in the built console (513 chunks weighed; the 3 ruled control(s) are in the derived set).
check:side-effects-array0@object-ui/app-shell: sideEffects names exactly the 10 module(s) that register at load time, plus its entry forms (23 entries, 432 modules walked).
console vite build0[declared-lazy-views] 7/8 views AppContent declares lazy are genuinely lazy; 1 eager, all pinned (objectui#6535).
check:docs-route-closure0all 13 packages named in registerCatalogBlocks.ts are accounted for
check:changeset-presence0No source of a released package changed in this range, so no changeset is owed. (a changeset ships anyway — see below)
check:changeset-no-major / -fixed0 / 0No changeset declares a major bump. / All workspace packages are in the changeset fixed group.
check:control-bytes0check-control-bytes: OK (scanned 5588 tracked text file(s); skipped 85 binary).
check:entry-guard053 scripts/ file(s) — no entry guard outside the baseline; 48 export bindings, 48 of them inert on import
check:esm-specifiers0Specifier leg: no un-ledgered package emits an extensionless relative specifier.
check:self-import0No package names itself inside its own src/.
check:phantom-deps0Every in-scope import is declared by the package that publishes it.
check:doc-fences / check:doc-links0 / 0every TypeScript block in 223 document(s) is fenced ... / Links are valid across 17 scan roots.
pnpm type-check:scripts0tsc -p tsconfig.scripts.json, no diagnostics
vitest scripts/__tests__/0Test Files 87 passed (87) / Tests 2425 passed (2425)
vitest manifest readers + packages/layout/0Test Files 21 passed (21) / Tests 261 passed (261)

The console build and every closure figure quoted above were produced by the same build on f905b0753; the report it wrote reads eagerGzipBytes 3254004, byte-identical to the figure BASELINE records for bd2a7ec50 — which is the check that the recorded commit and this head build the same tree (check-*.mjs is not in the console build's turbo inputs; scripts/vite-*.ts is).

Why a changeset ships even though the gate says none is owed

check-changeset-presence.mjs guards <pkg>/src/**. This diff changes packages/app-shell/package.json and no source, so the gate correctly reports nothing owed — and a sideEffects change is a published contract change that every consumer's bundler reads. The changeset spells out what it means for a consumer, at minor (objectui's major follows @objectstack's). That the gate cannot see this class of change at all is filed separately, below.

Declared narrowings — what was NOT run here, and why that is a measurement

ESLint. Repo-wide turbo run lint was not run; ESLint ran on the 8 changed JS/TS files. Three things make that a measurement rather than a gap: (1) the population came from ESLint's own resolution — all 8 returned real result objects, none reported as ignored; (2) the counts are read from --format json: 8 files linted, errorCount 0 and warningCount 0 on every one; (3) eslint.config.js configures no projectService, no project and no type-checked ruleset, so no rule's verdict on a file this PR does not touch can depend on this diff. CI runs the full farm regardless.

check:readme-exports — NOT MEASURED, not green and not red. It exits 1 in this worktree with 379 findings of the form "its type entry ./dist/index.d.ts is not on disk — run pnpm build first", across every package including ones this PR does not touch. That is the unbuilt-tree prerequisite, not a verdict on this diff (which changes no README and no exports/types field). CI builds packages before running it.

⚠️Repo-scoped vs package-scoped. Package-scoped and verified here: the array, both new gates, the re-baselined constants, the ledger change, the console build and its closure. Repo-scoped and therefore UNVERIFIED until CI speaks: the full pnpm test farm, turbo run lint, turbo run type-check, and check:readme-exports on a built tree.

Findings filed, not fixed here

Authoring session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49

Fences respected

packages/app-shell/src/** is untouched — the barrel's exports and its bare side-effect imports are exactly as they were; this PR changes the package's manifest, not its code. apps/console/vite.config.ts is untouched. scripts/vite-declared-lazy-views.ts is edited only in its ledger and its prose, both demanded by its own build-time verdict.


Generated by Claude Code

… that keeps it honest
`@object-ui/app-shell` declared no `sideEffects` field, so every bundler had to
assume every module in it does something on import and nothing in the package
was shakeable. `"sideEffects": false` is not the answer and is closed by
measurement: it drops three live SDUI widget registrations to zero chunks on a
green build. The package now declares the precise ARRAY -- its entry forms plus
the ten modules that register at load time, in both source and published
spellings.
An incomplete array fails silently inside a CONSUMER's bundle, so the array
never ships alone (maintainer ruling, 2026-08-29):
- `scripts/check-side-effects-array.mjs` re-derives the enumeration from the
module bodies and fails on a missing registrar, a stale name, a registrar no
chain of covered modules reaches, or a top-level effect it does not recognise.
- `scripts/check-sdui-registration-pins.mjs` weighs the built console for every
registration the array promises, with the key set derived from the array
itself.
`MAX_EAGER_CLOSURE_GZIP_BYTES` is re-baselined downward, 3,345,000 -> 3,300,000
over a measured 3,254,004, in the same commit -- the array took 56,668 gzipped
bytes out of the closure, more than the old ceiling's whole headroom.
Two entries leave `DECLARED_LAZY_VIEWS_STILL_EAGER`: `RecordFormPage` and
`ReportView` are no longer eager, because the co-tenant modules that anchored
their chunks became shakeable. The build named both, which is what a recorded
win looks like there.
Fixes#6683
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
…rement was taken on
The constant is not a build input — the console build's turbo `inputs` cover
`scripts/vite-*.ts`, not `scripts/check-*.mjs` — so this commit's tree builds
identically to the one it names, and the figure was re-measured on it.
Part of #6683
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CRJge11jso9TpXRWFt1Z49
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 48 chunks)3177.8 KB3222.7 KB
Main entry chunk (gzip)148.2 KB350 KB
Entry fileindex-e6Jw7zwb.js
StatusPASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)11.89KB4.50KB
app-shell (runtime-config.js)20.61KB7.35KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)511.66KB116.30KB
core (index.js)5.30KB2.13KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)173.10KB47.96KB
fields (index.js)239.31KB60.18KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (fallbackInterpolation.js)6.25KB2.77KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)26.89KB9.04KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)5.60KB2.33KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.89KB12.91KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)190.33KB45.10KB
plugin-dashboard (index.js)133.44KB34.48KB
plugin-designer (index.js)212.87KB43.19KB
plugin-detail (index.js)245.29KB62.39KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)132.01KB32.23KB
plugin-gantt (index.js)165.20KB40.37KB
plugin-grid (index.js)201.53KB54.54KB
plugin-kanban (index.js)53.11KB14.62KB
plugin-list (index.js)113.11KB27.58KB
plugin-map (index.js)20.17KB6.66KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.51KB11.94KB
plugin-timeline (index.js)26.44KB7.59KB
plugin-tree (index.js)9.00KB3.08KB
plugin-view (index.js)85.87KB21.12KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)4.47KB1.63KB
react (SchemaRenderer.js)67.73KB22.54KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)2.44KB1.21KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)20.57KB5.88KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)10.35KB3.60KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)2.74KB1.41KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)3.75KB1.85KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.85KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (icon-key-migration.js)4.26KB1.63KB
types (index.js)4.72KB2.24KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment