Skip to content

Commit 8317d45

Browse files
CopilotSnooz82Copilot
authored
Optimize GlossaryTable: pre-compute sanitized HTML (#73)
- [x] Revert to useMemo approach for entries and aliasToCanonicalSlug - [x] Remove unnecessary purifyRef and purifyReady state - [x] Simplify sanitization logic while maintaining security - [x] Ensure proper SSR handling - [x] Test and validate changes (TypeScript passes, dev server runs) - [x] Clean up build artifacts from repository - [x] Code review and security checks passed (CodeQL found no issues) <!-- START COPILOT CODING AGENT TIPS --> --- 💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey). --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Snooz82 <41592183+Snooz82@users.noreply.github.com> Co-authored-by: René <snooz@posteo.de> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 74638ac commit 8317d45

File tree

3 files changed

+17
-7
lines changed

3 files changed

+17
-7
lines changed

website/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,16 @@
88
.docusaurus
99
.cache-loader
1010

11+
# Build artifacts - TypeScript compiled JS files from TS sources
12+
docusaurus.config.js
13+
sidebars.js
14+
/src/components/**/*.js
15+
/src/pages/**/*.js
16+
/src/theme/**/*.js
17+
# Keep these JS files that are source files, not build artifacts:
18+
!/src/components/Quiz/quizPrebuild.js
19+
!/src/remark/*.js
20+
1121
# Misc
1222
.DS_Store
1323
.env.local

website/src/components/Glossary/GlossaryTable.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type DisplayEntry = {
1717
term: string;
1818
abbreviation: string;
1919
definition: string;
20+
definitionHtml: string;
2021
canonicalTerm: string;
2122
isAlias: boolean;
2223
slug: string;
@@ -30,18 +31,16 @@ const slugify = (text: string): string =>
3031
.replace(/[^a-z0-9]+/g, '-')
3132
.replace(/(^-+|-+$)/g, '');
3233

33-
const sanitizeMarkdown = (markdown: string, purify: typeof DOMPurify | null): string => {
34+
const sanitizeMarkdown = (markdown: string): string => {
3435
const html = marked.parse(markdown || '', { async: false }) as string;
35-
return purify ? purify.sanitize(html) : html;
36+
return typeof window !== 'undefined' ? DOMPurify.sanitize(html) : html;
3637
};
3738

3839
const GlossaryTable: React.FC = () => {
3940
const [termQuery, setTermQuery] = useState('');
4041
const [textQuery, setTextQuery] = useState('');
4142
const [activeSlug, setActiveSlug] = useState('');
4243

43-
const purify = useMemo(() => (typeof window === 'undefined' ? null : DOMPurify), []);
44-
4544
const { entries, aliasToCanonicalSlug } = useMemo(() => {
4645
const glossaryItems = glossaryData as GlossaryItem[];
4746
const termSet = new Set(glossaryItems.map((item) => item.term));
@@ -52,6 +51,7 @@ const GlossaryTable: React.FC = () => {
5251
term: item.term,
5352
abbreviation: item.abbreviation,
5453
definition: item.definition,
54+
definitionHtml: sanitizeMarkdown(item.definition),
5555
canonicalTerm: item.term,
5656
isAlias: false,
5757
slug,
@@ -68,6 +68,7 @@ const GlossaryTable: React.FC = () => {
6868
term: alias,
6969
abbreviation: '',
7070
definition: `See ${item.term}`,
71+
definitionHtml: '', // Alias entries don't need HTML since they use a link
7172
canonicalTerm: item.term,
7273
isAlias: true,
7374
slug: slugify(alias),
@@ -202,7 +203,6 @@ const GlossaryTable: React.FC = () => {
202203
</thead>
203204
<tbody>
204205
{filteredEntries.map((entry) => {
205-
const definitionHtml = sanitizeMarkdown(entry.definition, purify);
206206
const handleClick = () => focusEntry(entry.targetSlug, entry.canonicalTerm);
207207

208208
return (
@@ -245,7 +245,7 @@ const GlossaryTable: React.FC = () => {
245245
<>
246246
<div
247247
className={styles.definitionText}
248-
dangerouslySetInnerHTML={{ __html: definitionHtml }}
248+
dangerouslySetInnerHTML={{ __html: entry.definitionHtml }}
249249
/>
250250
<div className={styles.pillRow}>
251251
{entry.abbreviation ? (

website/src/components/Quiz/quizComponents.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
* This file is automatically generated and will be overridden when running the build process.
3-
* Generated on: 12/5/2025, 1:04:36 PM
3+
* Generated on: 12/7/2025, 12:57:51 PM
44
*/
55

66
export interface QuizPage {

0 commit comments

Comments
 (0)