Markdown
Render math expressions that don't require a full TeX distribution at build-time with MathJax or KaTeX.
Markdown + Svelte: Interweave markdown and Svelte components and syntax in your Svelte files.
Forgiving: SvelTeX will try to ensure your markup wouldn't yield unexpected results according to CommonMark, possibly making whitespace adjustments before passing it to the markdown processor.
Directives: Use markdown directives syntax, incl. curly brackets, without confusing the Svelte compiler.
Frontmatter: Set page metadata for SEO, import resources with
<link>
s, define JS variables, and more, all from within frontmatter written in YAML, TOML, or JSON.Custom transformers: Inject custom transformers to pre- and post-process the in- and output of the math renderer, respectively.
Backends
In order of recommendation:
unified (recommended) [web / github / npm]: The backbone of MDX (among many other things), unified has the largest ecosystem of plugins, many of which are maintained by the core team. Furthermore, it has several big sponsors, so it's continued maintenance and development is all but assured.
Note that unified is not a markdown parser in and of itself, but rather an umbrella term for an ecosystem of parsers and processors working with abstract syntax trees (ASTs). In this case, the SvelTeX uses
remark
to parse the markdown into a MDAST (Markdown AST),remark-rehype
to convert the MDAST to a HAST (Hypertext AST), andrehype
to serialize the HAST to HTML.The only downsides that I can think of are that the sheer size of the ecosystem can be somewhat overwhelming (especially due to its highly modularized nature, though said modularity is also a big advantage in many other ways), and that, in my view, plugin development or low-level customization within the unified ecosystem has a rather steep learning curve. However, this only matters if you're actually planning to develop plugins or do low-level customization, which, given the vastness of the plugin ecosystem, will probably not be necessary in the majority of use-cases.
markdown-it
[github / npm / demo]: This robust, CommonMark-compliant markdown parser is used by many SSGs, including Eleventy, Hugo, and VitePress. It has a solid ecosystem of plugins, and is generally well-maintained.micromark
[github / npm]: The parser powering unified, this is an extremely tiny dependency. Though extensible and fully CommonMark compliant, It'll seldom be the case that you should pick this overremark
/rehype
(which we refer to as "unified" above), since the latter offer a more high-level API and generally a more extensive ecosystem of plugins. Nonetheless, it's still supported, and a solid option.marked
[web / github / npm / demo]: The oldest of the bunch,marked
is a fast and widespread markdown parser. However, it's plugin ecosystem is not as extensive as that ofmarkdown-it
orunified
, and it lags behind the other two in terms of CommonMark and GFM compliance.
Configuration
Don't try to enable MDX syntax in your markdown parser when using SvelTeX, as it may conflict with SvelTeX's own parsing.
Hint: Hover over the different properties in the code block to show some IntelliSense.
// sveltex.config.js
import { sveltex } from '@nvl/sveltex';
export default await sveltex(
{ markdownBackend: 'unified' },
{
markdown: {
remarkPlugins: [],
retextPlugins: [],
rehypePlugins: [],
remarkRehypeOptions: {},
rehypeStringifyOptions: {},
// Common options
components: [],
prefersInline: () => true,
strict: false,
transformers: {
pre: [],
post: [],
},
},
},
);
// sveltex.config.js
import { sveltex } from '@nvl/sveltex';
export default await sveltex(
{ markdownBackend: 'markdown-it' },
{
markdown: {
extensions: [],
options: {
// markdown-it options
},
// Common options
components: [],
prefersInline: () => true,
strict: false,
transformers: {
pre: [],
post: [],
},
},
},
);
// sveltex.config.js
import { sveltex } from '@nvl/sveltex';
export default await sveltex(
{ markdownBackend: 'micromark' },
{
markdown: {
options: {
// micromark options
extensions: [],
htmlExtensions: [],
allowDangerousProtocol: false,
defaultLineEnding: undefined,
},
// Common options
components: [],
prefersInline: () => true,
strict: false,
transformers: {
pre: [],
post: [],
},
},
},
);
// sveltex.config.js
import { sveltex } from '@nvl/sveltex';
export default await sveltex(
{ markdownBackend: 'marked' },
{
markdown: {
extensions: [],
options: {
// marked options
},
// Common options
components: [],
prefersInline: () => true,
strict: false,
transformers: {
pre: [],
post: [],
},
},
},
);
Frontmatter
Languages
---
title: Example
---
# {title}
Lorem ipsum dolor.
---toml
title = "Example"
---
# {title}
Lorem ipsum dolor.
---json
{
title: "Example"
}
---
# {title}
Lorem ipsum dolor.
Variables
All properties defined in the frontmatter are accessible in the markup as variables:
- Top-level properties are accessible as variables of the same name.
- Nested properties are accessible as nested objects.
Example
---
prop: Example
arr:
- a
- b: text
c: 299792458
- - d
- e
obj:
a: foo
b:
b1: bar
b2: baz
c:
- c1
- 2
---
Use the frontmatter variables like you would any other variable:
- As-is: {prop}
- In markdown: _{arr[1].b}_
- In HTML: <span>{arr[1].c}</spa.n>
- In attributes: <img src={objb.b2} alt={obj.c[0]}>
- In Svelte components: <Example>{obj.b.b1}</Example>
- In Svelte component attributes: <Example {prop} x={obj.a}/>
In effect, the frontmatter above will result in the following lines being added to the Svelte file's <script>
block:
<script>
// ...
const prop = 'Example';
const arr = ['a', { b: 'text', c: 299792458 }, ['d', 'e']];
const obj = { a: 'foo', b: { b1: 'bar', b2: 'baz' }, c: ['c1', 2] };
</script>
NB: You can't use the variables in math expressions, code spans, code blocks, or verbatim environments.
Head elements
You can set many of the page's <head>
elements from the frontmatter.
The frontmatter content is not sanitized or validated by SvelTeX. In particular, if you pass in invalid content to the properties described below, you may end up with invalid HTML elements in your page's <head>
element.
Title, noscript
The title
and noscript
properties set the page's <title>
and <noscript>
elements, respectively.
---
title: Example
noscript: JS disabled.
---
<svelte:head>
<title>Example</title>
<noscript>JS disabled</noscript>
</svelte:head>
Meta
All standard metadata names are supported.
---
application-name: Name
author: Alice
charset: utf-8
color-scheme: normal
description: Text
generator: Svelte
keywords: a, b
referrer: no-referrer
theme-color: black
viewport: width=device-width, initial-scale=1
---
<svelte:head>
<meta name="application-name" content="Name">
<meta name="author" content="Alice">
<meta charset="utf-8">
<meta name="color-scheme" content="normal">
<meta name="description" content="Text">
<meta name="generator" content="Svelte">
<meta name="keywords" content="a, b">
<meta name="referrer" content="no-referrer">
<meta name="theme-color" content="black">
<meta name="viewport" content="width=device-width, initial-scale=1">
</svelte:head>
Alternative forms
You can also set the meta tags with a meta
object or array. Meta tags defined in a meta
object or array have precedence over those defined as top-level properties.
Note that, while these forms are equivalent to the shorter form above in terms of the meta
tags they generate, the variables that will be defined in the script
tag will be different, as these always follow the structure of the frontmatter one-to-one.
---
meta:
application-name: Name
author: Alice
charset: utf-8
color-scheme: normal
description: Text
generator: Svelte
keywords: a, b
referrer: no-referrer
theme-color: black
viewport: width=device-width, initial-scale=1
---
---
meta:
- name: application-name
content: Name
- name: author
content: Alice
- name: charset
content: utf-8
- name: color-scheme
content: normal
- name: description
content: Text
- name: generator
content: Svelte
- name: keywords
content: a, b
- name: referrer
content: no-referrer
- name: theme-color
content: black
- name: viewport
content: width=device-width, initial-scale=1
---
Link
---
link:
- rel: stylesheet
href: styles.css
- rel: preload
href: someFont.woff2
as: font
type: font/woff2
crossorigin: anonymous
---
<svelte:head>
<link rel="stylesheet" href="styles.css">
<link rel="preload" href="someFont.woff2" as="font" type="font/woff2" crossorigin="anonymous">
</svelte:head>
Base
---
base: https://example.com
---
<svelte:head>
<base href="https://example.com"/>
</svelte:head>
Alternative forms
You can also set the base
tag with an object. The object must have a href
property, and may have a target
property.
---
base:
href: https://example.com
target: _blank
---
<svelte:head>
<base href="https://example.com" target="_blank"/>
</svelte:head>