Frederic DesgreniersBook RecomendationsNotes

Rendering Markdown files using solid-start and MDX

Sometimes, it's easier to write down content in markdown. However, solid-start doesn't render these by default.

Thankfully, using vite and the mdx project, it's pretty easy to get everything set up.



Dependencies

In an existing solid start project (if you don't have one created already, refer to the getting started docs), install @vinxi/plugin-mdx

Terminal window
pnpm i @vinxi/plugin-mdx

vite.config.js

Add the plugin to your vite.config.js file

vite.config.js
import { defineConfig } from "@solidjs/start/config";
import pkg from "@vinxi/plugin-mdx";
const { default: mdx } = pkg;
export default defineConfig({
start: {
// Register the extensions with solid-start
extensions: ["mdx", "md"],
},
plugins: [
// Add and configure the `@vinxi/plugin-mdx` plugin in order to properly handle markdown files
mdx.withImports({})({
jsx: true,
jsxImportSource: "solid-js",
providerImportSource: "solid-mdx",
}),
],
});

Usage

Simple markdown component

From a jsx or tsx file, the markdown file can then be imported and used directly as a component

test.md
# This is a markdown file
...
some-page.tsx
"use server";
import Test from "./test.md";
export default function () {
return <Test />;
}

MDX

Render JSX inside the component

A .md will be limited to expressing plain markdown. It might instead be useful to render more complex pages by importing and rendering components from within the markdown file.

.mdx files allow you to render jsx from within a markdown file. For example, if an mdx file contains the following:

test.mdx
import Counter from "~/components/Counter";
# This is a counter:
<Counter />

It will render the Counter component from the ./components/Counter inline in the markdown file. Like so:

Frontmatter

From a .mdx file, you can expose properties that can then be read where the file is embedded.

test.mdx
export const title = "Test Page";
...
some-page.tsx
import * as MarkdownFile from "./test.mdx";
export default function() {
return <h1>{MarkdownFile.title}</h1>;
}

For instance, the root notes page of this site uses a title, url, and date property on each markdown file in order to render the note index.

Page

The markdown file can also be treated as a page. To do this, use the (.mdx)[https://mdxjs.com/] file extension.

./routes/test.mdx
# This is a markdown file
...

Navigating to /test will render the markdown file as a page. (this is how this page is rendered)

Code Syntax Highlighting

Using remark-expressive-code, code blocks can be highlighted.

Install the needed packages:

Terminal window
pnpm i remark-expressive-code rehype-raw @mdx-js/mdx

Feel free to read up on these packages to understand what they offer. But for this use case, the following configuration will show highlighted code.

Add these imports in vite.config.js

vite.config.js
import rehypeRaw from "rehype-raw";
import { nodeTypes } from "@mdx-js/mdx";
import remarkExpressiveCode from "remark-expressive-code";

And then configure the remark and rehype plugins:

vite.config.js
plugins: [
vinxiMdx.withImports({})({
//...
rehypePlugins: [[rehypeRaw, { passThrough: nodeTypes }]],
remarkPlugins: [
[
remarkExpressiveCode,
{ themes: ["min-light", "material-theme-ocean"] },
],
],
}),
],
});