cb9c5dda59
The comment panel lagged for seconds on open and stuttered on every resolve/apply
with many comments (real case: 30 open + 326 resolved ≈ 356 threads), because each
comment body mounted a full TipTap/ProseMirror editor, both tabs mounted at once,
and any mutation re-rendered the whole list.
- CommentContentView: static recursive renderer of comment ProseMirror JSON (no
editor instance) for the read-only body — supports exactly CommentEditor's node
set (doc/paragraph/text/hardBreak/mention) + marks (bold/italic/strike/code/
link), reproducing the 3-level DOM nesting for pixel-identical CSS. Unknown
node/mark or unparseable content degrades that one comment to the read-only
CommentEditor; legacy non-JSON strings render as plain text.
SECURITY: link hrefs are protocol-allowlisted (safeHref, mirroring
@tiptap/extension-link) so a stored comment with a `javascript:`/`data:` href
cannot XSS — the old TipTap read-only path sanitized this; the static renderer
must too. Control-char smuggling (java\tscript:) is stripped before the check.
- MentionContent extracted from MentionView, shared by the TipTap NodeView and the
static renderer (identical user/page-mention behavior).
- keepMounted={false} on the tabs: the inactive tab no longer mounts its editors.
- Lazy reply editor: a stub until click/focus, then the real editor (kept mounted
so the draft survives thread re-renders).
- React.memo(CommentListItem) + a childrenByParent map (replaces the per-thread
O(n^2) filter) + localized reply-send pending state: resolve/apply/reply now
re-render only the touched thread.
- Progressive first paint: useCommentsQuery no longer blocks on hasNextPage.
Gate: client comment+mention suites 22/22 passed, tsc --noEmit 0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
React + TypeScript + Vite
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Currently, two official plugins are available:
- @vitejs/plugin-react uses Babel for Fast Refresh
- @vitejs/plugin-react-swc uses SWC for Fast Refresh
Expanding the ESLint configuration
If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
- Configure the top-level
parserOptionsproperty like this:
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: ['./tsconfig.json', './tsconfig.node.json'],
tsconfigRootDir: __dirname,
},
- Replace
plugin:@typescript-eslint/recommendedtoplugin:@typescript-eslint/recommended-type-checkedorplugin:@typescript-eslint/strict-type-checked - Optionally add
plugin:@typescript-eslint/stylistic-type-checked - Install eslint-plugin-react and add
plugin:react/recommended&plugin:react/jsx-runtimeto theextendslist