diff --git a/nest.json b/nest.json new file mode 100644 index 00000000000..49a106d4067 --- /dev/null +++ b/nest.json @@ -0,0 +1,5 @@ +{ + "name": "react_docs", + "framework": "nextjs", + "oncall": "react_core" +} diff --git a/next.config.js b/next.config.js index f8ec196e131..1f30e7734bf 100644 --- a/next.config.js +++ b/next.config.js @@ -43,6 +43,303 @@ const nextConfig = { ], }; }, + async redirects() { + return [ + { + source: '/reference', + destination: '/reference/react', + permanent: true, + }, + { + source: '/reference/react-dom/hooks/useFormState', + destination: '/reference/react/useActionState', + permanent: true, + }, + { + source: '/learn/meet-the-team', + destination: '/community/team', + permanent: true, + }, + { + source: '/link/warning-keys', + destination: + '/learn/rendering-lists#keeping-list-items-in-order-with-key', + permanent: false, + }, + { + source: '/docs/lists-and-keys', + destination: + '/learn/rendering-lists#keeping-list-items-in-order-with-key', + permanent: false, + }, + { + source: '/link/invalid-hook-call', + destination: '/warnings/invalid-hook-call-warning', + permanent: false, + }, + { + source: '/link/hooks-data-fetching', + destination: '/reference/react/useEffect#fetching-data-with-effects', + permanent: false, + }, + { + source: '/link/special-props', + destination: '/warnings/special-props', + permanent: false, + }, + { + source: '/link/dangerously-set-inner-html', + destination: + '/reference/react-dom/components/common#dangerously-setting-the-inner-html', + permanent: false, + }, + { + source: '/link/controlled-components', + destination: + '/reference/react-dom/components/input#controlling-an-input-with-a-state-variable', + permanent: false, + }, + { + source: '/link/react-devtools', + destination: '/learn/react-developer-tools', + permanent: false, + }, + { + source: '/link/invalid-aria-props', + destination: '/warnings/invalid-aria-prop', + permanent: false, + }, + { + source: '/link/hydration-mismatch', + destination: + '/reference/react-dom/client/hydrateRoot#hydrating-server-rendered-html', + permanent: false, + }, + { + source: '/link/switch-to-createroot', + destination: + '/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis', + permanent: false, + }, + { + source: '/link/error-boundaries', + destination: + '/reference/react/Component#catching-rendering-errors-with-an-error-boundary', + permanent: false, + }, + { + source: '/link/strict-mode-find-node', + destination: + 'https://18.react.dev/reference/react-dom/findDOMNode#alternatives', + permanent: false, + }, + { + source: '/link/rules-of-hooks', + destination: '/warnings/invalid-hook-call-warning', + permanent: false, + }, + { + source: '/link/event-pooling', + destination: + 'https://legacy.reactjs.org/docs/legacy-event-pooling.html', + permanent: false, + }, + { + source: '/link/legacy-context', + destination: + 'https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-removing-legacy-context', + permanent: false, + }, + { + source: '/link/crossorigin-error', + destination: 'https://legacy.reactjs.org/docs/cross-origin-errors.html', + permanent: false, + }, + { + source: '/link/react-polyfills', + destination: + 'https://legacy.reactjs.org/docs/javascript-environment-requirements.html', + permanent: false, + }, + { + source: '/link/wrap-tests-with-act', + destination: 'https://legacy.reactjs.org/docs/test-utils.html#act', + permanent: false, + }, + { + source: '/link/refs-must-have-owner', + destination: + 'https://legacy.reactjs.org/warnings/refs-must-have-owner.html', + permanent: false, + }, + { + source: '/link/derived-state', + destination: + 'https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html', + permanent: false, + }, + { + source: '/link/strict-mode-string-ref', + destination: + 'https://legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs', + permanent: false, + }, + { + source: '/link/perf-use-production-build', + destination: + 'https://legacy.reactjs.org/docs/optimizing-performance.html#use-the-production-build', + permanent: false, + }, + { + source: '/link/unsafe-component-lifecycles', + destination: + 'https://legacy.reactjs.org/blog/2018/03/27/update-on-async-rendering.html', + permanent: false, + }, + { + source: '/link/test-utils-mock-component', + destination: + 'https://gist.github.com/bvaughn/fbf41b3f895bf2d297935faa5525eee9', + permanent: false, + }, + { + source: '/link/attribute-behavior', + destination: + 'https://legacy.reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail', + permanent: false, + }, + { + source: '/link/react-devtools-faq', + destination: + 'https://github.com/facebook/react/tree/main/packages/react-devtools#faq', + permanent: false, + }, + { + source: '/link/setstate-in-render', + destination: + 'https://github.com/facebook/react/issues/18178#issuecomment-595846312', + permanent: false, + }, + { + source: '/link/new-jsx-transform', + destination: + 'https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html', + permanent: false, + }, + { + source: '/link/cra', + destination: '/blog/2025/02/14/sunsetting-create-react-app', + permanent: false, + }, + { + source: '/warnings/version-mismatch', + destination: + '/warnings/invalid-hook-call-warning#mismatching-versions-of-react-and-react-dom', + permanent: false, + }, + { + source: '/reference/react/directives', + destination: '/reference/rsc/directives', + permanent: true, + }, + { + source: '/reference/react/use-client', + destination: '/reference/rsc/use-client', + permanent: true, + }, + { + source: '/reference/react/use-server', + destination: '/reference/rsc/use-server', + permanent: true, + }, + { + source: '/reference/rsc/server-actions', + destination: '/reference/rsc/server-functions', + permanent: true, + }, + { + source: '/reference/react-dom/findDOMNode', + destination: 'https://18.react.dev/reference/react-dom/findDOMNode', + permanent: true, + }, + { + source: '/reference/react/createFactory', + destination: 'https://18.react.dev/reference/react/createFactory', + permanent: true, + }, + { + source: '/reference/react-dom/render', + destination: 'https://18.react.dev/reference/react-dom/render', + permanent: true, + }, + { + source: '/reference/react-dom/hydrate', + destination: 'https://18.react.dev/reference/react-dom/hydrate', + permanent: true, + }, + { + source: '/reference/react-dom/unmountComponentAtNode', + destination: + 'https://18.react.dev/reference/react-dom/unmountComponentAtNode', + permanent: true, + }, + { + source: '/reference/react-dom/server/renderToStaticNodeStream', + destination: + 'https://18.react.dev/reference/react-dom/server/renderToStaticNodeStream', + permanent: true, + }, + { + source: '/reference/react-dom/server/renderToNodeStream', + destination: + 'https://18.react.dev/reference/react-dom/server/renderToNodeStream', + permanent: true, + }, + { + source: '/learn/start-a-new-react-project', + destination: '/learn/creating-a-react-app', + permanent: true, + }, + { + source: '/learn/building-a-react-framework', + destination: '/learn/build-a-react-app-from-scratch', + permanent: true, + }, + { + source: '/blog/2024/04/25/react-19', + destination: '/blog/2024/12/05/react-19', + permanent: true, + }, + { + source: '/feed.xml', + destination: '/rss.xml', + permanent: true, + }, + { + source: '/reference/react/experimental_useEffectEvent', + destination: '/reference/react/useEffectEvent', + permanent: true, + }, + { + source: '/blog/2025/04/21/react-compiler-rc', + destination: '/blog/2025/10/07/react-compiler-1', + permanent: true, + }, + ]; + }, + async headers() { + return [ + { + source: '/fonts/(.*).woff2', + headers: [ + { + key: 'Cache-Control', + value: 'public, max-age=31536000, immutable', + }, + ], + }, + ]; + }, env: {}, webpack: (config, {dev, isServer, ...options}) => { if (process.env.ANALYZE) { diff --git a/scripts/deadLinkChecker.js b/scripts/deadLinkChecker.js index 46a21cdc9ec..883956f41fd 100644 --- a/scripts/deadLinkChecker.js +++ b/scripts/deadLinkChecker.js @@ -326,23 +326,20 @@ async function fetchErrorCodes() { async function buildRedirectsMap() { try { - const vercelConfigPath = path.join(__dirname, '../vercel.json'); - const vercelConfig = JSON.parse( - await fs.promises.readFile(vercelConfigPath, 'utf8') - ); - - if (vercelConfig.redirects) { - for (const redirect of vercelConfig.redirects) { + const nextConfig = require('../next.config.js'); + if (typeof nextConfig.redirects === 'function') { + const redirects = await nextConfig.redirects(); + for (const redirect of redirects) { redirectMap.set(redirect.source, redirect.destination); } - console.log( - chalk.gray(`Loaded ${redirectMap.size} redirects from vercel.json`) - ); } + console.log( + chalk.gray(`Loaded ${redirectMap.size} redirects from next.config.js`) + ); } catch (error) { console.log( chalk.yellow( - `Warning: Could not load redirects from vercel.json: ${error.message}\n` + `Warning: Could not load redirects from next.config.js: ${error.message}\n` ) ); } diff --git a/src/pages/api/health.ts b/src/pages/api/health.ts new file mode 100644 index 00000000000..0a3cd9dae17 --- /dev/null +++ b/src/pages/api/health.ts @@ -0,0 +1,9 @@ +import type {NextApiRequest, NextApiResponse} from 'next'; + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + if (req.method !== 'GET') { + res.setHeader('Allow', 'GET'); + return res.status(405).send('Method not allowed'); + } + res.status(200).json({status: 'healthy'}); +} diff --git a/vercel.json b/vercel.json index e467632b030..03d263efb50 100644 --- a/vercel.json +++ b/vercel.json @@ -2,273 +2,5 @@ "github": { "silent": true }, - "trailingSlash": false, - "redirects": [ - { - "source": "/reference", - "destination": "/reference/react", - "permanent": true - }, - { - "source": "/reference/react-dom/hooks/useFormState", - "destination": "/reference/react/useActionState", - "permanent": true - }, - { - "source": "/learn/meet-the-team", - "destination": "/community/team", - "permanent": true - }, - { - "source": "/link/warning-keys", - "destination": "/learn/rendering-lists#keeping-list-items-in-order-with-key", - "permanent": false - }, - { - "source": "/docs/lists-and-keys", - "destination": "/learn/rendering-lists#keeping-list-items-in-order-with-key", - "permanent": false - }, - { - "source": "/link/invalid-hook-call", - "destination": "/warnings/invalid-hook-call-warning", - "permanent": false - }, - { - "source": "/link/hooks-data-fetching", - "destination": "/reference/react/useEffect#fetching-data-with-effects", - "permanent": false - }, - { - "source": "/link/special-props", - "destination": "/warnings/special-props", - "permanent": false - }, - { - "source": "/link/dangerously-set-inner-html", - "destination": "/reference/react-dom/components/common#dangerously-setting-the-inner-html", - "permanent": false - }, - { - "source": "/link/controlled-components", - "destination": "/reference/react-dom/components/input#controlling-an-input-with-a-state-variable", - "permanent": false - }, - { - "source": "/link/react-devtools", - "destination": "/learn/react-developer-tools", - "permanent": false - }, - { - "source": "/link/invalid-aria-props", - "destination": "/warnings/invalid-aria-prop", - "permanent": false - }, - { - "source": "/link/hydration-mismatch", - "destination": "/reference/react-dom/client/hydrateRoot#hydrating-server-rendered-html", - "permanent": false - }, - { - "source": "/link/switch-to-createroot", - "destination": "/blog/2022/03/08/react-18-upgrade-guide#updates-to-client-rendering-apis", - "permanent": false - }, - { - "source": "/link/error-boundaries", - "destination": "/reference/react/Component#catching-rendering-errors-with-an-error-boundary", - "permanent": false - }, - { - "source": "/link/strict-mode-find-node", - "destination": "https://18.react.dev/reference/react-dom/findDOMNode#alternatives", - "permanent": false - }, - { - "source": "/link/rules-of-hooks", - "destination": "/warnings/invalid-hook-call-warning", - "permanent": false - }, - { - "source": "/link/event-pooling", - "destination": "https://legacy.reactjs.org/docs/legacy-event-pooling.html", - "permanent": false - }, - { - "source": "/link/legacy-context", - "destination": "https://react.dev/blog/2024/04/25/react-19-upgrade-guide#removed-removing-legacy-context", - "permanent": false - }, - { - "source": "/link/crossorigin-error", - "destination": "https://legacy.reactjs.org/docs/cross-origin-errors.html", - "permanent": false - }, - { - "source": "/link/react-polyfills", - "destination": "https://legacy.reactjs.org/docs/javascript-environment-requirements.html", - "permanent": false - }, - { - "source": "/link/wrap-tests-with-act", - "destination": "https://legacy.reactjs.org/docs/test-utils.html#act", - "permanent": false - }, - { - "source": "/link/refs-must-have-owner", - "destination": "https://legacy.reactjs.org/warnings/refs-must-have-owner.html", - "permanent": false - }, - { - "source": "/link/derived-state", - "destination": "https://legacy.reactjs.org/blog/2018/06/07/you-probably-dont-need-derived-state.html", - "permanent": false - }, - { - "source": "/link/strict-mode-string-ref", - "destination": "https://legacy.reactjs.org/docs/refs-and-the-dom.html#legacy-api-string-refs", - "permanent": false - }, - { - "source": "/link/perf-use-production-build", - "destination": "https://legacy.reactjs.org/docs/optimizing-performance.html#use-the-production-build", - "permanent": false - }, - { - "source": "/link/unsafe-component-lifecycles", - "destination": "https://legacy.reactjs.org/blog/2018/03/27/update-on-async-rendering.html", - "permanent": false - }, - { - "source": "/link/test-utils-mock-component", - "destination": "https://gist.github.com/bvaughn/fbf41b3f895bf2d297935faa5525eee9", - "permanent": false - }, - { - "source": "/link/attribute-behavior", - "destination": "https://legacy.reactjs.org/blog/2017/09/08/dom-attributes-in-react-16.html#changes-in-detail", - "permanent": false - }, - { - "source": "/link/react-devtools-faq", - "destination": "https://github.com/facebook/react/tree/main/packages/react-devtools#faq", - "permanent": false - }, - { - "source": "/link/setstate-in-render", - "destination": "https://github.com/facebook/react/issues/18178#issuecomment-595846312", - "permanent": false - }, - { - "source": "/link/new-jsx-transform", - "destination": "https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html", - "permanent": false - }, - { - "source": "/link/cra", - "destination": "/blog/2025/02/14/sunsetting-create-react-app", - "permanent": false - }, - { - "source": "/warnings/version-mismatch", - "destination": "/warnings/invalid-hook-call-warning#mismatching-versions-of-react-and-react-dom", - "permanent": false - }, - { - "source": "/reference/react/directives", - "destination": "/reference/rsc/directives", - "permanent": true - }, - { - "source": "/reference/react/use-client", - "destination": "/reference/rsc/use-client", - "permanent": true - }, - { - "source": "/reference/react/use-server", - "destination": "/reference/rsc/use-server", - "permanent": true - }, - { - "source": "/reference/rsc/server-actions", - "destination": "/reference/rsc/server-functions", - "permanent": true - }, - { - "source": "/reference/react-dom/findDOMNode", - "destination": "https://18.react.dev/reference/react-dom/findDOMNode", - "permanent": true - }, - { - "source": "/reference/react/createFactory", - "destination": "https://18.react.dev/reference/react/createFactory", - "permanent": true - }, - { - "source": "/reference/react-dom/render", - "destination": "https://18.react.dev/reference/react-dom/render", - "permanent": true - }, - { - "source": "/reference/react-dom/hydrate", - "destination": "https://18.react.dev/reference/react-dom/hydrate", - "permanent": true - }, - { - "source": "/reference/react-dom/unmountComponentAtNode", - "destination": "https://18.react.dev/reference/react-dom/unmountComponentAtNode", - "permanent": true - }, - { - "source": "/reference/react-dom/server/renderToStaticNodeStream", - "destination": "https://18.react.dev/reference/react-dom/server/renderToStaticNodeStream", - "permanent": true - }, - { - "source": "/reference/react-dom/server/renderToNodeStream", - "destination": "https://18.react.dev/reference/react-dom/server/renderToNodeStream", - "permanent": true - }, - { - "source": "/learn/start-a-new-react-project", - "destination": "/learn/creating-a-react-app", - "permanent": true - }, - { - "source": "/learn/building-a-react-framework", - "destination": "/learn/build-a-react-app-from-scratch", - "permanent": true - }, - { - "source": "/blog/2024/04/25/react-19", - "destination": "/blog/2024/12/05/react-19", - "permanent": true - }, - { - "source": "/feed.xml", - "destination": "/rss.xml", - "permanent": true - }, - { - "source": "/reference/react/experimental_useEffectEvent", - "destination": "/reference/react/useEffectEvent", - "permanent": true - }, - { - "source": "/blog/2025/04/21/react-compiler-rc", - "destination": "/blog/2025/10/07/react-compiler-1", - "permanent": true - } - ], - "headers": [ - { - "source": "/fonts/(.*).woff2", - "headers": [ - { - "key": "Cache-Control", - "value": "public, max-age=31536000, immutable" - } - ] - } - ] + "trailingSlash": false }