# Migrate to prism-react-renderer + react-diff-viewer-continued > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace highlight.js and hand-rolled DiffViewer with prism-react-renderer and react-diff-viewer-continued for GitHub-quality code blocks and diff rendering. **Architecture:** (1) Install new deps and remove old ones, (2) Rewrite CodeViewer using prism-react-renderer's Highlight component with render props, (3) Rewrite DiffViewer using react-diff-viewer-continued with syntax highlighting via prism, (4) Update MarkdownRenderer to use a React-based code block instead of HTML strings, (5) Delete highlightCode.ts and hljs CSS. **Tech Stack:** prism-react-renderer (Highlight + themes.github), react-diff-viewer-continued (ReactDiffViewer), React 18, Tailwind CSS 4 --- ## File Map | Action | File | Responsibility | |--------|------|----------------| | Modify | `desktop/package.json` | Add prism-react-renderer + react-diff-viewer-continued, remove highlight.js + diff | | Rewrite | `desktop/src/components/chat/CodeViewer.tsx` | Pure React code blocks via prism-react-renderer | | Rewrite | `desktop/src/components/chat/DiffViewer.tsx` | GitHub PR-style diffs via react-diff-viewer-continued | | Rewrite | `desktop/src/components/markdown/MarkdownRenderer.tsx` | Use CodeViewer React component instead of HTML strings for code blocks | | Delete | `desktop/src/components/chat/highlightCode.ts` | No longer needed | | Modify | `desktop/src/theme/globals.css` | Remove .hljs-* CSS rules | **Consumers that import these files (no changes needed to their code):** - `ToolCallBlock.tsx` imports `CodeViewer` and `DiffViewer` — same Props interface, no changes - `ToolResultBlock.tsx` imports `CodeViewer` — same Props interface, no changes - `PermissionDialog.tsx` imports `DiffViewer` — same Props interface, no changes --- ### Task 1: Install dependencies **Files:** - Modify: `desktop/package.json` - [ ] **Step 1: Install new dependencies** ```bash cd /Users/nanmi/workspace/myself_code/claude-code-haha/desktop && npm install prism-react-renderer react-diff-viewer-continued ``` - [ ] **Step 2: Remove old dependencies** ```bash cd /Users/nanmi/workspace/myself_code/claude-code-haha/desktop && npm uninstall highlight.js @types/diff diff ``` Note: `diff` was only used by `DiffViewer.tsx`. `highlight.js` was only used by `CodeViewer.tsx` and `highlightCode.ts`. - [ ] **Step 3: Verify no broken imports** ```bash cd /Users/nanmi/workspace/myself_code/claude-code-haha/desktop && npx tsc --noEmit 2>&1 | head -20 ``` Expected: Errors about missing `highlight.js` and `diff` modules (since files still import them). This is fine — we fix those in subsequent tasks. - [ ] **Step 4: Commit** ```bash cd /Users/nanmi/workspace/myself_code/claude-code-haha && git add desktop/package.json desktop/package-lock.json && git commit -m "chore: add prism-react-renderer + react-diff-viewer-continued, remove highlight.js + diff" ``` --- ### Task 2: Rewrite CodeViewer with prism-react-renderer **Files:** - Rewrite: `desktop/src/components/chat/CodeViewer.tsx` - [ ] **Step 1: Replace the entire CodeViewer.tsx** ```tsx import { useState } from 'react' import { Highlight, themes } from 'prism-react-renderer' import { CopyButton } from '../shared/CopyButton' type Props = { code: string language?: string maxLines?: number showLineNumbers?: boolean } export function CodeViewer({ code, language, maxLines = 20, showLineNumbers = true }: Props) { const [expanded, setExpanded] = useState(false) const allLines = code.split('\n') const isTruncated = !expanded && allLines.length > maxLines const visibleCode = isTruncated ? allLines.slice(0, maxLines).join('\n') : code // Only show line numbers for known languages (actual code). // Plain text, file trees, command output look better without them. const effectiveShowLineNumbers = showLineNumbers && !!language && language !== 'text' const languageLabel = language || 'code' const lineCountLabel = `${allLines.length} ${allLines.length === 1 ? 'line' : 'lines'}` const showExpandToggle = allLines.length > maxLines return (
{tokens.map((line, i) => {
const lineProps = getLineProps({ line })
return effectiveShowLineNumbers ? (
{i + 1}
{line.map((token, key) => (
))}
) : (
{line.map((token, key) => (
))}
)
})}
)}