Construire un blog dans une app existante, c'est rarement la priorité — jusqu'au jour où on en a besoin. Voici comment j'ai branché MDX, Shiki et un système de typographie soigné dans Remix v2 sans renverser l'architecture.
Le pipeline en trois plugins#
Tout part de Vite (vite.config.ts). L'ordre des plugins
compte : MDX avant Remix, sinon Remix ne voit pas les .mdx comme des
routes potentielles.
import mdx from "@mdx-js/rollup"
import remarkFrontmatter from "remark-frontmatter"
import remarkMdxFrontmatter from "remark-mdx-frontmatter"
import rehypePrettyCode from "rehype-pretty-code"
export default defineConfig({
plugins: [
mdx({
remarkPlugins: [
remarkFrontmatter,
[remarkMdxFrontmatter, { name: "frontmatter" }],
],
rehypePlugins: [
[rehypePrettyCode, {
theme: { light: "github-light", dark: "github-dark" },
keepBackground: false,
}],
],
}),
remix({ /* ... */ }),
tsconfigPaths(),
],
})Lister les articles sans loader serveur#
Avec Vite, import.meta.glob permet de charger tous les .mdx d'un coup :
const modules = import.meta.glob<MdxModule>(
"../content/blog/*.mdx",
{ eager: true }
)Chaque module expose default (le composant React) et frontmatter (l'objet
parsé). Pour la liste, on extrait juste le frontmatter. Pour la page article,
on rend le composant.
Le piège du dual theme Shiki#
rehype-pretty-code peut générer un thème
clair et sombre dans le même HTML, en utilisant des CSS variables. Chaque token reçoit --shiki-light et
--shiki-dark. À nous de les piloter en CSS :
.prose code span {
color: var(--shiki-light);
}
html.dark .prose code span {
color: var(--shiki-dark);
}Et la typographie ?#
@tailwindcss/typography
fait le gros du travail avec sa classe prose. Pour override les couleurs sans
toucher au plugin, on définit une variante custom dans
tailwind.config.ts (typography.blog) avec les
bonnes CSS variables (--tw-prose-body, --tw-prose-links, etc).
Résultat : un article qui ressemble à un article, pas à un dashboard.