Skip to content

Commit

Permalink
Add support for React Server Components (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
timneutkens committed Jan 19, 2023
1 parent eace2a3 commit ae6c486
Show file tree
Hide file tree
Showing 15 changed files with 507 additions and 210 deletions.
35 changes: 35 additions & 0 deletions __tests__/fixtures/basic/app/app-dir-mdx/compile-mdx/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import fs from 'fs'
import path from 'path'
import dynamic from 'next/dynamic'
import Test from '../../../components/test'
import { paragraphCustomAlerts } from '@hashicorp/remark-plugins'
import { Provider, Consumer } from '../provider'
import { compileMDX } from 'next-mdx-remote/rsc'

const MDX_COMPONENTS = {
Test,
ContextConsumer: Consumer,
strong: (props) => <strong className="custom-strong" {...props} />,
Dynamic: dynamic(() => import('../../../components/dynamic')),
}

export default async function Page() {
const fixturePath = path.join(process.cwd(), 'mdx/test.mdx')
const source = await fs.promises.readFile(fixturePath, 'utf8')

const { content, frontmatter } = await compileMDX({
source,
components: MDX_COMPONENTS,
options: {
mdxOptions: { remarkPlugins: [paragraphCustomAlerts] },
parseFrontmatter: true,
},
})

return (
<>
<h1>{frontmatter.title}</h1>
<Provider>{content}</Provider>
</>
)
}
33 changes: 33 additions & 0 deletions __tests__/fixtures/basic/app/app-dir-mdx/mdxremote/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import fs from 'fs'
import path from 'path'
import dynamic from 'next/dynamic'
import Test from '../../../components/test'
import { paragraphCustomAlerts } from '@hashicorp/remark-plugins'
import { Provider, Consumer } from '../provider'
import { MDXRemote } from 'next-mdx-remote/rsc'

const MDX_COMPONENTS = {
Test,
ContextConsumer: Consumer,
strong: (props) => <strong className="custom-strong" {...props} />,
Dynamic: dynamic(() => import('../../../components/dynamic')),
}

export default async function Page() {
const fixturePath = path.join(process.cwd(), 'mdx/test.mdx')
const source = await fs.promises.readFile(fixturePath, 'utf8')

return (
<>
<Provider>
<MDXRemote
source={source}
components={MDX_COMPONENTS}
options={{
mdxOptions: { remarkPlugins: [paragraphCustomAlerts] },
}}
/>
</Provider>
</>
)
}
35 changes: 35 additions & 0 deletions __tests__/fixtures/basic/app/app-dir-mdx/provider.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client'
import { createContext, useEffect, useState } from 'react'

const TestContext = createContext('test')
const PROVIDER = {
component: TestContext.Provider,
props: { value: 'foo' },
}

export default function Provider({ children }) {
const [providerOptions, setProviderOptions] = useState(PROVIDER)

useEffect(() => {
setProviderOptions({
...PROVIDER,
props: {
value: 'bar',
},
})
}, [])

return (
<TestContext.Provider {...providerOptions.props}>
{children}
</TestContext.Provider>
)
}

export function Consumer() {
return (
<TestContext.Consumer>
{(value) => <p className="context">Context value: "{value}"</p>}
</TestContext.Consumer>
)
}
9 changes: 9 additions & 0 deletions __tests__/fixtures/basic/app/head.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export default function Head() {
return (
<>
<title></title>
<meta content="width=device-width, initial-scale=1" name="viewport" />
<link rel="icon" href="/favicon.ico" />
</>
)
}
8 changes: 8 additions & 0 deletions __tests__/fixtures/basic/app/layout.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default function RootLayout({ children }) {
return (
<html>
<head />
<body>{children}</body>
</html>
)
}
1 change: 1 addition & 0 deletions __tests__/fixtures/basic/components/test.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client'
import { useState } from 'react'

export default function Test({ name }) {
Expand Down
5 changes: 5 additions & 0 deletions __tests__/fixtures/basic/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
experimental: {
appDir: true,
},
}
7 changes: 0 additions & 7 deletions __tests__/fixtures/basic/pages/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,6 @@ const PROVIDER = {
component: TestContext.Provider,
props: { value: 'foo' },
}
const ContextConsumer = () => {
return (
<TestContext.Consumer>
{(value) => <p className="context">Context value: "{value}"</p>}
</TestContext.Consumer>
)
}

const MDX_COMPONENTS = {
Test,
Expand Down
17 changes: 11 additions & 6 deletions __tests__/integration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,17 @@ describe('hydration - production', () => {
const htmlOutput = $('#__next').html()

// server renders correctly
expect(htmlOutput).toContain(`<h1>foo</h1><h2>Headline</h2>
<!-- --><p>hello <!-- -->jeff<!-- --></p><button>Count: <!-- -->0<!-- --></button>
<!-- --><p class=\"context\">Context value: \"<!-- -->foo<!-- -->\"<!-- --></p>
<!-- --><p>Some <!-- --><strong class=\"custom-strong\">markdown</strong> content<!-- --></p>
<!-- --><div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>
<!-- --><div>I am a dynamic component.</div>`)
expect(htmlOutput).toContain(`<h1>foo</h1>`)
expect(htmlOutput).toContain(`<h2>Headline</h2>`)
expect(htmlOutput).toContain(`<p>hello <!-- -->jeff</p>`)
expect(htmlOutput).toContain(`<button>Count: <!-- -->0</button>`)
expect($('.context').text()).toBe('Context value: "foo"')
expect(htmlOutput).toContain(
`<p>Some <strong class=\"custom-strong\">markdown</strong> content</p>`
)
expect(htmlOutput).toContain(
`<div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>`
)
})

test('rehydrates correctly in browser', async () => {
Expand Down
Loading

0 comments on commit ae6c486

Please sign in to comment.