Skip to content

Commit ae6c486

Browse files
authored
Add support for React Server Components (#331)
1 parent eace2a3 commit ae6c486

File tree

15 files changed

+507
-210
lines changed

15 files changed

+507
-210
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import dynamic from 'next/dynamic'
4+
import Test from '../../../components/test'
5+
import { paragraphCustomAlerts } from '@hashicorp/remark-plugins'
6+
import { Provider, Consumer } from '../provider'
7+
import { compileMDX } from 'next-mdx-remote/rsc'
8+
9+
const MDX_COMPONENTS = {
10+
Test,
11+
ContextConsumer: Consumer,
12+
strong: (props) => <strong className="custom-strong" {...props} />,
13+
Dynamic: dynamic(() => import('../../../components/dynamic')),
14+
}
15+
16+
export default async function Page() {
17+
const fixturePath = path.join(process.cwd(), 'mdx/test.mdx')
18+
const source = await fs.promises.readFile(fixturePath, 'utf8')
19+
20+
const { content, frontmatter } = await compileMDX({
21+
source,
22+
components: MDX_COMPONENTS,
23+
options: {
24+
mdxOptions: { remarkPlugins: [paragraphCustomAlerts] },
25+
parseFrontmatter: true,
26+
},
27+
})
28+
29+
return (
30+
<>
31+
<h1>{frontmatter.title}</h1>
32+
<Provider>{content}</Provider>
33+
</>
34+
)
35+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import fs from 'fs'
2+
import path from 'path'
3+
import dynamic from 'next/dynamic'
4+
import Test from '../../../components/test'
5+
import { paragraphCustomAlerts } from '@hashicorp/remark-plugins'
6+
import { Provider, Consumer } from '../provider'
7+
import { MDXRemote } from 'next-mdx-remote/rsc'
8+
9+
const MDX_COMPONENTS = {
10+
Test,
11+
ContextConsumer: Consumer,
12+
strong: (props) => <strong className="custom-strong" {...props} />,
13+
Dynamic: dynamic(() => import('../../../components/dynamic')),
14+
}
15+
16+
export default async function Page() {
17+
const fixturePath = path.join(process.cwd(), 'mdx/test.mdx')
18+
const source = await fs.promises.readFile(fixturePath, 'utf8')
19+
20+
return (
21+
<>
22+
<Provider>
23+
<MDXRemote
24+
source={source}
25+
components={MDX_COMPONENTS}
26+
options={{
27+
mdxOptions: { remarkPlugins: [paragraphCustomAlerts] },
28+
}}
29+
/>
30+
</Provider>
31+
</>
32+
)
33+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use client'
2+
import { createContext, useEffect, useState } from 'react'
3+
4+
const TestContext = createContext('test')
5+
const PROVIDER = {
6+
component: TestContext.Provider,
7+
props: { value: 'foo' },
8+
}
9+
10+
export default function Provider({ children }) {
11+
const [providerOptions, setProviderOptions] = useState(PROVIDER)
12+
13+
useEffect(() => {
14+
setProviderOptions({
15+
...PROVIDER,
16+
props: {
17+
value: 'bar',
18+
},
19+
})
20+
}, [])
21+
22+
return (
23+
<TestContext.Provider {...providerOptions.props}>
24+
{children}
25+
</TestContext.Provider>
26+
)
27+
}
28+
29+
export function Consumer() {
30+
return (
31+
<TestContext.Consumer>
32+
{(value) => <p className="context">Context value: "{value}"</p>}
33+
</TestContext.Consumer>
34+
)
35+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export default function Head() {
2+
return (
3+
<>
4+
<title></title>
5+
<meta content="width=device-width, initial-scale=1" name="viewport" />
6+
<link rel="icon" href="/favicon.ico" />
7+
</>
8+
)
9+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export default function RootLayout({ children }) {
2+
return (
3+
<html>
4+
<head />
5+
<body>{children}</body>
6+
</html>
7+
)
8+
}

__tests__/fixtures/basic/components/test.jsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
'use client'
12
import { useState } from 'react'
23

34
export default function Test({ name }) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module.exports = {
2+
experimental: {
3+
appDir: true,
4+
},
5+
}

__tests__/fixtures/basic/pages/index.jsx

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,6 @@ const PROVIDER = {
1212
component: TestContext.Provider,
1313
props: { value: 'foo' },
1414
}
15-
const ContextConsumer = () => {
16-
return (
17-
<TestContext.Consumer>
18-
{(value) => <p className="context">Context value: "{value}"</p>}
19-
</TestContext.Consumer>
20-
)
21-
}
2215

2316
const MDX_COMPONENTS = {
2417
Test,

__tests__/integration.test.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,17 @@ describe('hydration - production', () => {
2929
const htmlOutput = $('#__next').html()
3030

3131
// server renders correctly
32-
expect(htmlOutput).toContain(`<h1>foo</h1><h2>Headline</h2>
33-
<!-- --><p>hello <!-- -->jeff<!-- --></p><button>Count: <!-- -->0<!-- --></button>
34-
<!-- --><p class=\"context\">Context value: \"<!-- -->foo<!-- -->\"<!-- --></p>
35-
<!-- --><p>Some <!-- --><strong class=\"custom-strong\">markdown</strong> content<!-- --></p>
36-
<!-- --><div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>
37-
<!-- --><div>I am a dynamic component.</div>`)
32+
expect(htmlOutput).toContain(`<h1>foo</h1>`)
33+
expect(htmlOutput).toContain(`<h2>Headline</h2>`)
34+
expect(htmlOutput).toContain(`<p>hello <!-- -->jeff</p>`)
35+
expect(htmlOutput).toContain(`<button>Count: <!-- -->0</button>`)
36+
expect($('.context').text()).toBe('Context value: "foo"')
37+
expect(htmlOutput).toContain(
38+
`<p>Some <strong class=\"custom-strong\">markdown</strong> content</p>`
39+
)
40+
expect(htmlOutput).toContain(
41+
`<div class=\"alert alert-warning g-type-body\"><p>Alert</p></div>`
42+
)
3843
})
3944

4045
test('rehydrates correctly in browser', async () => {

0 commit comments

Comments
 (0)