Skip to content

Commit 2c559a4

Browse files
checkpoint
1 parent 9848dff commit 2c559a4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+995
-1952
lines changed

README.md

Lines changed: 1 addition & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1 @@
1-
# Svelte library
2-
3-
Everything you need to build a Svelte library, powered by [`sv`](https://npmjs.com/package/sv).
4-
5-
Read more about creating a library [in the docs](https://svelte.dev/docs/kit/packaging).
6-
7-
## Creating a project
8-
9-
If you're seeing this, you've probably already done this step. Congrats!
10-
11-
```sh
12-
# create a new project in the current directory
13-
npx sv create
14-
15-
# create a new project in my-app
16-
npx sv create my-app
17-
```
18-
19-
## Developing
20-
21-
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
22-
23-
```sh
24-
npm run dev
25-
26-
# or start the server and open the app in a new browser tab
27-
npm run dev -- --open
28-
```
29-
30-
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
31-
32-
## Building
33-
34-
To build your library:
35-
36-
```sh
37-
npm pack
38-
```
39-
40-
To create a production version of your showcase app:
41-
42-
```sh
43-
npm run build
44-
```
45-
46-
You can preview the production build with `npm run preview`.
47-
48-
> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment.
49-
50-
## Publishing
51-
52-
Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
53-
54-
To publish your library to [npm](https://www.npmjs.com):
55-
56-
```sh
57-
npm publish
58-
```
1+
The monorepo for my Markdown-related Svelte stuff! Check out `packages` for the published packages and `apps` for the docs site.

apps/docs/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.vercel

apps/docs/package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@
1212
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
1313
},
1414
"devDependencies": {
15-
"@sejohnson/hardened-svelte-markdown": "workspace:*",
16-
"@sejohnson/svelte-markdown": "workspace:*",
15+
"sveltedown": "workspace:*",
1716
"@shikijs/langs": "catalog:",
1817
"@shikijs/rehype": "catalog:",
1918
"@shikijs/themes": "catalog:",

apps/docs/src/lib/demo-page.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import remark_toc from 'remark-toc';
55
import rehype_raw from 'rehype-raw';
66
import remark_gfm from 'remark-gfm';
7-
import { type Options } from '@sejohnson/svelte-markdown';
7+
import { type Options } from 'sveltedown';
88
import rehypeShikiFromHighlighter from '@shikijs/rehype/core';
99
import type { HighlighterCore } from 'shiki/core';
1010
import type { Snippet } from 'svelte';

apps/docs/src/routes/docs/+page.svelte

Whitespace-only changes.

apps/docs/src/routes/hardened-svelte-markdown/+page.svelte

Lines changed: 0 additions & 26 deletions
This file was deleted.

apps/docs/src/routes/hardened-svelte-markdown/+page.ts

Lines changed: 0 additions & 65 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<script lang="ts">
2+
import DemoPage from '$lib/demo-page.svelte';
3+
import { AppendOnly } from 'sveltedown';
4+
import initial_content from './initial-content.md?raw';
5+
6+
let { data } = $props();
7+
</script>
8+
9+
<DemoPage highlighter={data.highlighter} {initial_content} title="sveltedown">
10+
{#snippet markdown({ content, rehypePlugins, remarkPlugins })}
11+
<AppendOnly {content} {rehypePlugins} {remarkPlugins} />
12+
{/snippet}
13+
</DemoPage>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# A demo of `sveltedown`'s `AppendOnly` component
2+
3+
This component works identically to the standard `Markdown` export, save that it is optimized for append-only operations like streaming text from a LLM. Under normal circumstances, if you render `Markdown` with some content:
4+
5+
```svelte
6+
<script lang="ts">
7+
let content = $state('');
8+
</script>
9+
10+
<button onclick={() => (content += '\n# This is another heading')}>Add another heading</button>
11+
<Markdown {content} />
12+
```
13+
14+
...every time `content` is modified, the _entire_ string has to be re-processed. This means:
15+
16+
- Parsing from string to `mdast`, the Markdown AST
17+
- Running `remark` plugins
18+
- Converting from `mdast` to `hast` (the HTML AST)
19+
- Running `rehype` plugins
20+
- Converting from `hast` to the Svelte runtime
21+
22+
This is extremely wasteful when you _know_ content is only ever going to be added to the Markdown document, never modified or removed. Thankfully, we can optimize for this use case. `AppendOnly` will:
23+
24+
- On initial render, process the entire `content` string and save the location of the start of the last block of root content. (Think heading, paragraph, blockquote, etc.)
25+
- When `content` changes, slice `content` from the saved location to the end. Process only this content
26+
- Replace the last root block with the first new block, and append any additional root blocks. If we append any additional root blocks, the start of the last one becomes our new "saved location"
27+
28+
> `remark` plugins are run prior to saving the last block start location. `rehype` plugins are run after.
29+
30+
What this means in practice is that the only text we're ever actually processing is the very last block-level content. The efficiency gain of rendering this way grows as the size of the markdown document grows.
31+
32+
## Rules
33+
34+
Because of this, there are rules. Well, only one, really. You **must not** perform any content edits other than appending. The behavior of doing so is undefined (and by undefined, I mean "will definitely break in very strange and unexpected ways). An extension of this rule is that you cannot use `remark` or `rehype` plugins that retroactively modify content -- think things like `remark-toc`, which go back to prior sections to insert nodes based on later nodes.
35+
36+
## Try it out
37+
38+
Add content after this to see it in action. Add content before this block to see how things will fall apart if you don't follow the rules.

apps/docs/src/routes/svelte-markdown/+page.svelte renamed to apps/docs/src/routes/playground/sveltedown/+page.svelte

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
11
<script lang="ts">
22
import DemoPage from '$lib/demo-page.svelte';
3-
import { Markdown } from '@sejohnson/svelte-markdown';
3+
import { Markdown } from 'sveltedown';
4+
import initial_content from './initial-content.md?raw';
45
56
let { data } = $props();
67
</script>
78

8-
<DemoPage
9-
highlighter={data.highlighter}
10-
initial_content={data.initial_content}
11-
title="@sejohnson/svelte-markdown"
12-
>
9+
<DemoPage highlighter={data.highlighter} {initial_content} title="sveltedown">
1310
{#snippet markdown({ content, rehypePlugins, remarkPlugins })}
1411
<Markdown {content} {rehypePlugins} {remarkPlugins} />
1512
{/snippet}

0 commit comments

Comments
 (0)