perf(Message): hoist regex compilation in message text rendering - #3202
Merged
Conversation
…Text countEmojis/messageTextHasEmojisOnly and the emoji markdown rehype plugin each compiled their own ~15KB emoji RegExp on every call. Build it once in a shared emojiRegex.ts module and reuse the single instance. Safe because every consumer resets lastIndex before use: String#match/#replace do so internally, and hast-util-find-and-replace resets it before scanning. A new test asserts that reset directly so a future library version cannot silently break the shared instance.
messageCodeBlocks and matchMarkdownLinks created their RegExp literals on every call. Hoist codeRegex, regexMdLinks, and singleMatch to module scope. Safe: the first two are used only with String#match (resets lastIndex) and singleMatch is non-global (.exec ignores lastIndex).
|
Size Change: +739 B (+0.11%) Total Size: 652 kB 📦 View Changed
ℹ️ View Unchanged
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #3202 +/- ##
==========================================
+ Coverage 83.70% 83.73% +0.03%
==========================================
Files 435 436 +1
Lines 13130 13131 +1
Branches 4252 4252
==========================================
+ Hits 10990 10995 +5
+ Misses 2140 2136 -4 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
MartinCupela
approved these changes
Jun 3, 2026
github-actions Bot
pushed a commit
that referenced
this pull request
Jun 5, 2026
## [14.4.0](v14.3.0...v14.4.0) (2026-06-05) ### Bug Fixes * **compat:** restore React 17/18 compatibility in certain components ([#3197](#3197)) ([b513b69](b513b69)) * general performance and bug fixes ([#3201](#3201)) ([57c5795](57c5795)) * **interop:** unwrap CJS default exports (react-player, @emoji-mart/react) ([#3199](#3199)) ([4cddb02](4cddb02)) * maintain topmost modal non-inert ([#3206](#3206)) ([7ad98fa](7ad98fa)) ### Features * allow to stack modals on top of each other ([#3203](#3203)) ([4c934ae](4c934ae)) * display notifications above modals ([#3200](#3200)) ([0433090](0433090)) * **Reactions:** send emoji_code with reactions for push notification rendering ([#3209](#3209)) ([2faa620](2faa620)) ### Performance Improvements * **Message:** hoist regex compilation in message text rendering ([#3202](#3202)) ([8c018a4](8c018a4)) * **VideoPlayer:** lazy-load react-player to keep it out of the main bundle ([#3204](#3204)) ([18dc966](18dc966))
|
🎉 This PR is included in version 14.4.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Goal
Eliminate repeated
RegExpcompilation in the message text–rendering hot path* from the Vercel React best-practices audit (PERFORMANCE_AUDIT.md,js-hoist-regexp). These regexes were recompiled per render / perrenderTextcall; they are now compiled once at module load.🛠 Implementation details
Two commits:
perf(Message): reuse one compiled emoji regex …emoji-regexcompiles a ~15KB source string on everyemojiRegex()call.countEmojis/messageTextHasEmojisOnly(Message/utils.tsx) and the emoji markdown rehype plugin (renderText/rehypePlugins/emojiMarkdownPlugin.ts) each built their own instance per call. Introducedsrc/components/Message/emojiRegex.tsexporting a single sharedEMOJI_REGEX, imported by both. Used a dedicated leaf module (rather than re-exporting fromutils.tsx) so the lightweightrenderTextplugin doesn't pull inutils.tsx's heavier module graph or risk a circular import.perf(Message): hoist renderText code-block and markdown-link regexesmessageCodeBlocks/matchMarkdownLinks(renderText/regex.ts) created theirRegExpliterals on every call. HoistedcodeRegex,regexMdLinks, andsingleMatchto module scope, matching the existingdetectHttppattern in the same file.Safety (shared global regex): the emoji regex is global, so it carries a mutable
lastIndex. Every consumer resetslastIndexbefore scanning —String#match/#replacedo so internally, andhast-util-find-and-replaceresets it before each use (lib/index.js:155). A new test,renderText/__tests__/emojiMarkdownPlugin.test.ts(4 tests), guards this — including one that poisonslastIndexand assertsfindAndReplaceresets it, so a future version of that library can't silently break the shared instance.