morethanwords/tweb/master • 1ddddac • 2 files, +39/-2
Fix big emoji disappearing in production builds
An emoji-only message stopped rendering big and animated once built — in dev it
was always fine, which is what made it look like a settings or server problem.
src/vendor/emoji/regex.ts held lone surrogates in its string value: the upstream
pattern splits astral emoji across alternations, so '\uD83C[\uDFFB-\uDFFF]' has
a high surrogate with nothing to pair with. Rolldown folds that constant into
the bundle and re-encodes it as UTF-8, where a lone surrogate has no
representation — in index.worker-*.js every one of them came out as U+FFFD
followed by the leftover "d83c", 1246 times. Evaluating the shipped pattern
confirms it: 😳 🔥 👍 😀 no longer match, while ❤ ☝ ⌚ still do, because those
are BMP and were never written as surrogates.
So the worker's FULL_REG_EXP produced no messageEntityEmoji for any astral
emoji, totalEntities carried none, and bubbles' emojiStrLength === strLength
test could never hold — bigEmojis stayed 0, no .emoji-big, no animated sticker.
Only the worker chunk was affected, which is why the input's own suggestions
kept working: those are parsed on the main thread.
The literal is pure ASCII now — every \u and \x backslash is doubled, so the
escapes stay text and RegExp resolves them itself when the pattern compiles.
Same matching, and nothing left in the string for a bundler to mangle. A test
pins both halves: the source stays ASCII, and parseEntities still returns an
emoji entity spanning the whole emoji. A clean build has zero U+FFFD in any
chunk.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
morethanwords/tweb/master • 1d0ec11 • 1 files, +7/-0
Stop rebuilding the emoji suggestions for an emoji already suggested
Typing 😳 into an input that already ended in 😳 tore the suggestion strip down
and built it again from scratch: a fresh searchCustomEmoji, a new container for
every item, replaceWith, and the scroll back at zero — all to arrive at exactly
what was on screen.
checkAutocomplete only guards against an unchanged value, but the emoticon is
derived from it: getCustomEmojiSuggestionEmoticon slices from the emoji entity
that ends at the caret, so a longer value can still name the same emoji.
checkEmoticon took it from there unconditionally.
It returns early now when the emoticon matches the one already on screen. The
helper has to be visible for that — hidden means the strip was torn down and
must be rebuilt, and it also covers an in-flight request that a hide cancelled.
A different emoticon, or a `:query` search (which clears this.emoticon), still
renders as before.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#webk
Post #20533
187
- 🫡 3