From 5646930061841d688ffe925e5ddfc2714b6126ad Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Mon, 13 Feb 2023 10:40:39 -0600 Subject: [PATCH 1/4] Improve frontmatter types, pass generic TFrontmatter type through --- src/rsc.tsx | 7 +++++-- src/serialize.ts | 12 +++++++----- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/rsc.tsx b/src/rsc.tsx index 650ae14..31db575 100644 --- a/src/rsc.tsx +++ b/src/rsc.tsx @@ -27,12 +27,15 @@ export type MDXRemoteProps = Omit< export { MDXRemoteSerializeResult } -export async function compileMDX({ +export async function compileMDX>({ source, options, components = {}, }: MDXRemoteProps) { - const { compiledSource, frontmatter, scope } = await serialize( + const { compiledSource, frontmatter, scope } = await serialize< + Record, + TFrontmatter + >( source, options, // Enable RSC importSource diff --git a/src/serialize.ts b/src/serialize.ts index 882d634..43c7e86 100644 --- a/src/serialize.ts +++ b/src/serialize.ts @@ -38,7 +38,10 @@ function getCompileOptions( /** * Parses and compiles the provided MDX string. Returns a result which can be passed into to be rendered. */ -export async function serialize( +export async function serialize< + TScope = Record, + TFrontmatter = Record +>( source: VFileCompatible, { scope = {}, @@ -46,7 +49,7 @@ export async function serialize( parseFrontmatter = false, }: SerializeOptions = {}, rsc: boolean = false -): Promise { +): Promise> { const vfile = new VFile(source) // makes frontmatter available via vfile.data.matter @@ -66,8 +69,7 @@ export async function serialize( return { compiledSource, - frontmatter: - (vfile.data.matter as Record | undefined) ?? {}, - scope, + frontmatter: (vfile.data.matter ?? {}) as TFrontmatter, + scope: scope as TScope, } } From c0a3f5f11238b20e34fe41457c5732d5742b66a3 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Mon, 27 Feb 2023 17:29:53 -0600 Subject: [PATCH 2/4] add test, update README --- README.md | 13 +++++++------ __tests__/rsc.test.tsx | 18 ++++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 __tests__/rsc.test.tsx diff --git a/README.md b/README.md index eb120c7..691df26 100644 --- a/README.md +++ b/README.md @@ -524,25 +524,26 @@ export default function Home() { ```tsx // app/page.js -import { compileMDX } from "next-mdx-remote/rsc"; +import { compileMDX } from 'next-mdx-remote/rsc' export default async function Home() { - const {content, frontmatter} = compileMDX({ - source: ` + // Optionally provide a type for your frontmatter object + const { content, frontmatter } = compileMDX<{ title: string }>({ + source: ` --- title: RSC Frontmatter Example --- # Hello World This is from Server Components! `, - options: { parseFrontmatter: true } + options: { parseFrontmatter: true }, }) return ( <>

{frontmatter.title}

{content} - - ); + + ) } ``` diff --git a/__tests__/rsc.test.tsx b/__tests__/rsc.test.tsx new file mode 100644 index 0000000..d03ca70 --- /dev/null +++ b/__tests__/rsc.test.tsx @@ -0,0 +1,18 @@ +import { compileMDX } from '../rsc' + +describe('compileMDX', () => { + test('frontmatter types', async () => { + const { frontmatter } = await compileMDX<{ title: string }>({ + source: `--- +title: 'Hello World' +--- + +# Hi`, + }) + + expect(frontmatter?.title).toEqual('Hello World') + + // @ts-expect-error -- blah does not exist on the frontmatter type + expect(frontmatter?.blah).toBeUndefined() + }) +}) From 2a94512d3715fd239ad3c2627a3f4cd27fab0710 Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Mon, 27 Feb 2023 17:41:24 -0600 Subject: [PATCH 3/4] fix test --- __tests__/rsc.test.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/__tests__/rsc.test.tsx b/__tests__/rsc.test.tsx index d03ca70..e1540fc 100644 --- a/__tests__/rsc.test.tsx +++ b/__tests__/rsc.test.tsx @@ -8,6 +8,9 @@ title: 'Hello World' --- # Hi`, + options: { + parseFrontmatter: true, + }, }) expect(frontmatter?.title).toEqual('Hello World') From dcc04fa3faa3b23c992f807cb0ab851c7625b95b Mon Sep 17 00:00:00 2001 From: Bryce Kalow Date: Mon, 27 Feb 2023 17:47:19 -0600 Subject: [PATCH 4/4] fix return type of compileMDX --- __tests__/rsc.test.tsx | 4 ++-- src/rsc.tsx | 12 +++++++----- src/types.ts | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/__tests__/rsc.test.tsx b/__tests__/rsc.test.tsx index e1540fc..d0d885b 100644 --- a/__tests__/rsc.test.tsx +++ b/__tests__/rsc.test.tsx @@ -13,9 +13,9 @@ title: 'Hello World' }, }) - expect(frontmatter?.title).toEqual('Hello World') + expect(frontmatter.title).toEqual('Hello World') // @ts-expect-error -- blah does not exist on the frontmatter type - expect(frontmatter?.blah).toBeUndefined() + expect(frontmatter.blah).toBeUndefined() }) }) diff --git a/src/rsc.tsx b/src/rsc.tsx index 31db575..c14c4cf 100644 --- a/src/rsc.tsx +++ b/src/rsc.tsx @@ -10,10 +10,7 @@ import { VFileCompatible } from 'vfile' import { MDXProvider } from '@mdx-js/react' import { serialize } from './serialize' -export type MDXRemoteProps = Omit< - MDXRemoteSerializeResult, - 'compiledSource' -> & { +export type MDXRemoteProps = { source: VFileCompatible options?: SerializeOptions /** @@ -27,11 +24,16 @@ export type MDXRemoteProps = Omit< export { MDXRemoteSerializeResult } +export type CompileMDXResult> = { + content: React.ReactElement + frontmatter: TFrontmatter +} + export async function compileMDX>({ source, options, components = {}, -}: MDXRemoteProps) { +}: MDXRemoteProps): Promise> { const { compiledSource, frontmatter, scope } = await serialize< Record, TFrontmatter diff --git a/src/types.ts b/src/types.ts index f36c02e..6303a9f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -39,9 +39,9 @@ export type MDXRemoteSerializeResult< * For example, in cases where you want to provide template variables to the MDX, like `my name is {name}`, * you could provide scope as `{ name: "Some name" }`. */ - scope?: TScope + scope: TScope /** * If parseFrontmatter was set to true, contains any parsed frontmatter found in the MDX source. */ - frontmatter?: TFrontmatter + frontmatter: TFrontmatter }