@admirable-oss/mdx-press

Compile .mdx straight to Vue components in Rsbuild, with real dev-server HMR.
171
Install
npm install @admirable-oss/mdx-press
Latest Version:0.0.1
Vue:3
Last Updated:Sep 10, 2026
Links: npm
Maintainer: admirable-oss

admirable.mdx-press

MDXPress

admirable version licence version admirable version

A native Rspack/Rsbuild plugin that compiles .mdx files directly into Vue components, with blazing-fast native performance and built-in dev-server HMR — edit a .mdx file and see your changes update instantly, just like any other component in your project.

Built for and used by admirable-oss/kyc's design-system app (apps/identity), and published as its own package because the problem it solves — content-authored-separately-from-code that still hot-reloads — isn't specific to that app.

Why this exists

The obvious tool for "MDX in a bundler" is unplugin-vue-markdown or @mdx-js/loader. Both were tried here first and didn't work with Rsbuild's Vue toolchain (rspack-vue-loader, a different implementation than webpack's vue-loader) — a separately-registered rspack plugin injecting its own module rule has no ordering guarantee against @rsbuild/plugin-vue's own rule for the same file, so the markdown transform silently never ran.

mdx-press takes a narrower, more direct approach: one loader, chained into the same module rule as rspack-vue-loader, with a documented, deterministic execution order. No unplugin abstraction layer, no separate plugin registration to race against.

What you get

  • .mdx files compile to real Vue components — no v-html, no runtime markdown parsing in the browser.
  • Each compiled component has two static named exports: headings (an { id, level, text }[] outline of its h2/h3s) and frontmatter (its --- YAML block, flat string fields only).
  • Real HMR, inherited from rspack-vue-loader itself — not a custom dev-server hack.
  • One runtime dependency tree: markdown-it + markdown-it-anchor. No MDX/JSX compiler, no Babel.

Install

pnpm add @admirable-oss/mdx-press

Requires @rsbuild/plugin-vue to already be configured in your project — mdx-press relies on the VueLoaderPlugin it registers and doesn't register a second one.

Setup

// rsbuild.config.ts
import { pluginMdxPress } from "@admirable-oss/mdx-press";
import { defineConfig } from "@rsbuild/core";
import { pluginVue } from "@rsbuild/plugin-vue";

export default defineConfig({
  plugins: [
    pluginVue(),
    pluginMdxPress({
      // Optional: Tailwind (or any) utility classes injected onto generated
      // tags — there's no Vue template to put class= on markdown-generated
      // HTML, so this is how you theme it.
      classes: {
        h2: "text-2xl font-bold",
        h3: "text-lg font-semibold",
        paragraph: "leading-relaxed",
        list: "list-disc pl-5",
        inlineCode: "rounded bg-gray-100 px-1.5 py-0.5 font-mono",
      },
    }),
  ],
});

Add the ambient module declaration so TypeScript knows what importing a .mdx file gives you:

// tsconfig.json
{
  "compilerOptions": {
    "types": ["@admirable-oss/mdx-press/client"]
  }
}

Usage

Write content in .mdx — plain markdown, plus raw HTML for anything that needs a visual treatment markdown can't express (styled with the same utility classes as the rest of your app, since it's just HTML):

---
title: Colors
---

## Foundation

### Colors

<div class="grid grid-cols-3 gap-2">
<div class="rounded border p-2"><span class="block h-8 bg-black"></span>Ink</div>
</div>

Import it like any component — headings/frontmatter come along as named exports:

<script setup lang="ts">
import Content, { headings, frontmatter } from "./colors.mdx";
</script>

<template>
  <h1>{{ frontmatter.title }}</h1>
  <nav>
    <a v-for="h in headings" :key="h.id" :href="https://github.com/admirable-oss/kyc/blob/HEAD/`#${h.id}`">{{ h.text }}</a>
  </nav>
  <Content />
</template>

What this is not

There's no live-Vue-component-embedding inside the markdown itself (the actual "MDX" part of MDX — <MyComponent /> written directly in the .md prose). That's what broke with unplugin-vue-markdown + rspack-vue-loader. If you need a real component inside a content page today, render it in the Vue file that imports the .mdx content, alongside <Content /> — not inside the markdown source.

html: true is on by default in the underlying markdown-it instance — mdx-press assumes first-party-authored content (docs, design-system pages you write yourself), not untrusted/user-submitted markdown. Don't point it at user input.

API

  • pluginMdxPress(options?) — the Rsbuild plugin. options.test (default /\.mdx$/), options.classes, options.wrapperClass (default "mdx-press", the class on the element wrapping rendered content), options.vueLoaderOptions (forwarded to rspack-vue-loader).
  • createMdxParser(classes?) — the underlying markdown-it wrapper, if you want to parse markdown yourself outside the loader (e.g. in a script, in tests).

License

MIT

Related Packages

rsbuild-plugin-svg

Rsbuild plugin to load SVG files as Vue components

7,833 4
@vue-devtools-rstack/rsbuild

An Rsbuild plugin for Vue DevTools - feature parity with vite-plugin-vue-devtool...

414 15
babel-plugin-vue-jsx-hmr

babel plugin for vue3 jsx HMR

267,483 5
xdm

an MDX compiler

2,024,925 596
storybook-vue3-rsbuild

Storybook for Vue3 and Rsbuild: Develop React Component in isolation with Hot Re...

158,562 157

Version History

Version Released Vue License
0.0.1 ^3.2.0