morethanwords/tweb/master • 6cd749c • 6 files, +348/-169
Fix stories never opening in production builds
Clicking a story did nothing on the built app while dev was fine — `actions.set`
threw before it could hand the peer to the viewer:
TypeError: Cannot read properties of undefined (reading 'index')
at getNearestStory <- getNearestStories <- checkForNearestSkipped <- set
The logic was right, the bundle was not. `getNearestStory`'s parameter defaults
read `state`, and the minifier bound that read to `ep` — clientPip's module-level
`state`, normally `undefined` — while the body of the very same function kept the
correct name. The source map settles it: minified `ep` maps to store.tsx:133, name
`state`, so one source symbol was emitted under two names. viewer.tsx had it twice
as well, `wasPlaying = !stories.paused` reading `Kd.paused` off a premium-feature
descriptor, so closing any popup resumed a story that was paused.
Both resolve their defaults in the function body now, where the minifier gets the
binding right. rolldown 1.2.3 still miscompiles the old shape, so this is not
something an upgrade fixes.
scripts/check-bundle-mangling.mjs catches the class rather than the pattern, since
the trigger never reproduced in isolation: for every identifier in a default value
— parameter, destructuring, class field — it asks the source map which source
variable it came from and checks how that variable is spelled everywhere else in
the chunk. One dominant spelling plus a stray one is the signature. It finds
exactly these four in the shipped bundle and nothing else, and now runs at the end
of `pnpm build`. It also fails on any U+FFFD, which is how the astral emoji regex
died in the worker chunk.
Vite 8.2.1 comes along: rolldown 1.2.3 no longer rewrites lone surrogates in
folded constants, the trap that one cost us.
`build.cssTarget` is explicit now. `target: 'es2020'` says nothing about browsers,
so lightningcss lowered every logical property into a pair of `:lang()` rules,
emitted after the block they came from and with a higher specificity — a physical
`left` authored next to `inset-inline-*` silently lost, which is what pinned the
emoji panel to the window edge. Naming versions that support logical properties
natively drops 13680 `:lang()` selectors to 1824 and 157 KiB off the CSS. RTL is
unaffected: it runs off `documentElement.dir`, which index.ts sets for every
language.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
morethanwords/tweb/master • e3730e1 • 300 files, +1278/-1325
Build
#webk
Post #20535
162
- 🫡 3