Skip to content

Commit dc4510c

Browse files
committed
fix(tables): revert toSorted to spread-sort for universal browser support
Array.prototype.toSorted is ES2023 runtime; SWC does not polyfill it and the default browserslist still includes browsers without it (iOS 15 Safari), so the tables page would crash there. [...result].sort() is non-mutating (sorts a copy, never touches the React Query cache array) and works everywhere; the perf delta is negligible. Correct the sim-react-performance rule doc to reflect that tsconfig lib only affects type-checking, not runtime availability.
1 parent cd25b34 commit dc4510c

2 files changed

Lines changed: 8 additions & 8 deletions

File tree

.claude/rules/sim-react-performance.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,19 +61,19 @@ for (const child of columns) {
6161

6262
Preserve `.find()`'s **first-match** semantics when duplicate keys are possible: `new Map(arr.map(...))` keeps the *last* entry, so guard with `if (!map.has(key))` when replacing a `.find()`. Skip this for tiny, cold arrays (a handful of items in an event handler) where the Map build costs more than it saves.
6363

64-
## Immutable array methods over spread-then-mutate
64+
## Never mutate a shared array in place
6565

66-
Use `toSorted()` / `toReversed()` / `with()` / `toSpliced()` instead of copying an array only to mutate the copy. One pass instead of copy-then-mutate, and non-mutating by construction (so it never risks mutating a React Query cache array in place — which a bare `.sort()` would).
66+
The real bug to avoid is `array.sort()` / `array.reverse()` on an array you don't own — sorting a React Query cache array in place corrupts shared state. Always sort a copy:
6767

6868
```typescript
69-
// ✗ Bad — copies just to sort the copy
70-
return [...items].sort(compare)
69+
// ✗ Bad — mutates the (possibly shared) source array in place
70+
return items.sort(compare)
7171

72-
// ✓ Good — sorts without the throwaway copy, still non-mutating
73-
return items.toSorted(compare)
72+
// ✓ Good — sorts a throwaway copy, source untouched
73+
return [...items].sort(compare)
7474
```
7575

76-
**Lib caveat:** these are ES2023. `apps/sim` sets `"lib": ["ES2023", ...]` in its `tsconfig.json`, so they type-check there. Packages under `packages/*` inherit the **ES2022** base tsconfig — in those, `toSorted` does not resolve; keep `[...arr].sort()`. Check the nearest `tsconfig` `lib` before reaching for these.
76+
**Do NOT reach for `toSorted()` / `toReversed()` / `with()` / `toSpliced()` on client render paths.** They are ES2023 *runtime* methods — and a tsconfig `"lib": ["ES2023"]` only makes them **type-check**, it does not make them **run**. Next/SWC compiles syntax but does **not** polyfill prototype methods, and the default browserslist still includes browsers without them (`toSorted` landed in Safari 16 / iOS 16, so any device capped at iOS 15 throws `TypeError: x.toSorted is not a function` and crashes the page). The perf difference vs `[...arr].sort()` is negligible (both allocate one array), so the copy-then-sort form is the correct default everywhere client code runs. Only consider the immutable methods in Node-only code (server routes, scripts) on Node ≥20, where the runtime is known.
7777

7878
## Local feature barrels are the convention — do not "fix" them
7979

apps/sim/app/workspace/[workspaceId]/tables/tables.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export function Tables() {
185185
}
186186
const col = activeSort?.column ?? 'updated'
187187
const dir = activeSort?.direction ?? 'desc'
188-
return result.toSorted((a, b) => {
188+
return [...result].sort((a, b) => {
189189
let cmp = 0
190190
switch (col) {
191191
case 'name':

0 commit comments

Comments
 (0)