react-codemirror-runmode 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -3
- package/dist/react-highlighter.js +3 -2
- package/package.json +22 -22
- package/src/react-highlighter.tsx +11 -1
- package/test/fixtures/large.html +17604 -0
- package/test/index.spec.tsx +22 -0
- package/test/perf.bench.tsx +64 -0
- package/tsconfig.json +2 -0
package/test/index.spec.tsx
CHANGED
|
@@ -203,4 +203,26 @@ describe('React Highlighter', () => {
|
|
|
203
203
|
expect(element).toHaveProperty('className', 'ͼp')
|
|
204
204
|
expect(screen.getByText('123')).toHaveProperty('className', 'ͼu')
|
|
205
205
|
})
|
|
206
|
+
|
|
207
|
+
it('swaps in a freshly created wrapper once highlighting resolves', async () => {
|
|
208
|
+
const { container } = render(
|
|
209
|
+
<code>
|
|
210
|
+
<Highlighter lang="js" theme={oneDarkHighlightStyle}>
|
|
211
|
+
{'const x = 123'}
|
|
212
|
+
</Highlighter>
|
|
213
|
+
</code>
|
|
214
|
+
)
|
|
215
|
+
const pendingWrapper = container.querySelector('code > span')
|
|
216
|
+
expect(pendingWrapper).not.toBeNull()
|
|
217
|
+
|
|
218
|
+
await sleep(100)
|
|
219
|
+
|
|
220
|
+
// Reusing the pending element would make React insert every highlighted span
|
|
221
|
+
// into the already-attached DOM one at a time, which is ~25x slower on large
|
|
222
|
+
// input. The wrapper must be a genuinely new element.
|
|
223
|
+
const resolvedWrapper = container.querySelector('code > span')
|
|
224
|
+
expect(resolvedWrapper).not.toBe(pendingWrapper)
|
|
225
|
+
expect(resolvedWrapper?.getAttribute('style')).toContain('display: contents')
|
|
226
|
+
expect(container.textContent).toBe('const x = 123')
|
|
227
|
+
})
|
|
206
228
|
})
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { resolve } from 'node:path'
|
|
3
|
+
|
|
4
|
+
import { oneDarkHighlightStyle } from '@codemirror/theme-one-dark'
|
|
5
|
+
import { createRoot } from 'react-dom/client'
|
|
6
|
+
import { bench, describe } from 'vitest'
|
|
7
|
+
|
|
8
|
+
import { highlightCode, Highlighter } from '../src'
|
|
9
|
+
|
|
10
|
+
const page = readFileSync(resolve(process.cwd(), 'test/fixtures/large.html'), 'utf8')
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Rendering ~90k spans into jsdom costs seconds per iteration, so the defaults
|
|
14
|
+
* (5 warmup + 10 timed runs) would take minutes. Keep the run bounded.
|
|
15
|
+
*/
|
|
16
|
+
const RENDER_BENCH_OPTIONS = { time: 0, iterations: 5, warmupTime: 0, warmupIterations: 1 }
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolves once the highlighted spans are in the document. The pending state is
|
|
20
|
+
* itself a single wrapper `<span>`, so waiting for *any* span would return
|
|
21
|
+
* immediately and measure nothing — hence the count.
|
|
22
|
+
*/
|
|
23
|
+
const waitForHighlight = (host: HTMLElement) =>
|
|
24
|
+
new Promise<void>(resolve => {
|
|
25
|
+
const poll = () => (host.querySelectorAll('span').length > 1 ? resolve() : setTimeout(poll, 5))
|
|
26
|
+
poll()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
describe(`html highlighting (${(page.length / 1024).toFixed(0)}KB)`, () => {
|
|
30
|
+
bench('highlightCode: parse + tokenize', async () => {
|
|
31
|
+
await highlightCode(
|
|
32
|
+
'html',
|
|
33
|
+
page,
|
|
34
|
+
oneDarkHighlightStyle,
|
|
35
|
+
undefined,
|
|
36
|
+
undefined,
|
|
37
|
+
(text, style, from, to) => ({ text, style, from, to })
|
|
38
|
+
)
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Rendered through createRoot rather than @testing-library/react so the
|
|
42
|
+
// measurement excludes act() overhead and each iteration starts on an empty DOM.
|
|
43
|
+
bench(
|
|
44
|
+
'Highlighter: parse + tokenize + React render into jsdom',
|
|
45
|
+
async () => {
|
|
46
|
+
const host = document.createElement('div')
|
|
47
|
+
document.body.appendChild(host)
|
|
48
|
+
const root = createRoot(host)
|
|
49
|
+
|
|
50
|
+
root.render(
|
|
51
|
+
<code>
|
|
52
|
+
<Highlighter lang="html" theme={oneDarkHighlightStyle}>
|
|
53
|
+
{page}
|
|
54
|
+
</Highlighter>
|
|
55
|
+
</code>
|
|
56
|
+
)
|
|
57
|
+
await waitForHighlight(host)
|
|
58
|
+
|
|
59
|
+
root.unmount()
|
|
60
|
+
host.remove()
|
|
61
|
+
},
|
|
62
|
+
RENDER_BENCH_OPTIONS
|
|
63
|
+
)
|
|
64
|
+
})
|