MDsveX
MDsveX copied to clipboard
Can't substitute <pre> elements for components
Layouts allow providing Svelte components to be rendered instead of certain HTML elements that markdown generates, but that doesn't seem to apply to <pre>
or <code>
elements.
Perhaps this has something to do with the fact that they undergo special treatment with the default syntax highlighter, but I think this deserves a note in the docs. Or maybe it is possible to substitute them, which would be great!
Steps to reproduce
- Clone the Svelte template
- Install
mdsvex
:yarn add -D mdsvex
- Set up MDsveX in
rollup.config.js
:
// ...
import { mdsvex } from 'mdsvex';
export default {
// ...
plugins: [
// ...
svelte({
extensions: ['.svelte', '.svx'],
preprocess: mdsvex({
layout: './src/layout.svelte',
}),
}),
// ...
- Add an MDsveX file (
src/test.svx
) with the following content:
```js
alert()
```
- Add a layout file (
src/layout.svelte
) exporting thepre
element (also createsrc/pre.svelte
with content.<pre><slot /></pre>
to see a dot before every<pre>
element):
<script context="module">
import pre from './pre.svelte';
export { pre };
</script>
<slot />
- Import the SVX into
src/App.svelte
Yeah, this doesn't work which is expected but perhaps undesirable.
This is simply because of how the markup for code blocks is generated, which is slightly different to other markdown elements.
It should be possible to make this work, I'll take a look at it.
Found a workaround:
Make a custom highlighter function and change the pre
tags to Components.pre
;
Mine looks like this:
highlight: {
highlighter: (code, lang) => {
if (lang && Prism.languages[lang]) {
const parsed = Prism.highlight(code, Prism.languages[lang]);
const escaped = parsed.replace(/{/g, '{').replace(/}/g, '}');
const langTag = 'language-' + lang;
// This thing below ↓↓↓↓
return `<Components.pre class=${langTag}><code class=${langTag}>${escaped}</code></Components.pre>`;
} else {
const escaped = code.replace(/{/g, '{').replace(/}/g, '}');
return `<Components.pre><code>${escaped}</code></Components.pre>`;
}
},
},
<script context="module">
import { pre } from "./defaults";
export { pre };
</script>
MDsveX replaces all html tags with Components.{tag}
so we basically tell it to do the same with pre
This isn't public API and could change at any time, so I wouldn't recommend this approach (although it would work fine as a workaround). I'll have a real fix for this soon.
I managed to make my own Svelte component receive the direct props from the highlighter this way. This lets me make a single Svelte component for both MDsveX and normal Svelte code.
highlight: {
highlighter: (code, lang) => {
return `<Components.pre code={\`${escape(code)}\`} lang={\`${lang}\`} />`;
},
}