Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] migrate to app router #7091

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
3 changes: 0 additions & 3 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ const nextConfig = {
pageExtensions: ['jsx', 'js', 'ts', 'tsx', 'mdx', 'md'],
reactStrictMode: true,
experimental: {
// TODO: Remove after https://github.com/vercel/next.js/issues/49355 is fixed
appDir: false,
scrollRestoration: true,
legacyBrowsers: false,
},
env: {},
webpack: (config, {dev, isServer, ...options}) => {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
"date-fns": "^2.16.1",
"debounce": "^1.2.1",
"github-slugger": "^1.3.0",
"next": "^13.4.1",
"next": "^14.2.5",
"next-remote-watch": "^1.0.0",
"parse-numeric-range": "^1.2.0",
"react": "^0.0.0-experimental-16d053d59-20230506",
Expand Down
6 changes: 3 additions & 3 deletions patches/next+13.4.1.patch → patches/next+14.2.5.patch
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
diff --git a/node_modules/next/dist/server/render.js b/node_modules/next/dist/server/render.js
index a1f8648..1b3d608 100644
index b808abf..94ee987 100644
--- a/node_modules/next/dist/server/render.js
+++ b/node_modules/next/dist/server/render.js
@@ -758,9 +758,14 @@ async function renderToHTML(req, res, pathname, query, renderOpts) {
@@ -831,9 +831,14 @@ async function renderToHTMLImpl(req, res, pathname, query, renderOpts, extra) {
// Always using react concurrent rendering mode with required react version 18.x
const renderShell = async (EnhancedApp, EnhancedComponent)=>{
const content = renderContent(EnhancedApp, EnhancedComponent);
- return await (0, _nodewebstreamshelper.renderToInitialStream)({
- return await (0, _nodewebstreamshelper.renderToInitialFizzStream)({
- ReactDOMServer: _serverbrowser.default,
- element: content
+ return new Promise((resolve, reject) => {
Expand Down
97 changes: 97 additions & 0 deletions src/app/[[...markdownPath]]/client.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
'use client';

import {Fragment, useMemo} from 'react';
import {usePathname} from 'next/navigation';
import {Page} from 'components/Layout/Page';
import {MDXComponents} from 'components/MDX/MDXComponents';
import sidebarHome from '../../sidebarHome.json';
import sidebarLearn from '../../sidebarLearn.json';
import sidebarReference from '../../sidebarReference.json';
import sidebarCommunity from '../../sidebarCommunity.json';
import sidebarBlog from '../../sidebarBlog.json';

function useActiveSection() {
const pathname = usePathname() ?? '/';
if (pathname === '/') {
return 'home';
} else if (pathname.startsWith('/reference')) {
return 'reference';
} else if (pathname.startsWith('/learn')) {
return 'learn';
} else if (pathname.startsWith('/community')) {
return 'community';
} else if (pathname.startsWith('/blog')) {
return 'blog';
} else {
return 'unknown';
}
}

// Deserialize a client React tree from JSON.
function reviveNodeOnClient(key: any, val: any) {
if (Array.isArray(val) && val[0] == '$r') {
// Assume it's a React element.
let type = val[1];
let key = val[2];
let props = val[3];
if (type === 'wrapper') {
type = Fragment;
props = {children: props.children};
}
if (MDXComponents[type as keyof typeof MDXComponents]) {
type = MDXComponents[type as keyof typeof MDXComponents];
}
if (!type) {
console.error('Unknown type: ' + type);
type = Fragment;
}
return {
$$typeof: Symbol.for('react.element'),
type: type,
key: key,
ref: null,
props: props,
_owner: null,
};
} else {
return val;
}
}

export function Client({content, toc, meta, languages}: any) {
const parsedContent = useMemo(
() => JSON.parse(content, reviveNodeOnClient),
[content]
);
const parsedToc = useMemo(() => JSON.parse(toc, reviveNodeOnClient), [toc]);
const section = useActiveSection();
let routeTree: any;
switch (section) {
case 'home':
case 'unknown':
routeTree = sidebarHome;
break;
case 'learn':
routeTree = sidebarLearn;
break;
case 'reference':
routeTree = sidebarReference;
break;
case 'community':
routeTree = sidebarCommunity;
break;
case 'blog':
routeTree = sidebarBlog;
break;
}
return (
<Page
toc={parsedToc}
routeTree={routeTree}
meta={meta}
section={section}
languages={languages}>
{parsedContent}
</Page>
);
}
97 changes: 97 additions & 0 deletions src/app/[[...markdownPath]]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/

import compileMDX from 'utils/compileMDX';
import {generateRssFeed} from '../../utils/rss';
import {Client} from './client';

export default async function Layout({
params: {markdownPath},
}: {
params: {markdownPath: string[]};
}) {
const {toc, content, meta, languages} = await getData({markdownPath});
return (
<Client toc={toc} content={content} meta={meta} languages={languages} />
);
}

// Put MDX output into JSON for client.
export async function getData({markdownPath}: {markdownPath: string[]}) {
generateRssFeed();
const fs = require('fs');
const rootDir = process.cwd() + '/src/content/';

// Read MDX from the file.
let path = (markdownPath || []).join('/') || 'index';
let mdx;
try {
mdx = fs.readFileSync(rootDir + path + '.md', 'utf8');
} catch {
mdx = fs.readFileSync(rootDir + path + '/index.md', 'utf8');
}

const {toc, content, meta, languages} = await compileMDX(mdx, path, {});
return {
toc,
content,
meta,
languages,
};
}

// Collect all MDX files for static generation.
export async function getStaticPaths() {
const {promisify} = require('util');
const {resolve} = require('path');
const fs = require('fs');
const readdir = promisify(fs.readdir);
const stat = promisify(fs.stat);
const rootDir = process.cwd() + '/src/content';

// Find all MD files recursively.
async function getFiles(dir: string) {
const subdirs = await readdir(dir);
const files = await Promise.all(
subdirs.map(async (subdir: string) => {
const res = resolve(dir, subdir);
return (await stat(res)).isDirectory()
? getFiles(res)
: res.slice(rootDir.length + 1);
})
);
return (
files
.flat()
// ignores `errors/*.md`, they will be handled by `pages/errors/[errorCode].tsx`
.filter((file) => file.endsWith('.md') && !file.startsWith('errors/'))
);
}

// 'foo/bar/baz.md' -> ['foo', 'bar', 'baz']
// 'foo/bar/qux/index.md' -> ['foo', 'bar', 'qux']
function getSegments(file: string) {
let segments = file.slice(0, -3).replace(/\\/g, '/').split('/');
if (segments[segments.length - 1] === 'index') {
segments.pop();
}
return segments;
}

const files = await getFiles(rootDir);

const paths = files.map((file) => ({
params: {
markdownPath: getSegments(file),
// ^^^ CAREFUL HERE.
// If you rename markdownPath, update patches/next-remote-watch.patch too.
// Otherwise you'll break Fast Refresh for all MD files.
},
}));

return {
paths: paths,
fallback: false,
};
}
7 changes: 7 additions & 0 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function RootLayout({children}: {children: React.ReactNode}) {
return (
<html lang="en">
<body>{children}</body>
</html>
);
}
7 changes: 3 additions & 4 deletions src/components/Layout/Feedback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@
*/

import {useState} from 'react';
import {useRouter} from 'next/router';
import {usePathname} from 'next/navigation';
import cn from 'classnames';

export function Feedback({onSubmit = () => {}}: {onSubmit?: () => void}) {
const {asPath} = useRouter();
const cleanedPath = asPath.split(/[\?\#]/)[0];
const pathname = usePathname() ?? '/';
// Reset on route changes.
return <SendFeedback key={cleanedPath} onSubmit={onSubmit} />;
return <SendFeedback key={pathname} onSubmit={onSubmit} />;
}

const thumbsUpIcon = (
Expand Down
6 changes: 3 additions & 3 deletions src/components/Layout/Sidebar/SidebarRouteTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import {useRef, useLayoutEffect, Fragment} from 'react';

import cn from 'classnames';
import {useRouter} from 'next/router';
import {usePathname} from 'next/navigation';
import {SidebarLink} from './SidebarLink';
import {useCollapse} from 'react-collapsed';
import usePendingRoute from 'hooks/usePendingRoute';
Expand Down Expand Up @@ -76,7 +76,7 @@ export function SidebarRouteTree({
routeTree,
level = 0,
}: SidebarRouteTreeProps) {
const slug = useRouter().asPath.split(/[\?\#]/)[0];
const pathname = usePathname() ?? '/';
const pendingRoute = usePendingRoute();
const currentRoutes = routeTree.routes as RouteItem[];
return (
Expand All @@ -94,7 +94,7 @@ export function SidebarRouteTree({
},
index
) => {
const selected = slug === path;
const selected = pathname === path;
let listItem = null;
if (!path || heading) {
// if current route item has no path and children treat it as an API sidebar heading
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/Challenges/Challenges.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/ErrorDecoder.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
import {useEffect, useState} from 'react';
import {useErrorDecoderParams} from '../ErrorDecoderContext';
import cn from 'classnames';
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/ExpandableExample.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/LanguagesContext.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/MDXComponents.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/Sandpack/CustomPreset.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/TerminalBlock.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
1 change: 1 addition & 0 deletions src/components/MDX/TocContext.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
'use client';
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*/
Expand Down
Loading
Loading