Closed jdgamble555 closed 1 year ago
I've had a look at svelte-markdown (im working on something similar). Under the hood svelte-markdown uses markedjs, which supports code fences (3 ticks with a language)
svelte-markdown also lets you override renderers. So you could override the code renderer with a custom component that would use svelte-highlight.
For example, you could create a Code.svelte component ..
<script lang="ts">
import { HighlightAuto } from 'svelte-highlight';
export let type: 'code';
export let raw: string;
export let codeBlockStyle: 'indented' | undefined = undefined;
export let lang: string | undefined = undefined;
export let text: string;
// Disable warning about unused variables
type;
raw;
codeBlockStyle;
lang;
</script>
<HighlightAuto code={text} />
Then in your +page.svelte , or where you call svelte-markdown set your new renderer with renderers={{code: Code.svelte}}
The only issue I see is with the language, which is why I used HighlightAuto in the above. markedjs (and inturn svelte-markdown) will return the language as text, but the Highlight
component in svelte-highligh want a Language object. To get this language object you have to explicitly know the language ahead of time and import it in the code
Svelte component.
If you are only rendereing a a handful of languages then your custom code
component could just import a select few. If you want to support all languages then you are limited to HighlightAuto
Thanks for the pointer @geerew, this worked for me:
<script lang="ts">
import { HighlightAuto } from "svelte-highlight";
import style from "svelte-highlight/styles/edge-light";
export let type: "code";
export let raw: string;
export let codeBlockStyle: "indented" | undefined = undefined;
export let lang: string | undefined = undefined;
export let text: string;
// Disable warnings
type = "code";
raw;
codeBlockStyle;
lang;
</script>
<svelte:head>
{@html style}
</svelte:head>
<HighlightAuto code={text} />
I disabled it though, since it blows up the final JS size with 500KB...
I disabled it though, since it blows up the final JS size with 500KB...
This is because of HighlightAuto
, which loads all grammars since it doesn't know what syntax to highlight. If possible, I would recommend loading only the grammars you need and using the Highlight
component.
HighlightAuto
bundle size is acceptable, but it's too slow. It's also sad that svelte-markdown may give you a lang
prop, but you can't pass it to HighlightAuto
. I considered directly importing a few languages that I intend to support, and then pick the right one from lang
in a switch statement, but this is not ideal.
Ultimately I used highlight.js directly (without svelte-highlight). The speed is acceptable for my needs (you can run it on a service worker), and there is less bloat if you can use the highlight.js/lib/common
subset.
Similar to previous answers, I wrote a MardownCode
component as follows:
// MarkdownCode.svelte
<script lang="ts">
import hljs from 'highlight.js/lib/common';
import 'highlight.js/styles/github.css';
export let lang: string;
export let text: string;
$: highlightedCode = lang
? hljs.highlight(text, { language: lang }).value
: hljs.highlightAuto(text).value
</script>
<div class="mt-4 rounded-lg relative">
<pre><code class="hljs rounded-lg">{@html highlightedCode}</code></pre>
</div>
Then I configured svelte-markdown to use it like so
<script lang="ts">
import SvelteMarkdown from '@dogagenc/svelte-markdown';
import MarkdownCode from './MarkdownCode';
export let source: string;
const renderers = { code: MarkdownCode };
</script>
<SvelteMarkdown {source} {renderers} />
I think this could be possible if you could turn this on for the whole component, and not child components?
Would be nice.
Thanks,
J