A Vite plugin that transforms Markdown files into HTML, allowing you to import and use Svelte components directly in your Markdown content. Extensible with remark and rehype plugins.
<p>, <h1>, <pre>, etc.) with your custom Svelte components{, }) in code blocksnpm install @khotwa/jana
Add Jana to your vite.config.js or vite.config.ts:
import { defineConfig } from 'vite'
import { jana } from '@khotwa/jana'
export default defineConfig({
plugins: [
jana()
// ... other plugins
]
})
Add .md to the extensions in your svelte.config.js:
const config = {
extensions: ['.svelte', '.md']
// ... rest of your config
}
Import Markdown files directly as Svelte components:
<script>
import Post from './Post.md'
</script>
<Post />
In SvelteKit, you can use Markdown files directly as route pages:
src/routes/blog/+page.md
The Markdown file will be automatically processed and rendered as a Svelte page when accessed via the route.
You can import and use Svelte components directly inside your Markdown files:
<script>
import MyComponent from './MyComponent.svelte'
</script>
# My Blog Post
This is regular markdown content.
<MyComponent />
You can use components anywhere in your markdown!
Prose components let you replace standard HTML tags with your own Svelte components. For example, you can replace every <p> with a custom <P> component that adds styling, or every <pre> with a <Pre> component that adds a copy button.
By default, Jana scans src/lib/components/prose/ for Svelte files that match known HTML tag names:
src/lib/components/prose/
P.svelte → wraps all <p> tags
H1.svelte → wraps all <h1> tags
Pre.svelte → wraps all <pre> tags
Code.svelte → wraps all <code> tags
A.svelte → wraps all <a> tags
Just create the file and Jana picks it up automatically. No config needed.
Supported tag names: A, Blockquote, Code, Em, H1-H6, Hr, Img, Li, Ol, P, Pre, Strong, Table, Tbody, Td, Th, Thead, Tr, Ul.
Change the scan directory with the prose option:
jana({
prose: 'src/components/prose'
})
Map HTML tags to specific component paths directly:
jana({
components: {
p: '$lib/components/P.svelte',
pre: '$lib/components/CodeBlock.svelte',
h1: '$lib/components/Heading.svelte'
}
})
Explicit components override auto-scanned ones, so you can use both — auto-scan for most tags and explicit config for specific overrides.
When you use a prose component for pre, Jana automatically passes code block metadata as props:
```js title="example.js" highlight
console.log('hello')
```
Your Pre.svelte component receives:
<script>
let { lang, title, highlight, children } = $props()
// lang = "js", title = "example.js", highlight = true
</script>
Jana supports adding custom remark and rehype plugins to extend functionality:
import { defineConfig } from 'vite'
import { jana } from '@khotwa/jana'
import remarkGfm from 'remark-gfm'
import rehypeShiki from 'rehype-shiki'
export default defineConfig({
plugins: [
jana({
plugins: {
remark: [remarkGfm],
rehype: [[rehypeShiki, { theme: 'github-dark' }]]
}
})
]
})
Plugin format:
[remarkGfm][[rehypeSlug, { prefix: "heading-" }]]jana({
// Custom prose directory (default: 'src/lib/components/prose')
prose: 'src/lib/components/prose',
// Explicit component mappings (override auto-scanned ones)
components: {
pre: '$lib/components/CodeBlock.svelte'
},
// Custom unified plugins
plugins: {
remark: [remarkGfm],
rehype: [rehypeSlug]
}
})
Jana uses the unified ecosystem to process Markdown:
remark-parse<p> wrappers (remark treats them as inline)remark-rehype{, }) in code blocksThe plugin automatically processes any file ending with .md during Vite's build process.
MIT