Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/size.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Size

# Tracks tree-shaken scenario costs per PR (#2883). scripts/size/ is a
# standalone npm package OUTSIDE the pnpm workspace on purpose: adding its
# tooling to the workspace graph re-keys pnpm peer instances (vitest,
# @codspeed/vitest-plugin), which relocates the benchmark harness and shows
# up as phantom CodSpeed regressions. The limits in size/.size-limit.js are
# the strict tree-shaking gate; the retained-module-graph assertions in
# packages/solid-signals/tests/treeshake.test.ts stay the which-module
# diagnostic underneath.
on:
pull_request:
branches: [main, next]

permissions:
contents: read
pull-requests: write

jobs:
# The hard gate: self-contained on the PR head, fails when any scenario
# exceeds its limit. Never depends on the base branch.
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm build
- run: npm ci --no-audit --no-fund
working-directory: scripts/size
- run: npm run size
working-directory: scripts/size

# Best-effort base-vs-head delta comment. Requires the base branch to also
# carry scripts/size/, so it is informational and never blocks: continue-on-error
# keeps bootstrap PRs (and any action hiccup) green.
compare:
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: pnpm
- uses: andresz1/size-limit-action@v1
continue-on-error: true
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
package_manager: npm
directory: scripts/size
build_script: build
1 change: 1 addition & 0 deletions scripts/size/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
48 changes: 48 additions & 0 deletions scripts/size/.size-limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Import-cost scenarios for #2883, measured against the built browser-prod
// artifacts. Bare specifiers resolve via esbuild aliases so nothing here
// touches the workspace dependency graph. Limits carry ~5% headroom over the
// sizes at landing: a breach means tree-shaking regressed (or a deliberate
// feature landed — bump the limit in the same PR and say why). The simple-app
// scenario is pinned at 10 KB on purpose.
const alias = {
"solid-js": "../../packages/solid/dist/solid.js",
"@solidjs/web": "../../packages/solid-web/dist/web.js",
"@solidjs/signals": "../../packages/solid-signals/dist/prod/index.js"
};
const modifyEsbuildConfig = config => ({ ...config, alias });

module.exports = [
{
name: "signals: core floor (createSignal/Memo/Effect/Root/flush)",
path: "../../packages/solid-signals/dist/prod/index.js",
import: "{ createSignal, createMemo, createEffect, createRoot, flush }",
limit: "7.1 KB",
modifyEsbuildConfig
},
{
name: "signals: + createStore",
path: "../../packages/solid-signals/dist/prod/index.js",
import: "{ createSignal, createMemo, createEffect, createRoot, flush, createStore }",
limit: "11.6 KB",
modifyEsbuildConfig
},
{
name: "signals: + isPending/latest",
path: "../../packages/solid-signals/dist/prod/index.js",
import: "{ createSignal, createMemo, createEffect, createRoot, flush, isPending, latest }",
limit: "8.75 KB",
modifyEsbuildConfig
},
{
name: "app: render + one signal (the simple-app floor)",
path: "minimal-app.js",
limit: "10 KB",
modifyEsbuildConfig
},
{
name: "app: CSR with Show/For/Loading/Errored/lazy",
path: "csr-app.js",
limit: "12 KB",
modifyEsbuildConfig
}
];
19 changes: 19 additions & 0 deletions scripts/size/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Size scenarios (#2883)

Tree-shaken import-cost tracking: `.size-limit.js` defines scenario entries
(signals floor, +createStore, +isPending/latest, the render+one-signal simple
app, a representative CSR app) with hard gzip-limits. CI fails when a scenario
exceeds its limit — that means tree-shaking regressed, or a deliberate feature
landed and the limit should be bumped in the same PR with a reason. The
simple-app scenario is pinned at 10 KB on purpose.

This directory is deliberately **outside the pnpm workspace**, with its own
npm lockfile. Its tooling must never enter the workspace dependency graph:
changing that graph re-keys pnpm peer instances (vitest,
@codspeed/vitest-plugin), which relocates the benchmark harness and shows up
as phantom CodSpeed regressions. Nothing here is published (`private: true`).

Run locally: `cd scripts/size && npm ci && npm run size` (build the repo
first). The retained-module-graph test in
`packages/solid-signals/tests/treeshake.test.ts` is the companion diagnostic
that names the re-coupled module when shaking breaks.
11 changes: 11 additions & 0 deletions scripts/size/csr-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// A representative CSR app surface: flow components, boundaries, lazy.
import { render, Show, For, Loading, Errored } from "@solidjs/web";
import { createSignal, createMemo, lazy } from "solid-js";

const [n, setN] = createSignal(0);
const Page = lazy(() => import("./lazy-page.js"));
render(() => {
const d = createMemo(() => n() + 1);
setN(1);
return [d(), Show, For, Loading, Errored, Page];
}, document.body);
1 change: 1 addition & 0 deletions scripts/size/lazy-page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => "page";
11 changes: 11 additions & 0 deletions scripts/size/minimal-app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// The "simple app" floor: render + one signal. Tracks the tree-shaken cost a
// hello-world CSR app ships (#2883).
import { render } from "@solidjs/web";
import { createSignal } from "solid-js";

const [count, setCount] = createSignal(0);
render(() => {
const el = document.createElement("button");
el.onclick = () => setCount(count() + 1);
return el;
}, document.getElementById("app"));
Loading
Loading