Skip to content

Commit 3b931b0

Browse files
authored
Merge pull request #24 from acmucsd/markdown-parser
feat: back to jsx markdown parser we go
2 parents 6bf7170 + a7cfa4e commit 3b931b0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+895
-173
lines changed

website/package.json

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,16 @@
99
"lint": "next lint"
1010
},
1111
"dependencies": {
12+
"@mdx-js/mdx": "^2.1.1",
1213
"clsx": "^1.1.1",
1314
"copy-text-to-clipboard": "^3.0.1",
1415
"esbuild": "^0.14.36",
16+
"mdx-bundler": "^9.0.1",
1517
"next": "12.1.5",
1618
"prism-react-renderer": "^1.3.1",
1719
"react": "17.0.2",
1820
"react-dom": "17.0.2",
19-
"rehype-katex": "^6.0.2",
20-
"rehype-raw": "^6.1.1",
21-
"rehype-react": "^7.1.1",
22-
"remark-gfm": "^3.0.1",
23-
"remark-math": "^5.1.1",
24-
"remark-parse": "^10.0.1",
25-
"remark-rehype": "^10.1.0",
26-
"sass": "^1.50.1",
27-
"unified": "^10.1.2"
21+
"sass": "^1.50.1"
2822
},
2923
"devDependencies": {
3024
"@babel/parser": "^7.17.9",
@@ -36,10 +30,12 @@
3630
"@types/glob": "^7.1.4",
3731
"@types/react": "17.0.27",
3832
"@types/unist": "^2.0.6",
33+
"acorn": "^8.7.1",
3934
"escape-html": "^1.0.3",
4035
"eslint": "7.32.0",
4136
"eslint-config-next": "11.1.2",
4237
"glob": "^8.0.1",
38+
"html-react-parser": "^1.4.12",
4339
"mdast": "^3.0.0",
4440
"mdast-util-from-markdown": "^1.2.0",
4541
"mdast-util-gfm": "^2.0.1",
@@ -49,10 +45,17 @@
4945
"mdast-util-to-string": "^3.1.0",
5046
"micromark-extension-gfm": "^2.0.1",
5147
"micromark-extension-math": "^2.0.2",
52-
"micromark-extension-mdxjs-esm": "^1.0.2",
48+
"micromark-extension-mdxjs-esm": "^1.0.3",
49+
"rehype-katex": "^6.0.2",
50+
"rehype-react": "^7.1.1",
5351
"rehype-stringify": "^9.0.3",
52+
"remark-gfm": "^3.0.1",
53+
"remark-math": "^5.1.1",
54+
"remark-parse": "^10.0.1",
55+
"remark-rehype": "^10.1.0",
5456
"remark-stringify": "^10.0.2",
5557
"typescript": "^4.6.3",
58+
"unified": "^10.1.2",
5659
"unist-util-visit": "^4.1.0"
5760
}
5861
}

website/src/components/Sidebar/Desktop.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import c from "clsx";
99

1010
import SidebarItems from "./SidebarItems";
1111

12-
import { markdown } from "@/markdown/markdown.module.scss";
12+
import { markdown } from "@/mdx/markdown.module.scss";
1313
import s from "./styles.module.scss";
1414

1515
import type { SidebarProps } from ".";

website/src/components/Sidebar/Mobile.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
import SidebarItems from "./SidebarItems";
1111

12-
import { markdown } from "@/markdown/markdown.module.scss";
12+
import { markdown } from "@/mdx/markdown.module.scss";
1313
import s from "./styles.module.scss";
1414

1515
import type { SidebarProps } from ".";

website/src/components/Toc/Desktop.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import c from "clsx"
99

1010
import Toc from "."
1111

12-
import { markdown } from "@/markdown/markdown.module.scss"
12+
import { markdown } from "@/mdx/markdown.module.scss"
1313
import s from "./styles.module.scss"
1414

1515
import type { TocProps } from "../Toc"
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { createContext, useContext } from "react";
2+
3+
import { useMDX } from "./useMDX";
4+
5+
import type { FC, ReactNode } from "react";
6+
import type { MDXComponentProps } from "./useMDX";
7+
8+
type MDXData = {
9+
MDXComponent: FC<MDXComponentProps>
10+
}
11+
12+
const MDXContext = createContext<MDXData | undefined>(undefined);
13+
14+
export const useMDXContext = () => {
15+
const context = useContext(MDXContext)
16+
if (context === undefined) {
17+
throw new Error('useMDXContext must be used in a MDXProvider')
18+
}
19+
return context
20+
}
21+
22+
interface MDXProviderProps {
23+
source: string
24+
children: ReactNode
25+
}
26+
27+
export default function MDXProvider ({ children, ...props }: MDXProviderProps) {
28+
const { MDXComponent } = useMDX(props)
29+
30+
return (
31+
<MDXContext.Provider value={{ MDXComponent }}>
32+
{children}
33+
</MDXContext.Provider>
34+
)
35+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { useMemo, useCallback } from "react";
2+
import { ComponentMap, getMDXExport } from "mdx-bundler/client";
3+
4+
import defaultComponents from "@/mdx/components";
5+
6+
import type { FC } from "react";
7+
8+
interface UseMDXProps {
9+
source: string
10+
}
11+
12+
export interface MDXComponentProps {
13+
components?: ComponentMap
14+
}
15+
16+
export function useMDX ({ source }: UseMDXProps) {
17+
const { default: BaseComponent } = useMemo(() => getMDXExport(source), [source])
18+
19+
const MDXComponent: FC<MDXComponentProps> = useCallback(({ components, ...props}) => (
20+
<BaseComponent components={{...defaultComponents, ...components}} {...props} />
21+
), [BaseComponent])
22+
23+
return { MDXComponent }
24+
}

website/src/layout/components/Markdown/useMarkdown.ts

Lines changed: 0 additions & 56 deletions
This file was deleted.

website/src/layout/components/MarkdownWrapper/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import c from "clsx";
22

3-
import { markdown, content } from "@/markdown/markdown.module.scss";
3+
import { markdown, content } from "@/mdx/markdown.module.scss";
44

55
import type { ReactNode } from "react";
66

website/src/layout/pages/DocPage/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@ import TocContainer from "@/layout/components/TocContainer";
1111
import BeforeMarkdown from "@/layout/components/BeforeMarkdown";
1212
import OpenInColab from "@/layout/components/OpenInColab";
1313
import MarkdownWrapper from "@/layout/components/MarkdownWrapper";
14-
import { useMarkdown } from "@/layout/components/Markdown/useMarkdown";
1514
import PageProvider from "@/layout/context/Page";
1615

1716
import type { DocPageProps } from "@/layout/pages/types";
17+
import { useMDX } from "@/layout/components/MDX/useMDX";
1818

1919
export default function DocPage ({ source, slug, fsPath, sidebar, toc }: DocPageProps) {
2020
const { asPath } = useRouter();
2121

22-
const { markdownReactElement, MarkdownComponent } = useMarkdown(source)
22+
const { MDXComponent } = useMDX({ source })
2323

2424
return (
2525
<PageProvider sidebar={sidebar} toc={toc}>
@@ -34,7 +34,7 @@ export default function DocPage ({ source, slug, fsPath, sidebar, toc }: DocPage
3434
<OpenInColab fsPath={fsPath} />
3535
</BeforeMarkdown>
3636
<MarkdownWrapper>
37-
<MarkdownComponent fallback={<h1>Loading...</h1>} />
37+
<MDXComponent />
3838
</MarkdownWrapper>
3939
</ContentContainer>
4040
<TocContainer>

website/src/lib/bundle.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import path from "path";
2+
import { bundleMDX } from "mdx-bundler";
3+
4+
import remarkHeadingIds from "@/lib/unified/remark-heading-ids";
5+
import remarkGfm from "remark-gfm";
6+
import remarkMath from "remark-math";
7+
import rehypeKatex from "rehype-katex";
8+
9+
import astDebug from "./unified/ast-debug";
10+
11+
// kinda hacky
12+
import type { BundleMDX } from "mdx-bundler/dist/types";
13+
14+
// https://www.alaycock.co.uk/2021/03/mdx-bundler#esbuild-executable
15+
const fixEsbuildPath = () => {
16+
if (process.platform === 'win32') {
17+
process.env.ESBUILD_BINARY_PATH = path.join(
18+
process.cwd(),
19+
'node_modules',
20+
'esbuild-windows-64',
21+
'esbuild.exe',
22+
)
23+
} else {
24+
process.env.ESBUILD_BINARY_PATH = path.join(
25+
process.cwd(),
26+
'node_modules',
27+
'esbuild',
28+
'bin',
29+
'esbuild',
30+
)
31+
}
32+
}
33+
34+
type Options<Frontmatter> = Required<Pick<BundleMDX<Frontmatter>, 'source' | 'cwd'>> & {
35+
baseUrl: `/${string}`
36+
slug: string[]
37+
}
38+
export const bundle = async <Frontmatter>({ source, cwd, baseUrl, slug }: Options<Frontmatter>) => {
39+
fixEsbuildPath();
40+
const res = await bundleMDX({
41+
source,
42+
cwd,
43+
mdxOptions: (options) => {
44+
options.remarkPlugins = [
45+
...(options.remarkPlugins ?? []),
46+
remarkHeadingIds,
47+
remarkGfm,
48+
remarkMath,
49+
]
50+
options.rehypePlugins = [
51+
...(options.rehypePlugins ?? []),
52+
rehypeKatex,
53+
]
54+
55+
return options
56+
},
57+
esbuildOptions: (options) => {
58+
options.loader = {
59+
...(options.loader ?? {}),
60+
".png": 'file',
61+
".jpg": 'file',
62+
".gif": 'file',
63+
}
64+
// write assets locally to `~/public/static/content/[...slug]`,
65+
// and they will correspondingly be served at /static/content/[...slug]
66+
options.outdir = slug ? path.join(process.cwd(), 'public', 'static', 'content', ...slug) : undefined
67+
options.publicPath = slug ? `/static/content${baseUrl}/${slug.join('/')}` : undefined
68+
options.write = true
69+
70+
return options
71+
},
72+
});
73+
74+
if (res.errors.length > 0) { console.error(res.errors.map(({ detail }) => detail)); }
75+
76+
return res;
77+
}

0 commit comments

Comments
 (0)