An open API service indexing awesome lists of open source software.

https://github.com/sveltek/markdown

Svelte Markdown Preprocessor.
https://github.com/sveltek/markdown

kit markdown md mdx preprocess preprocessor svelte svelte-kit svelte-markdown svelte-md svelte-mdx svelte-plugin svelte-preprocess sveltek

Last synced: about 1 month ago
JSON representation

Svelte Markdown Preprocessor.

Awesome Lists containing this project

README

          



@sveltek/markdown

Svelte Markdown Preprocessor.


> [!NOTE]
>
> While the **API** is solid and mostly complete, some changes may still occur before the first stable release.
>
> Ideas, [suggestions](https://github.com/sveltek/markdown/discussions) and code [contributions](.github/CONTRIBUTING.md) are welcome.
>
> If you find any issues or bugs, please [report](https://github.com/sveltek/markdown/issues/new/choose) them so the project can be improved.


## Core Concepts

- **Custom Components:** Simplifies development by supporting `import`/`export` of reusable components.
- **Named Layouts:** Provides a powerful named `layout` mechanism to completely customize page design.
- **Unique Entries:** Defines specialized, `entry-level` configuration adapted for all markdown files.
- **Unified Plugins:** Enables content transformation using widely-adopted tools like `remark` and `rehype`.
- **Global Frontmatter:** Streamlines workflow by offering centralized options for markdown `metadata`.
- **Global Components:** Defines `global components` that can be used in all markdown files without manual setup.
- **Special Elements:** Supports parsing Svelte special elements such as `svelte:head` etc. in markdown files.
- **Code Highlighter:** Offers quick and easy customization for `syntax highlighting`.

## Intro

**Svelte Markdown** has been completely rewritten to take full advantage of `Svelte 5` and its `Runes` mode.

It’s a light, simple and powerful preprocessor designed specifically for managing `Markdown` content within `Svelte` projects.

Also, it comes with zero-config setup, built-in types and a dev-friendly API.

## Docs

The plan is to create online docs soon, so until its published, feel free to ask questions or share feedback in the official [Discussions](https://github.com/sveltek/markdown/discussions).

## Installation

```sh
# via pnpm
pnpm add -D @sveltek/markdown
```

```sh
# via npm
npm install -D @sveltek/markdown
```

## Usage

### Zero-Config Setup

```js
// svelte.config.js

import adapter from '@sveltejs/adapter-static'
import { svelteMarkdown } from '@sveltek/markdown'

/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [svelteMarkdown()],
extensions: ['.svelte', '.md'],
kit: { adapter: adapter() },
}

export default config
```

### Custom Config Setup

```js
// markdown.config.js

import { defineConfig } from '@sveltek/markdown'

export const markdownConfig = defineConfig({
frontmatter: {
defaults: {
layout: 'default',
author: {
name: 'Sveltek',
url: 'https://github.com/sveltek',
},
// other global data...
},
},
layouts: [
{
name: 'default',
path: 'lib/content/layouts/default/layout.svelte',
},
{
name: 'blog',
path: 'lib/content/layouts/blog/layout.svelte',
plugins: {
remark: [],
rehype: [],
},
},
// other layouts...
],
})
```

Import the config to the `svelte.config.js` file:

```js
// svelte.config.js

import adapter from '@sveltejs/adapter-static'
import { svelteMarkdown } from '@sveltek/markdown'
import { markdownConfig } from './markdown.config.js'

/** @type {import('@sveltejs/kit').Config} */
const config = {
preprocess: [svelteMarkdown(markdownConfig)],
extensions: ['.svelte', '.md'],
kit: { adapter: adapter() },
}

export default config
```

### Types

If you work with `TypeScript` and `Markdown` components, you can define types to avoid potential issues when importing `.md` into `.svelte` files.

```ts
// src/app.d.ts

declare global {
namespace App {
declare module '*.md' {
import type { Component } from 'svelte'

declare const MarkdownComponent: Component

export default MarkdownComponent
}
}
}

export {}
```

Now you can import `.md` file into `.svelte` without type errors:

```html

import Comp from '$lib/content/components/comp.md'

```

## Examples

> [!NOTE]
>
> More examples will be added to the online docs.

### Playground

Explore the [playground](https://github.com/sveltek/markdown/tree/main/playgrounds/sveltekit) to see more details.

### Custom Components

```markdown
---
title: Page Title
---

import { Component } from '$lib/components'

Children content

Content...
```

```markdown
---
title: Page Title
---

import { Component } from '$lib/components'

::Component

::Component prop="data"

::Component
Children content
::

Content...
```

### Named Layouts

```markdown
---
title: Page Title
layout: default
---

Content...
```

```markdown
---
layout: false
---

Content...
```

### Unique Entries

```markdown
---
title: Page Title
entry: blog
---

Content...
```

```markdown
---
entry: false
---

Content...
```

### Global Components

```ts
// markdown.config.js

import { defineConfig } from '@sveltek/markdown'

export const markdownConfig = defineConfig({
components: [
{
name: 'Link',
path: 'src/lib/components/ui/Link.svelte',
},
{
name: 'Button',
path: 'src/components/button/Button.svelte',
},
// ...
],
})
```

```markdown
---
title: About page
description: Svelte Markdown Preprocessor.
---

Content...
```

### Special Elements

```markdown
---
title: About page
description: Svelte Markdown Preprocessor.
layout: false
specialElements: true
---

Custom Title - {title}

p {
opacity: 0.6;
font-family: monospace;
font-size: 1.125rem;
}

{description}

Content...
```

## Code Highlighting

### Shiki Syntax Highlighter

#### rehypeShiki plugin

Recommended way is to simply import the official `rehypeShiki` plugin from `@sveltek/unplugins`.

It's super flexible and easy, you can apply it to just one page, to specific layouts, or to all pages if needed.

Plugin works without additional configuration, but if you want you can configure it further via plugin options.

> Install the required dependencies before use.
>
> ```sh
> pnpm add -D @sveltek/unplugins shiki
> ```

```ts
import { svelteMarkdown } from '@sveltek/markdown'
import { rehypeShiki } from '@sveltek/unplugins'

svelteMarkdown({
plugins: {
rehype: [[rehypeShiki, { theme: 'github-light-default' }]],
},
})
```

#### highlight option

It is also possible to use the `highlight` option which is a powerful way if you need more advanced configuration, but this require manual setup. Keep in mind that this applies to all pages, so it may not be desirable in every case.

> Install the required dependencies before use.
>
> ```sh
> pnpm add -D shiki
> ```

```ts
import { createHighlighter } from 'shiki'

const theme = 'github-dark-default'
const highlighter = await createHighlighter({
themes: [theme],
langs: ['javascript', 'typescript', 'svelte'],
})

svelteMarkdown({
highlight: {
highlighter: async ({ lang, code }) => {
return highlighter.codeToHtml(code, { lang, theme })
},
},
})
```

## Plugins

### Remark Table of Contents (Toc)

> Install the required dependencies before use.
>
> ```sh
> pnpm add -D @sveltek/unplugins
> ```

```js
import { remarkToc } from '@sveltek/unplugins'

svelteMarkdown({
plugins: {
remark: [remarkToc],
},
})
```

Usage in markdown page:

```markdown
---
title: Blog page
description: Read the latest news.
---

## What's New

## Featured Posts


```

### Remark Reading Stats

> Install the required dependencies before use.
>
> ```sh
> pnpm add -D @sveltek/unplugins
> ```

```js
import { remarkReadingStats } from '@sveltek/unplugins'

svelteMarkdown({
plugins: {
remark: [remarkReadingStats],
},
})
```

Usage in markdown page:

```markdown
---
title: Page title
---

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.

Reading Stats {JSON.stringify(readingStats)}

Reading Time: {readingStats.text}
```

## API

```ts
import { svelteMarkdown, defineConfig, compile } from '@sveltek/markdown'

import { escapeSvelte } from '@sveltek/markdown/utils'
```

### preprocessor

- Type: `function svelteMarkdown(config?: MarkdownConfig): PreprocessorGroup`

```ts
import { svelteMarkdown } from '@sveltek/markdown'

svelteMarkdown(config)
```

### defineConfig

- Type: `function defineConfig(config: MarkdownConfig): MarkdownConfig`

```ts
import { defineConfig } from '@sveltek/markdown'

defineConfig(config)
```

### compile

- Type: `function compile(source: string, options: CompileOptions): Promise`

```ts
import { compile } from '@sveltek/markdown'

compile(source, options)
```

### escapeSvelte

- Type: `function escapeSvelte(value: string): string`

```ts
import { escapeSvelte } from '@sveltek/markdown/utils'

escapeSvelte(value)
```

## Types

### main

Imports all types from the main package.

```ts
import type {
ASTScript,
CompileOptions,
Entries,
Entry,
FileData,
Frontmatter,
Highlight,
Layout,
Layouts,
MarkdownConfig,
Plugin,
PluginList,
Plugins,
} from '@sveltek/markdown'
```

## Options

All options are documented with descriptions and examples so autocompletion will be offered as you type. Simply hover over the property and see what it does in the quick info tooltip.

### extensions

- Type: `string[]`
- Default: `['.md']`

Specifies custom file extensions.

```ts
svelteMarkdown({
extensions: ['.md'],
})
```

### preprocessors

- Type: `PreprocessorGroup[]`
- Default: `undefined`

Specifies a custom list of preprocessors that will be applied to a Svelte file.

```ts
svelteMarkdown({
preprocessors: [vitePreprocess()],
})
```

### plugins

- Type: `{ remark: [], rehype: [] }`
- Default: `undefined`

Specifies the **top-level** plugins that will be used for all markdown files.

- **Lifecycle:** `plugins` → `layout.plugins` → `entry.plugins`

```ts
svelteMarkdown({
plugins: {
remark: [], // Specifies custom `remark` plugins at the top-level (optional).
rehype: [], // Specifies custom `rehype` plugins at the top-level (optional).
},
})
```

Also, plugins can be disabled at the **file-level**:

```markdown
---
title: Page title
plugins:
remark: false # Disables remark plugins for this file only
rehype: false # Disables rehype plugins for this file only
---

Content...
```

### layouts

- Type: `Layout[]`
- Default: `undefined`

Specifies a custom layout array.

Layout component serves as a wrapper for the markdown files, which means the page content is displayed via the component's children prop.

- **Lifecycle:** `plugins` → `layout.plugins` → `entry.plugins`

```ts
svelteMarkdown({
layouts: [
{
name: 'default',
path: 'lib/content/layouts/default/layout.svelte', // Specifies the path to the layout file (required).
plugins: {
remark: [], // Specifies custom `remark` plugins at the layout-level (optional).
rehype: [], // Specifies custom `rehype` plugins at the layout-level (optional).
},
},
{
name: 'blog',
path: 'lib/content/layouts/blog/layout.svelte',
},
],
})
```

Can be enabled at the **top-level** (via config) or at the **file-level** (via frontmatter).

**File-level**

```markdown
---
title: Page title
layout: blog
---

Content...
```

Also, layout plugins can be disabled at the **file-level**:

```markdown
---
title: Page title
layout:
name: blog
plugins:
remark: false # Disables remark layout plugins for this file only
rehype: false # Disables rehype layout plugins for this file only
---

Content...
```

**Config**

```ts
svelteMarkdown({
frontmatter: {
defaults: {
layout: 'default',
},
},
})
```

### entries

- Type: `Entry[]`
- Default: `undefined`

Specifies a custom entry array.

Entry serves as a special configuration for markdown files, which means it is similar to layout but without the need to create a custom component file.

Allows unique and straightforward customization for an individual markdown file. An entry can be a page or a component.

- **Lifecycle:** `plugins` → `layout.plugins` → `entry.plugins`

```ts
svelteMarkdown({
entries: [
{
name: 'blog',
plugins: {
remark: [], // Specifies custom `remark` plugins at the entry-level (optional).
rehype: [], // Specifies custom `rehype` plugins at the entry-level (optional).
},
},
],
})
```

Can be enabled at the **top-level** (via config) or at the **file-level** (via frontmatter).

**File-level**

```markdown
---
title: Page title
entry: blog
---

Content...
```

Also, entry plugins can be disabled at the **file-level**:

```markdown
---
title: Page title
entry:
name: blog
plugins:
remark: false # Disables remark entry plugins for this file only
rehype: false # Disables rehype entry plugins for this file only
---

Content...
```

**Config**

```ts
svelteMarkdown({
frontmatter: {
defaults: {
entry: 'default',
},
},
})
```

### components

- Type: `Component[]`
- Default: `undefined`

Defines global components that can be used in all markdown files without manual setup.

Especially useful for some generic components like buttons, links, images, etc.

#### Default import

```ts
svelteMarkdown({
components: [
{
name: 'GlobalButton', // Specifies the component name
path: 'src/components/button/Button.svelte', // Specifies the component path
},
// ...
],
})
```

```markdown
---
title: Home page
description: Svelte Markdown Preprocessor.
---

Content...
```

#### Named import

```ts
svelteMarkdown({
components: [
{
name: 'Link', // Specifies named import
path: 'src/components/link/index.ts', // Specifies import path from the barrel file
form: 'named', // Specifies the component import form
},
{
name: 'Link as MainLink', // Specifies named alias
path: 'src/components/link/index.ts',
form: 'named',
},
{
name: 'Tabs',
path: 'npm-package', // Specifies import path from the external package
form: 'named',
},
// ...
],
})
```

```markdown
---
title: Docs page
description: Get started with Svelte Markdown.
---

Content...
```

### frontmatter

- Type: `object`
- Default: `undefined`

Defines frontmatter custom options.

By default, frontmatter only supports the `YAML` format, but allows additional customization via parser.

#### defaults

- Type: `Record`
- Default: `undefined`

Specifies frontmatter global data to be applied to all markdown files.

```ts
svelteMarkdown({
frontmatter: {
defaults: {
author: 'Sveltek',
},
},
})
```

#### marker

- Type: `string`
- Default: `-`

Specifies the **start/end** symbols for the frontmatter content block.

It only works in combination with the default parser.

```ts
svelteMarkdown({
frontmatter: {
marker: '+',
},
})
```

#### parser

- Type: `(value: string) => Record | void`
- Default: `undefined`

Specifies a custom parser for frontmatter.

Allows adaptation to other formats such as `TOML` or `JSON`.

```ts
svelteMarkdown({
frontmatter: {
parser: (file) => {
// ...
},
},
})
```

### highlight

- Type: `object`
- Default: `undefined`

Defines custom syntax highlighting options.

#### highlighter

- Type: `(data: HighlightData) => Promise | string | undefined`
- Default: `undefined`

Specifies custom syntax highlighter.

```ts
svelteMarkdown({
highlight: {
highlighter: async ({ lang, meta, code }) => {
// ...
return code
},
},
})
```

### specialElements

- Type: `boolean`
- Default: `undefined`

Specifies support for parsing Svelte `special` elements such as [`svelte:head`](https://svelte.dev/docs/svelte/svelte-head) etc. in markdown files.

Can be enabled at the **top-level** (via config) or at the **file-level** (via frontmatter).

If you don't plan to use them in every markdown file, it is recommended to enable the option only on those pages where you really need it.

**File-level**

```markdown
---
title: Page title
specialElements: true
---

...

Content...
```

**Config**

```ts
svelteMarkdown({
frontmatter: {
defaults: {
specialElements: true,
},
},
})
```

## Credits

- Inspired by [MDsveX](https://github.com/pngwn/MDsveX)

## Contribute

Check out the quick [guide](.github/CONTRIBUTING.md) for more info.

## License

Developed in 🇭🇷 Croatia, © Sveltek.

Released under the [MIT](LICENSE.txt) license.