metonym / svelte-highlight

Syntax Highlighting for Svelte using highlight.js
https://svhe.onrender.com
MIT License
253 stars 13 forks source link

Feature Request - Work with Svelte-Markdown #246

Closed jdgamble555 closed 1 year ago

jdgamble555 commented 1 year ago

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

geerew commented 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

Niek commented 1 year ago

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...

metonym commented 1 year ago

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.

edman commented 1 year ago

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} />