Skip to content

Update deadlinks script to take into account redirects #7882

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

Merged
merged 2 commits into from
Jul 21, 2025
Merged
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
45 changes: 44 additions & 1 deletion scripts/deadLinkChecker.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const PUBLIC_DIR = path.join(__dirname, '../public');
const fileCache = new Map();
const anchorMap = new Map(); // Map<filepath, Set<anchorId>>
const contributorMap = new Map(); // Map<anchorId, URL>
const redirectMap = new Map(); // Map<source, destination>
let errorCodes = new Set();

async function readFileWithCache(filePath) {
Expand Down Expand Up @@ -162,6 +163,22 @@ async function validateLink(link) {
return {valid: true};
}

// Check for redirects
if (redirectMap.has(urlWithoutAnchor)) {
const redirectDestination = redirectMap.get(urlWithoutAnchor);
if (
redirectDestination.startsWith('http://') ||
redirectDestination.startsWith('https://')
) {
return {valid: true};
}
const redirectedLink = {
...link,
url: redirectDestination + (anchorMatch ? anchorMatch[0] : ''),
};
return validateLink(redirectedLink);
}

// Check if it's an error code link
const errorCodeMatch = urlWithoutAnchor.match(/^\/errors\/(\d+)$/);
if (errorCodeMatch) {
Expand Down Expand Up @@ -295,17 +312,42 @@ async function fetchErrorCodes() {
}
const codes = await response.json();
errorCodes = new Set(Object.keys(codes));
console.log(chalk.gray(`Fetched ${errorCodes.size} React error codes\n`));
console.log(chalk.gray(`Fetched ${errorCodes.size} React error codes`));
} catch (error) {
throw new Error(`Failed to fetch error codes: ${error.message}`);
}
}

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) {
redirectMap.set(redirect.source, redirect.destination);
}
console.log(
chalk.gray(`Loaded ${redirectMap.size} redirects from vercel.json`)
);
}
} catch (error) {
console.log(
chalk.yellow(
`Warning: Could not load redirects from vercel.json: ${error.message}\n`
)
);
}
}

async function main() {
const files = getMarkdownFiles();
console.log(chalk.gray(`Checking ${files.length} markdown files...`));

await fetchErrorCodes();
await buildRedirectsMap();
await buildContributorMap();
await buildAnchorMap(files);

Expand All @@ -315,6 +357,7 @@ async function main() {
const totalLinks = results.reduce((sum, r) => sum + r.totalLinks, 0);

if (deadLinks.length > 0) {
console.log('\n');
for (const link of deadLinks) {
console.log(chalk.yellow(`${link.file}:${link.line}:${link.column}`));
console.log(chalk.reset(` Link text: ${link.text}`));
Expand Down
4 changes: 2 additions & 2 deletions src/content/blog/2023/03/16/introducing-react-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ When we released React Hooks in 2018, the Hooks docs assumed the reader is famil
**The new docs teach React with Hooks from the beginning.** The docs are divided in two main sections:

* **[Learn React](/learn)** is a self-paced course that teaches React from scratch.
* **[API Reference](/reference/react)** provides the details and usage examples for every React API.
* **[API Reference](/reference)** provides the details and usage examples for every React API.

Let's have a closer look at what you can find in each section.

Expand Down Expand Up @@ -607,7 +607,7 @@ button { display: block; margin-top: 10px; }

</Recipes>

Some API pages also include [Troubleshooting](/reference/react/useEffect#troubleshooting) (for common problems) and [Alternatives](https://18.react.dev/reference/react-dom/findDOMNode#alternatives) (for deprecated APIs).
Some API pages also include [Troubleshooting](/reference/react/useEffect#troubleshooting) (for common problems) and [Alternatives](/reference/react-dom/findDOMNode#alternatives) (for deprecated APIs).

We hope that this approach will make the API reference useful not only as a way to look up an argument, but as a way to see all the different things you can do with any given API—and how it connects to the other ones.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ The biggest change is that we introduced [`async` / `await`](https://github.com/

Now that we have data fetching pretty well sorted, we're exploring the other direction: sending data from the client to the server, so that you can execute database mutations and implement forms. We're doing this by letting you pass Server Action functions across the server/client boundary, which the client can then call, providing seamless RPC. Server Actions also give you progressively enhanced forms before JavaScript loads.

React Server Components has shipped in [Next.js App Router](/learn/creating-a-react-app#nextjs-app-router). This showcases a deep integration of a router that really buys into RSC as a primitive, but it's not the only way to build a RSC-compatible router and framework. There's a clear separation for features provided by the RSC spec and implementation. React Server Components is meant as a spec for components that work across compatible React frameworks.
React Server Components has shipped in [Next.js App Router](/learn/start-a-new-react-project#nextjs-app-router). This showcases a deep integration of a router that really buys into RSC as a primitive, but it's not the only way to build a RSC-compatible router and framework. There's a clear separation for features provided by the RSC spec and implementation. React Server Components is meant as a spec for components that work across compatible React frameworks.

We generally recommend using an existing framework, but if you need to build your own custom framework, it is possible. Building your own RSC-compatible framework is not as easy as we'd like it to be, mainly due to the deep bundler integration needed. The current generation of bundlers are great for use on the client, but they weren't designed with first-class support for splitting a single module graph between the server and the client. This is why we're now partnering directly with bundler developers to get the primitives for RSC built-in.

Expand Down Expand Up @@ -92,7 +92,7 @@ Since our last update, we've tested an experimental version of prerendering inte

## Transition Tracing {/*transition-tracing*/}

The Transition Tracing API lets you detect when [React Transitions](/reference/react/useTransition) become slower and investigate why they may be slow. Following our last update, we have completed the initial design of the API and published an [RFC](https://github.com/reactjs/rfcs/pull/238). The basic capabilities have also been implemented. The project is currently on hold. We welcome feedback on the RFC and look forward to resuming its development to provide a better performance measurement tool for React. This will be particularly useful with routers built on top of React Transitions, like the [Next.js App Router](/learn/creating-a-react-app#nextjs-app-router).
The Transition Tracing API lets you detect when [React Transitions](/reference/react/useTransition) become slower and investigate why they may be slow. Following our last update, we have completed the initial design of the API and published an [RFC](https://github.com/reactjs/rfcs/pull/238). The basic capabilities have also been implemented. The project is currently on hold. We welcome feedback on the RFC and look forward to resuming its development to provide a better performance measurement tool for React. This will be particularly useful with routers built on top of React Transitions, like the [Next.js App Router](/learn/start-a-new-react-project#nextjs-app-router).

* * *
In addition to this update, our team has made recent guest appearances on community podcasts and livestreams to speak more on our work and answer questions.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Activity is still under research and our remaining work is to finalize the primi

In addition to this update, our team has presented at conferences and made appearances on podcasts to speak more on our work and answer questions.

- [Sathya Gunasekaran](https://github.com/gsathya) spoke about the React Compiler at the [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) conference
- [Sathya Gunasekaran](/community/team#sathya-gunasekaran) spoke about the React Compiler at the [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) conference

- [Dan Abramov](/community/team#dan-abramov) gave a talk at [RemixConf](https://www.youtube.com/watch?v=zMf_xeGPn6s) titled “React from Another Dimension” which explores an alternative history of how React Server Components and Actions could have been created

Expand Down
4 changes: 2 additions & 2 deletions src/content/blog/2024/04/25/react-19-upgrade-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ For a list of all available codemods, see the [`react-codemod` repo](https://git

In previous versions of React, errors thrown during render were caught and rethrown. In DEV, we would also log to `console.error`, resulting in duplicate error logs.

In React 19, we've [improved how errors are handled](/blog/2024/12/05/react-19#error-handling) to reduce duplication by not re-throwing:
In React 19, we've [improved how errors are handled](/blog/2024/04/25/react-19#error-handling) to reduce duplication by not re-throwing:

- **Uncaught Errors**: Errors that are not caught by an Error Boundary are reported to `window.reportError`.
- **Caught Errors**: Errors that are caught by an Error Boundary are reported to `console.error`.
Expand Down Expand Up @@ -499,7 +499,7 @@ function AutoselectingInput() {

### Deprecated: `element.ref` {/*deprecated-element-ref*/}

React 19 supports [`ref` as a prop](/blog/2024/12/05/react-19#ref-as-a-prop), so we're deprecating the `element.ref` in place of `element.props.ref`.
React 19 supports [`ref` as a prop](/blog/2024/04/25/react-19#ref-as-a-prop), so we're deprecating the `element.ref` in place of `element.props.ref`.

Accessing `element.ref` will warn:

Expand Down
4 changes: 2 additions & 2 deletions src/content/blog/2024/12/05/react-19.md
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ For more information, see [React DOM Static APIs](/reference/react-dom/static).

Server Components are a new option that allows rendering components ahead of time, before bundling, in an environment separate from your client application or SSR server. This separate environment is the "server" in React Server Components. Server Components can run once at build time on your CI server, or they can be run for each request using a web server.

React 19 includes all of the React Server Components features included from the Canary channel. This means libraries that ship with Server Components can now target React 19 as a peer dependency with a `react-server` [export condition](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md#react-server-conditional-exports) for use in frameworks that support the [Full-stack React Architecture](/learn/creating-a-react-app#which-features-make-up-the-react-teams-full-stack-architecture-vision).
React 19 includes all of the React Server Components features included from the Canary channel. This means libraries that ship with Server Components can now target React 19 as a peer dependency with a `react-server` [export condition](https://github.com/reactjs/rfcs/blob/main/text/0227-server-module-conventions.md#react-server-conditional-exports) for use in frameworks that support the [Full-stack React Architecture](/learn/start-a-new-react-project#which-features-make-up-the-react-teams-full-stack-architecture-vision).


<Note>
Expand Down Expand Up @@ -389,7 +389,7 @@ For more info, see the docs for [Directives](/reference/rsc/directives).

Server Actions can be created in Server Components and passed as props to Client Components, or they can be imported and used in Client Components.

For more, see the docs for [React Server Actions](/reference/rsc/server-functions).
For more, see the docs for [React Server Actions](/reference/rsc/server-actions).

## Improvements in React 19 {/*improvements-in-react-19*/}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2495,7 +2495,7 @@ For example, we can slow down the `default` cross fade animation:
</ViewTransition>
```

And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-class):
And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-classes):

```css
::view-transition-old(.slow-fade) {
Expand Down
6 changes: 3 additions & 3 deletions src/content/learn/add-react-to-an-existing-project.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ Let's say you have an existing web app at `example.com` built with another serve

Here's how we recommend to set it up:

1. **Build the React part of your app** using one of the [React-based frameworks](/learn/creating-a-react-app).
1. **Build the React part of your app** using one of the [React-based frameworks](/learn/start-a-new-react-project).
2. **Specify `/some-app` as the *base path*** in your framework's configuration (here's how: [Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)).
3. **Configure your server or a proxy** so that all requests under `/some-app/` are handled by your React app.

This ensures the React part of your app can [benefit from the best practices](/learn/creating-a-react-app#full-stack-frameworks) baked into those frameworks.
This ensures the React part of your app can [benefit from the best practices](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) baked into those frameworks.

Many React-based frameworks are full-stack and let your React app take advantage of the server. However, you can use the same approach even if you can't or don't want to run JavaScript on the server. In that case, serve the HTML/CSS/JS export ([`next export` output](https://nextjs.org/docs/advanced-features/static-html-export) for Next.js, default for Gatsby) at `/some-app/` instead.

Expand Down Expand Up @@ -149,7 +149,7 @@ root.render(<NavigationBar />);

Notice how the original HTML content from `index.html` is preserved, but your own `NavigationBar` React component now appears inside the `<nav id="navigation">` from your HTML. Read the [`createRoot` usage documentation](/reference/react-dom/client/createRoot#rendering-a-page-partially-built-with-react) to learn more about rendering React components inside an existing HTML page.

When you adopt React in an existing project, it's common to start with small interactive components (like buttons), and then gradually keep "moving upwards" until eventually your entire page is built with React. If you ever reach that point, we recommend migrating to [a React framework](/learn/creating-a-react-app) right after to get the most out of React.
When you adopt React in an existing project, it's common to start with small interactive components (like buttons), and then gradually keep "moving upwards" until eventually your entire page is built with React. If you ever reach that point, we recommend migrating to [a React framework](/learn/start-a-new-react-project) right after to get the most out of React.

## Using React Native in an existing native mobile app {/*using-react-native-in-an-existing-native-mobile-app*/}

Expand Down
2 changes: 1 addition & 1 deletion src/content/learn/synchronizing-with-effects.md
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ Writing `fetch` calls inside Effects is a [popular way to fetch data](https://ww

This list of downsides is not specific to React. It applies to fetching data on mount with any library. Like with routing, data fetching is not trivial to do well, so we recommend the following approaches:

- **If you use a [framework](/learn/creating-a-react-app#full-stack-frameworks), use its built-in data fetching mechanism.** Modern React frameworks have integrated data fetching mechanisms that are efficient and don't suffer from the above pitfalls.
- **If you use a [framework](/learn/start-a-new-react-project#production-grade-react-frameworks), use its built-in data fetching mechanism.** Modern React frameworks have integrated data fetching mechanisms that are efficient and don't suffer from the above pitfalls.
- **Otherwise, consider using or building a client-side cache.** Popular open source solutions include [React Query](https://tanstack.com/query/latest), [useSWR](https://swr.vercel.app/), and [React Router 6.4+.](https://beta.reactrouter.com/en/main/start/overview) You can build your own solution too, in which case you would use Effects under the hood, but add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes).

You can continue fetching data directly in Effects if neither of these approaches suit you.
Expand Down
6 changes: 3 additions & 3 deletions src/content/learn/typescript.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out

* [TypeScript with React Components](/learn/typescript#typescript-with-react-components)
* [Examples of typing with Hooks](/learn/typescript#example-hooks)
* [Common types from `@types/react`](/learn/typescript#useful-types)
* [Further learning locations](/learn/typescript#further-learning)
* [Common types from `@types/react`](/learn/typescript/#useful-types)
* [Further learning locations](/learn/typescript/#further-learning)

</YouWillLearn>

## Installation {/*installation*/}

All [production-grade React frameworks](/learn/creating-a-react-app#full-stack-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation:
All [production-grade React frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation:

- [Next.js](https://nextjs.org/docs/app/building-your-application/configuring/typescript)
- [Remix](https://remix.run/docs/en/1.19.2/guides/typescript)
Expand Down
Loading
Loading