Create content driven sites using mdx (markdown + react) with added support typescript based autocompletion for the pages.
JASSM is a simple abstraction layer over mdx-js and its vite plugin for creating a route/file aware loader for mdx file.
Each page is configured at a single source of truth (registry) and thereby provides typesafe access throughout.
(ps the DX is similar to that of TanstackRouter or Elysia)
-
Initialize a react app using vite
-
Install jassm
npm install @d1vij/jassm
# OR
pnpm add @d1vij/jassm
# OR
bun add @d1vij/jassm- Setup vite plugin in vite config
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import jassm from "@d1vij/jassm/plugin";
export default defineConfig({
plugins: [
jassm(), // Put jassm plugin before react's plugin
react(),
],
});- Create a folder with
.mdxassets
mkdir assets/mdx
cd assets/mdx
echo "# This is a Heading" > sample.mdx- Setup a mdx registry
// src/Registry.tsx
import { Registry } from "@d1vij/jassm";
export const registry = new Registry({
modules: import.meta.glob("/src/assets/mdx/**/*.mdx"),
source: "/src/assets/mdx",
mountOn: "/root",
records: {
"/sample": "/example.mdx",
},
});- Setup style classes
// src/stylesmap.ts
import type { StyleClassesMap } from "jassm";
// import stylesheet
import "myStyles.css";
export const stylesmap: StyleClassesMap = {
header: "myHeader",
paragraph: "pee",
};Or using css modules
import styles from "myStyles.module.css";
import type { StyleClassesMap } from "jassm";
export const stylesmap: StyleClassesMap = {
header: styles.myHeader,
paragraph: styles.pee,
};- Using the registry in any other component
// importing defined registry
import { registry } from "./Registry";
// importing styles map
import {stylesmap} from "./stylesmap";
import {MDXFromComponent} from "jassm";
import {use} from "react";
type ExportType = {
meta: {
title: string
}
};
export default function Content() {
const Component = registry.getComponent("/root/sample");
const exports = use(registry.getExport<ExportType>("/root/sample")) // consuming the 'import' promise using use
return (
<div>
{exports.meta.title}
<MDXFromComponent
SourceComponent={Component}
styles={stylesmap}
{/* Optional fallback component for suspense*/}
fallback={<div>Loading</div>}
/>
<div/>
)
}Using MDXSourceComponent automatically sets up the required enclosing StyleContext and Suspense component.
The setup can also be done manually as follows
import { StyleContext, Elements } from "@d1vij/jassm";
import { registry } from "./Registry";
import { stylesmap } from "./stylesmap";
import { Suspense } from "react";
export default function MyLoader() {
const Component = registry["/root/sample"];
return (
<div>
<StyleContext styles={stylesmap}>
<Suspense>
<Component components={Elements} />
</Suspense>
</StyleContext>
</div>
);
}