| ... | ... | @@ -25,16 +25,25 @@ to Streamdown: |
| 25 | 25 | as adjacent content changes. This is done to preserve remounts for things like |
| 26 | 26 | custom `<a>` tags or other components. (For example, if a custom `<a>` fetches |
| 27 | 27 | previewing data and provides a hover card, that card won't flicker). |
| 28 | - **Better Prediction**: While optimizing edge cases, the prediction system became |
| 29 | better than the Streamdown one on accident. |
| 28 | 30 | - **Headless UI**: No built in styles or components, bring your own CSS to blend |
| 29 | 31 | your markdown with your existing theme. `@clo/react-markdown` simply takes in |
| 30 | 32 | your existing `unified` pipeline and works off of that. |
| 31 | | - **Easy to Audit**: ~850 lines of TypeScript. Main dependency is [unified]. |
| 33 | - **Easy to Audit**: Only ~1000 lines of modern TypeScript. 4 total files. |
| 32 | 34 | |
| 33 | 35 | [Streamdown]: https://streamdown.ai |
| 34 | 36 | [unified]: https://unifiedjs.com/ |
| 35 | 37 | |
| 36 | 38 | ## Getting Started |
| 37 | 39 | |
| 40 | Install off of the [JSR package](https://jsr.io/clo/react-markdown): |
| 41 | |
| 42 | ```sh |
| 43 | npx jsr add @clo/react-markdown |
| 44 | pnpm add jsr:@clo/react-markdown |
| 45 | ``` |
| 46 | |
| 38 | 47 | ```tsx |
| 39 | 48 | import { Markdown } from "@clo/react-markdown"; |
| 40 | 49 | import remarkGfm from "remark-gfm"; |
| ... | ... | @@ -70,6 +79,15 @@ export function HelloWorld() { |
| 70 | 79 | } |
| 71 | 80 | ``` |
| 72 | 81 | |
| 82 | If you want to play with the example project, which offers a comparison to |
| 83 | Streamdown and the non-memoized `react-markdown` package. |
| 84 | |
| 85 | ``` |
| 86 | git clone https://git.paperclover.net/clo/react-markdown |
| 87 | cd react-markdown |
| 88 | pnpm demo # auto-install |
| 89 | ``` |
| 90 | |
| 73 | 91 | ## Architecture |
| 74 | 92 | |
| 75 | 93 | The `Markdown` component is built out of a memoizer which uses the following tricks to improve performance: |
| ... | ... | @@ -89,7 +107,8 @@ The `Markdown` component is built out of a memoizer which uses the following tri |
| 89 | 107 | it means any places that might have used a reference link may now have to |
| 90 | 108 | reflect it. |
| 91 | 109 | - After all that, a special AST -> React node transform is used that diffs the |
| 92 | | new ast with the last ast, reusing React nodes whenever possible. This is what |
| 93 | | prevents most rerenders. |
| 110 | new ast with the last ast, reusing React nodes whenever possible. It supports |
| 111 | nested children as well as re-ordering top level blocks. This is what prevents |
| 112 | most rerenders and is the "secret sauce". |
| 94 | 113 | |
| 95 | 114 | All put together, basically nothing rerenders except what actually changed, and the document is beautiful. |