From 52e9ae6ea97460eb64dc93bc6ccc1eaa3ef6a50f Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 28 Feb 2025 11:19:35 -0500 Subject: [PATCH 001/129] [ci] Run notify workflow on open or ready for review Ports over the fix in the facebook/react repo for this workflow. We don't have to wait for it to be labeled first, now that we have the reusable maintainer check. --- .github/workflows/discord_notify.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml index 9d83081cc..a4b8c9137 100644 --- a/.github/workflows/discord_notify.yml +++ b/.github/workflows/discord_notify.yml @@ -2,7 +2,7 @@ name: Discord Notify on: pull_request_target: - types: [labeled] + types: [opened, ready_for_review] jobs: check_maintainer: From 90cc2437c15fd582bbcbc1513cb170157d8c01e3 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 21 Mar 2025 16:23:54 -0400 Subject: [PATCH 002/129] [ci] Fix permissions and don't use pull_request_target Defaults permissions to none for all workflows, and only request extra permissions when needed. Similar to https://github.com/facebook/react/pull/32708, prefer the less permissive `pull_request` trigger instead. --- .github/workflows/analyze.yml | 4 +++- .github/workflows/analyze_comment.yml | 4 +++- .github/workflows/discord_notify.yml | 7 ++++++- .github/workflows/label_core_team_prs.yml | 12 +++++++++++- .github/workflows/site_lint.yml | 4 +++- 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index b1ef428d0..13c9c844a 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -7,6 +7,8 @@ on: - main # change this if your default branch is named differently workflow_dispatch: +permissions: {} + jobs: analyze: runs-on: ubuntu-latest @@ -23,7 +25,7 @@ jobs: - name: Restore cached node_modules uses: actions/cache@v4 with: - path: "**/node_modules" + path: '**/node_modules' key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - name: Install deps diff --git a/.github/workflows/analyze_comment.yml b/.github/workflows/analyze_comment.yml index 5a3047cfc..7e5a24d04 100644 --- a/.github/workflows/analyze_comment.yml +++ b/.github/workflows/analyze_comment.yml @@ -2,10 +2,12 @@ name: Analyze Bundle (Comment) on: workflow_run: - workflows: ["Analyze Bundle"] + workflows: ['Analyze Bundle'] types: - completed +permissions: {} + jobs: comment: runs-on: ubuntu-latest diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml index a4b8c9137..a553b23a0 100644 --- a/.github/workflows/discord_notify.yml +++ b/.github/workflows/discord_notify.yml @@ -1,12 +1,17 @@ name: Discord Notify on: - pull_request_target: + pull_request: types: [opened, ready_for_review] +permissions: {} + jobs: check_maintainer: uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read with: actor: ${{ github.event.pull_request.user.login }} is_remote: true diff --git a/.github/workflows/label_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml index 3d9fa2be1..6099b8fcb 100644 --- a/.github/workflows/label_core_team_prs.yml +++ b/.github/workflows/label_core_team_prs.yml @@ -1,7 +1,9 @@ name: Label Core Team PRs on: - pull_request_target: + pull_request: + +permissions: {} env: TZ: /usr/share/zoneinfo/America/Los_Angeles @@ -11,6 +13,9 @@ env: jobs: check_maintainer: uses: facebook/react/.github/workflows/shared_check_maintainer.yml@main + permissions: + # Used by check_maintainer + contents: read with: actor: ${{ github.event.pull_request.user.login }} is_remote: true @@ -19,6 +24,11 @@ jobs: if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} runs-on: ubuntu-latest needs: check_maintainer + permissions: + # Used to add labels on issues + issues: write + # Used to add labels on PRs + pull-requests: write steps: - name: Label PR as React Core Team uses: actions/github-script@v7 diff --git a/.github/workflows/site_lint.yml b/.github/workflows/site_lint.yml index 36f7642c9..81a04601c 100644 --- a/.github/workflows/site_lint.yml +++ b/.github/workflows/site_lint.yml @@ -7,6 +7,8 @@ on: pull_request: types: [opened, synchronize, reopened] +permissions: {} + jobs: lint: runs-on: ubuntu-latest @@ -25,7 +27,7 @@ jobs: - name: Restore cached node_modules uses: actions/cache@v4 with: - path: "**/node_modules" + path: '**/node_modules' key: node_modules-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - name: Install deps From a6615dba7cf859faae0c94e01a9b0ad9c8628d38 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 21 Mar 2025 16:27:40 -0400 Subject: [PATCH 003/129] [ci] Pin 3rd party actions to specific hash --- .github/workflows/analyze.yml | 2 +- .github/workflows/analyze_comment.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index 13c9c844a..83e7f2e8a 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -57,7 +57,7 @@ jobs: name: bundle_analysis.json - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e if: success() && github.event.number with: workflow: analyze.yml diff --git a/.github/workflows/analyze_comment.yml b/.github/workflows/analyze_comment.yml index 7e5a24d04..1e086b9b7 100644 --- a/.github/workflows/analyze_comment.yml +++ b/.github/workflows/analyze_comment.yml @@ -16,7 +16,7 @@ jobs: github.event.workflow_run.conclusion == 'success' }} steps: - name: Download base branch bundle stats - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e with: workflow: analyze.yml run_id: ${{ github.event.workflow_run.id }} @@ -24,7 +24,7 @@ jobs: path: analysis_comment.txt - name: Download PR number - uses: dawidd6/action-download-artifact@v2 + uses: dawidd6/action-download-artifact@268677152d06ba59fcec7a7f0b5d961b6ccd7e1e with: workflow: analyze.yml run_id: ${{ github.event.workflow_run.id }} @@ -50,7 +50,7 @@ jobs: echo "pr-number=$pr_number" >> $GITHUB_OUTPUT - name: Comment - uses: marocchino/sticky-pull-request-comment@v2 + uses: marocchino/sticky-pull-request-comment@52423e01640425a022ef5fd42c6fb5f633a02728 with: header: next-bundle-analysis number: ${{ steps.get-comment-body.outputs.pr-number }} From 8c00811edf2e97daa5515d733c1a03bf3ecc3cd9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 24 Mar 2025 16:06:46 -0400 Subject: [PATCH 004/129] [ci] Remove unused param https://github.com/facebook/react/pull/32727 removes the `is_remote` param. --- .github/workflows/discord_notify.yml | 1 - .github/workflows/label_core_team_prs.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/discord_notify.yml b/.github/workflows/discord_notify.yml index 8314deb3a..2f5b2a497 100644 --- a/.github/workflows/discord_notify.yml +++ b/.github/workflows/discord_notify.yml @@ -14,7 +14,6 @@ jobs: contents: read with: actor: ${{ github.event.pull_request.user.login }} - is_remote: true notify: if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} diff --git a/.github/workflows/label_core_team_prs.yml b/.github/workflows/label_core_team_prs.yml index 529d7cc48..f9b3328ee 100644 --- a/.github/workflows/label_core_team_prs.yml +++ b/.github/workflows/label_core_team_prs.yml @@ -18,7 +18,6 @@ jobs: contents: read with: actor: ${{ github.event.pull_request.user.login }} - is_remote: true label: if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} From 566e977fb670fa633b7ff14eba1bb3f8e0dc859c Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:23:24 -0400 Subject: [PATCH 005/129] Fix missing Sunsetting CRA entry in sidebar This was missed in the last blog post. Also fixed the incorrect date. --- src/content/blog/index.md | 4 ++-- src/sidebarBlog.json | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f7bbe76f3..f74a57ba6 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -4,7 +4,7 @@ title: React Blog -This blog is the official source for the updates from the React team. Anything important, including release notes or deprecation notices, will be posted here first. +This blog is the official source for the updates from the React team. Anything important, including release notes or deprecation notices, will be posted here first. You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account on Bluesky, or [@reactjs](https://twitter.com/reactjs) account on Twitter, but you won’t miss anything essential if you only read this blog. @@ -12,7 +12,7 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
- + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 5562a5a6c..567988023 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "Sunsetting Create React App", + "titleForHomepage": "Sunsetting Create React App", + "icon": "blog", + "date": "February 14, 2025", + "path": "/blog/2025/02/14/sunsetting-create-react-app" + }, { "title": "React 19", "titleForHomepage": "React 19", From d3aead6a25be239c863e5607d59a2b38629730b9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:25:47 -0400 Subject: [PATCH 006/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 81 +++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..7dfd9fbb4 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,81 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes), [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production. + +## Use React Compiler RC today +To install the RC: + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks +To install eslint-plugin-react-hooks: + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From 183b9d2e4eeee75779dc800648cff965d4018353 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:36:15 -0400 Subject: [PATCH 007/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 81 +++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..7dfd9fbb4 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,81 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes), [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production. + +## Use React Compiler RC today +To install the RC: + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks +To install eslint-plugin-react-hooks: + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From b3dd75ea6a1f975e1c803936946c54dc101b9314 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:36:15 -0400 Subject: [PATCH 008/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 81 +++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..5e4fb318b --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,81 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes), [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From 9e45b84584e5a445c30128ba65d6ca8eca4f7787 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:36:15 -0400 Subject: [PATCH 009/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 116 ++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..00161cf83 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,116 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes) and [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + + +# npm +npm install --save-dev --save-exact babel-plugin-react-compiler@rc + +# pnpm +pnpm add --save-dev --save-exact babel-plugin-react-compiler@rc + +# yarn +yarn add --dev --exact babel-plugin-react-compiler@rc + + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + + +# npm +npm install --save-dev eslint-plugin-react-hooks@^6.0.0 + +# pnpm +pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0 + +# yarn +yarn add --dev eslint-plugin-react-hooks@^6.0.0 + + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +```js +// eslint.config.js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // Flat Config (eslint 9+) + reactHooks.configs.recommended, + + // Legacy Config + reactHooks.configs['recommended-latest'] +]; +``` + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From 672e08a7fd278ba4048376cd6be77b089da34477 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:42:20 -0400 Subject: [PATCH 010/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 116 ++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..62ae370b4 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,116 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes) and [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + + +# npm {/*npm*/} +npm install --save-dev --save-exact babel-plugin-react-compiler@rc + +# pnpm {/*pnpm*/} +pnpm add --save-dev --save-exact babel-plugin-react-compiler@rc + +# yarn {/*yarn*/} +yarn add --dev --exact babel-plugin-react-compiler@rc + + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + + +# npm {/*npm*/} +npm install --save-dev eslint-plugin-react-hooks@^6.0.0 + +# pnpm {/*pnpm*/} +pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0 + +# yarn {/*yarn*/} +yarn add --dev eslint-plugin-react-hooks@^6.0.0 + + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +```js +// eslint.config.js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // Flat Config (eslint 9+) + reactHooks.configs.recommended, + + // Legacy Config + reactHooks.configs['recommended-latest'] +]; +``` + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From 72e42b8ab1cf7b4f1fddb12ed79b75774affb8d9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:44:04 -0400 Subject: [PATCH 011/129] Compiler blog post Blog post for Compiler RC --- .../blog/2025/04/21/react-compiler-rc.md | 110 ++++++++++++++++++ src/content/blog/index.md | 7 ++ src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 ++ 4 files changed, 126 insertions(+), 6 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..2f5fd4cd7 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,110 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes) and [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + + +npm install --save-dev --save-exact babel-plugin-react-compiler@rc + +pnpm add --save-dev --save-exact babel-plugin-react-compiler@rc + +yarn add --dev --exact babel-plugin-react-compiler@rc + + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + + +npm install --save-dev eslint-plugin-react-hooks@^6.0.0 + +pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0 + +yarn add --dev eslint-plugin-react-hooks@^6.0.0 + + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +```js +// eslint.config.js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // Flat Config (eslint 9+) + reactHooks.configs.recommended, + + // Legacy Config + reactHooks.configs['recommended-latest'] +]; +``` + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From 3ccd884d06860ae789fb59b0255d4ae81cddca78 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:47:13 -0400 Subject: [PATCH 012/129] Compiler blog post Blog post for Compiler RC --- next-env.d.ts | 3 +- .../blog/2025/04/21/react-compiler-rc.md | 124 ++++++++++++++++++ src/content/blog/index.md | 7 + src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 + 5 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/next-env.d.ts b/next-env.d.ts index 3cd7048ed..52e831b43 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..1d053649a --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,124 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes) and [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + +npm + +npm install --save-dev --save-exact babel-plugin-react-compiler@rc + + +pnpm + +pnpm add --save-dev --save-exact babel-plugin-react-compiler@rc + + +yarn + +yarn add --dev --exact babel-plugin-react-compiler@rc + + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + +npm + +npm install --save-dev eslint-plugin-react-hooks@^6.0.0 + + +pnpm + +pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0 + + +yarn + +yarn add --dev eslint-plugin-react-hooks@^6.0.0 + + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +```js +// eslint.config.js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // Flat Config (eslint 9+) + reactHooks.configs.recommended, + + // Legacy Config + reactHooks.configs['recommended-latest'] +]; +``` + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From fbdf12301ad75c1d82ee38a1810c871fe0d3fea8 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 15:57:03 -0400 Subject: [PATCH 013/129] Compiler blog post Blog post for Compiler RC --- next-env.d.ts | 3 +- .../blog/2025/04/21/react-compiler-rc.md | 124 ++++++++++++++++++ src/content/blog/index.md | 7 + src/content/learn/react-compiler.md | 8 +- src/sidebarBlog.json | 7 + 5 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 src/content/blog/2025/04/21/react-compiler-rc.md diff --git a/next-env.d.ts b/next-env.d.ts index 3cd7048ed..52e831b43 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -1,6 +1,5 @@ /// /// -/// // NOTE: This file should not be edited -// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information. diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md new file mode 100644 index 000000000..ab4790129 --- /dev/null +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -0,0 +1,124 @@ +--- +title: "React Compiler RC" +author: Lauren Tan and Mofei Zhang +date: 2025/04/21 +description: We are releasing the compiler's first Release Candidate (RC) today. + +--- + +April 21, 2025 by [Lauren Tan](https://x.com/potetotes) and [Mofei Zhang](https://x.com/zmofei). + +--- + + + +The React team is excited to share new updates: + + + +1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. +2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. + +--- + +[React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. + +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. + +## Use React Compiler RC today {/*use-react-compiler-rc-today*/} +To install the RC: + +npm + +{`npm install --save-dev --save-exact babel-plugin-react-compiler@rc`} + + +pnpm + +{`pnpm add --save-dev --save-exact babel-plugin-react-compiler@rc`} + + +yarn + +{`yarn add --dev --exact babel-plugin-react-compiler@rc`} + + +As part of the RC, we've been making React Compiler easier to add to your projects and added optimizations to how the compiler generates memoization. React Complier now supports optional chains and array indices as dependencies. We're exploring how to infer even more dependencies like equality checks and string interpolation. These improvements ultimately result in fewer re-renders and more responsive UIs. + +We have also heard from the community that the ref-in-render validation sometimes has false positives. Since as a general philosophy we want you to be able to fully trust in the compiler's error messages and hints, we are turning it off by default for now. We will keep working to improve this validation, and we will re-enable it in a follow up release. + +You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). + +### Backwards Compatibility {/*backwards-compatibility*/} +As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). + +## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} +To install eslint-plugin-react-hooks: + +npm + +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} + + +pnpm + +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} + + +yarn + +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} + + +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +```js +// eslint.config.js +import * as reactHooks from 'eslint-plugin-react-hooks'; + +export default [ + // Flat Config (eslint 9+) + reactHooks.configs.recommended, + + // Legacy Config + reactHooks.configs['recommended-latest'] +]; +``` + +The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. + +## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} +We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. + +Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. + +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. + +## Upgrading React Compiler {/*upgrading-react-compiler*/} +React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. + +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). + +In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. + +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. + +## Roadmap to Stable {/*roadmap-to-stable*/} +*This is not a final roadmap, and is subject to change.* + +After a period of final feedback from the community on the RC, we plan on a Stable Release for the compiler. + +* ✅ Experimental: Released at React Conf 2024, primarily for feedback from application developers. +* ✅ Public Beta: Available today, for feedback from library authors. +* ✅ Release Candidate (RC): React Compiler works for the majority of rule-following apps and libraries without issue. +* General Availability: After final feedback period from the community. + +Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. + +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +--- + +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index f74a57ba6..4707e5f48 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -12,6 +12,13 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account
+ + +We are releasing the compiler's first Release Candidate (RC) today. ... + + + + Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 7c46673e7..143c859a1 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -6,10 +6,6 @@ title: React Compiler This page will give you an introduction to React Compiler and how to try it out successfully. - -These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable. - - * Getting started with the compiler @@ -19,9 +15,9 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules). +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. -The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. +The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. diff --git a/src/sidebarBlog.json b/src/sidebarBlog.json index 567988023..33a474766 100644 --- a/src/sidebarBlog.json +++ b/src/sidebarBlog.json @@ -11,6 +11,13 @@ "path": "/blog", "skipBreadcrumb": true, "routes": [ + { + "title": "React Compiler RC", + "titleForHomepage": "React Compiler RC", + "icon": "blog", + "date": "April 21, 2025", + "path": "/blog/2025/04/21/react-compiler-rc" + }, { "title": "Sunsetting Create React App", "titleForHomepage": "Sunsetting Create React App", From f974c788dbbdd8b5429bea7fe30c7520011ba749 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:19:56 -0400 Subject: [PATCH 014/129] Compiler blog post edits Tweaks to the post. --- src/content/blog/2025/04/21/react-compiler-rc.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index ab4790129..8c12921d9 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -17,7 +17,7 @@ The React team is excited to share new updates: 1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. -2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +2. We're merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. 3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. --- @@ -58,20 +58,20 @@ To install eslint-plugin-react-hooks: npm -{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} pnpm -{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} yarn -{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0-rc.1`} -`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! +`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0-rc.1 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! ```js // eslint.config.js From b54bd892ad3ef93530831683b45f8b7fab5f3172 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:41:47 -0400 Subject: [PATCH 015/129] React compiler doc updates --- src/content/learn/react-compiler.md | 54 +++++++---------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..0bc6b18ff 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1` -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +npm install react-compiler-runtime@rc You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +npm install babel-plugin-react-compiler@rc The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. From d9a3f7191b34f793a27c975e6432e10ff99728a9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:48:02 -0400 Subject: [PATCH 016/129] Compiler blog post edits Tweaks to the post. --- .../blog/2025/04/21/react-compiler-rc.md | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index ab4790129..81a0768df 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -17,8 +17,8 @@ The React team is excited to share new updates: 1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. -2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. -3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. +2. We're merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We've added support for swc and are working with oxc to support Babel-free builds. --- @@ -54,25 +54,25 @@ You can find more details on using the Compiler in [our docs](https://react.dev/ As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). ## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} -To install eslint-plugin-react-hooks: +If you have already installed eslint-plugin-react-compiler, you can now remove it and use eslint-plugin-react-hooks@^6.0.0-rc.1. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +To install `eslint-plugin-react-hooks`: npm -{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} pnpm -{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} yarn -{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0-rc.1`} -`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! - ```js // eslint.config.js import * as reactHooks from 'eslint-plugin-react-hooks'; @@ -89,7 +89,11 @@ export default [ The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. ## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} -We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. +React Compiler can be installed across [several build tools](/learn/react-compiler#installation) such as Babel, Vite, and Rsbuild. + +We have been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding additional support for React Compiler as an swc plugin. As part of the RC release, you can now integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of Babel. + +We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. From 2c4ba99378f06b60e5a6dbb0e81cf9111a7bd8f5 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:48:03 -0400 Subject: [PATCH 017/129] React compiler doc updates --- src/content/learn/react-compiler.md | 54 +++++++---------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..0bc6b18ff 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1` -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +npm install react-compiler-runtime@rc You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +npm install babel-plugin-react-compiler@rc The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. From 0285da51d12dbca036085c000ceaf4803e533853 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:48:02 -0400 Subject: [PATCH 018/129] Compiler blog post edits Tweaks to the post. --- .../2024/10/21/react-compiler-beta-release.md | 8 +++++++ .../blog/2025/04/21/react-compiler-rc.md | 22 +++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md index f5a870b22..58e6b24aa 100644 --- a/src/content/blog/2024/10/21/react-compiler-beta-release.md +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -10,6 +10,14 @@ October 21, 2024 by [Lauren Tan](https://twitter.com/potetotes). --- + + +### React Compiler is now in RC! {/*react-compiler-is-now-in-rc*/} + +Please see the [RC blog post](/blog/2025/04/21/react-compiler-rc) for details. + + + The React team is excited to share new updates: diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index ab4790129..81a0768df 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -17,8 +17,8 @@ The React team is excited to share new updates: 1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. -2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. -3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. +2. We're merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We've added support for swc and are working with oxc to support Babel-free builds. --- @@ -54,25 +54,25 @@ You can find more details on using the Compiler in [our docs](https://react.dev/ As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). ## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} -To install eslint-plugin-react-hooks: +If you have already installed eslint-plugin-react-compiler, you can now remove it and use eslint-plugin-react-hooks@^6.0.0-rc.1. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +To install `eslint-plugin-react-hooks`: npm -{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} pnpm -{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} yarn -{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0-rc.1`} -`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! - ```js // eslint.config.js import * as reactHooks from 'eslint-plugin-react-hooks'; @@ -89,7 +89,11 @@ export default [ The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. ## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} -We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. +React Compiler can be installed across [several build tools](/learn/react-compiler#installation) such as Babel, Vite, and Rsbuild. + +We have been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding additional support for React Compiler as an swc plugin. As part of the RC release, you can now integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of Babel. + +We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. From 390418fda7e57458c9eb99f9da8334ada5625808 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:51:00 -0400 Subject: [PATCH 019/129] React compiler doc updates --- src/content/learn/react-compiler.md | 54 +++++++---------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..0bc6b18ff 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1` -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +npm install react-compiler-runtime@rc You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +npm install babel-plugin-react-compiler@rc The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. From 0cf08f2d3a068ec707a7016fcc288f12e2963fb9 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:48:02 -0400 Subject: [PATCH 020/129] Compiler blog post edits Tweaks to the post. --- .../2024/10/21/react-compiler-beta-release.md | 8 +++++++ .../blog/2025/04/21/react-compiler-rc.md | 22 +++++++++++-------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md index f5a870b22..58e6b24aa 100644 --- a/src/content/blog/2024/10/21/react-compiler-beta-release.md +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -10,6 +10,14 @@ October 21, 2024 by [Lauren Tan](https://twitter.com/potetotes). --- + + +### React Compiler is now in RC! {/*react-compiler-is-now-in-rc*/} + +Please see the [RC blog post](/blog/2025/04/21/react-compiler-rc) for details. + + + The React team is excited to share new updates: diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index ab4790129..35f668e77 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -17,8 +17,8 @@ The React team is excited to share new updates: 1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. -2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. -3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. +2. We're merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We've added support for swc and are working with oxc to support Babel-free builds. --- @@ -54,25 +54,25 @@ You can find more details on using the Compiler in [our docs](https://react.dev/ As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). ## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} -To install eslint-plugin-react-hooks: +If you have already installed eslint-plugin-react-compiler, you can now remove it and use `eslint-plugin-react-hooks@^6.0.0-rc.1`. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +To install: npm -{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} pnpm -{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} yarn -{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0-rc.1`} -`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! - ```js // eslint.config.js import * as reactHooks from 'eslint-plugin-react-hooks'; @@ -89,7 +89,11 @@ export default [ The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. ## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} -We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. +React Compiler can be installed across [several build tools](/learn/react-compiler#installation) such as Babel, Vite, and Rsbuild. + +We have been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding additional support for React Compiler as an swc plugin. As part of the RC release, you can now integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of Babel. + +We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. From 6c91a8da0281648c51711741902ae9d93b314b5a Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:52:27 -0400 Subject: [PATCH 021/129] React compiler doc updates --- src/content/learn/react-compiler.md | 54 +++++++---------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..0bc6b18ff 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1` -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +npm install react-compiler-runtime@rc You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +npm install babel-plugin-react-compiler@rc The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. From 6ccb7415efe54509a42d8dfe6208c6e2bfbfed0c Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:48:02 -0400 Subject: [PATCH 022/129] Compiler blog post edits Tweaks to the post. --- .../2024/10/21/react-compiler-beta-release.md | 8 +++++++ .../blog/2025/04/21/react-compiler-rc.md | 24 ++++++++++--------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md index f5a870b22..58e6b24aa 100644 --- a/src/content/blog/2024/10/21/react-compiler-beta-release.md +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -10,6 +10,14 @@ October 21, 2024 by [Lauren Tan](https://twitter.com/potetotes). --- + + +### React Compiler is now in RC! {/*react-compiler-is-now-in-rc*/} + +Please see the [RC blog post](/blog/2025/04/21/react-compiler-rc) for details. + + + The React team is excited to share new updates: diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index ab4790129..fe9e3c6c1 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -17,8 +17,8 @@ The React team is excited to share new updates: 1. We're publishing React Compiler RC today, in preparation of the compiler's stable release. -2. We're simplifying your eslint setup by merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. -3. We're working with the swc and oxc teams to add plugins to allow for Babel-free build pipelines. +2. We're merging `eslint-plugin-react-compiler` into `eslint-plugin-react-hooks`. +3. We've added support for swc and are working with oxc to support Babel-free builds. --- @@ -54,25 +54,25 @@ You can find more details on using the Compiler in [our docs](https://react.dev/ As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). ## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} -To install eslint-plugin-react-hooks: +If you have already installed eslint-plugin-react-compiler, you can now remove it and use `eslint-plugin-react-hooks@^6.0.0-rc.1`. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! + +To install: npm -{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`npm install --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} pnpm -{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0`} +{`pnpm add --save-dev eslint-plugin-react-hooks@^6.0.0-rc.1`} yarn -{`yarn add --dev eslint-plugin-react-hooks@^6.0.0`} +{`yarn add --dev eslint-plugin-react-hooks@^6.0.0-rc.1`} -`eslint-plugin-react-hooks` 5.2.0 has been ported to TypeScript, which allowed us to improve the type-safety of the plugin. In the 6.0.0 release of the ESLint plugin, the compiler lint rule has now been merged in. If you were previously using `eslint-plugin-react-compiler`, this means you can now use a single ESLint plugin in your codebase. Many thanks to [@michaelfaith](https://bsky.app/profile/michael.faith) for contributing to this improvement! - ```js // eslint.config.js import * as reactHooks from 'eslint-plugin-react-hooks'; @@ -88,12 +88,14 @@ export default [ The linter does not require the compiler to be installed, so there's no risk in upgrading eslint-plugin-react-hooks. We recommend everyone upgrade today. -## swc and oxc support (experimental) {/*swc-and-oxc-support-experimental*/} -We have also been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding support for React Compiler as an swc plugin. As part of the RC release, you can integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of babel. We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048), which should allow more people to use the compiler if they have already migrated off of Babel. +## swc support (experimental) {/*swc-support-experimental*/} +React Compiler can be installed across [several build tools](/learn/react-compiler#installation) such as Babel, Vite, and Rsbuild. + +In addition to those tools, we have been collaborating with Kang Dongyoong ([@kdy1dev](https://x.com/kdy1dev)) from the [swc](https://swc.rs/) team on adding additional support for React Compiler as an swc plugin. As part of the RC release, you can now integrate the compiler into your [Next.js app with swc](https://nextjs.org/docs/app/api-reference/config/next-config-js/reactCompiler) instead of Babel. Next.js users can upgrade to [15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) or greater to try this out. If you have already enabled the compiler in your Next.js's config, swc support will be enabled automatically. -Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. +Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vite-plugin-react) to enable the compiler, by adding it as a [Babel plugin](https://react.dev/learn/react-compiler#usage-with-vite). We are also working with the [oxc](https://oxc.rs/) team to [add support for the compiler](https://github.com/oxc-project/oxc/issues/10048). Once [rolldown](https://github.com/rolldown/rolldown) is officially released and supported in Vite and oxc support is added for React Compiler, we'll update the docs with information on how to migrate. ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. From 7d4fa7734e4e3c258bedb126e5e937333058b998 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 16:56:30 -0400 Subject: [PATCH 023/129] React compiler doc updates --- src/content/learn/react-compiler.md | 54 +++++++---------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..0bc6b18ff 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1` -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +npm install react-compiler-runtime@rc You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +npm install babel-plugin-react-compiler@rc The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. From b69b26e46a141a9cfa7dd91e0230bdd084a596b7 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:00:08 -0400 Subject: [PATCH 024/129] React compiler doc updates --- src/content/learn/react-compiler.md | 56 ++++++++--------------------- 1 file changed, 14 insertions(+), 42 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 143c859a1..9d4e19d21 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -15,25 +15,25 @@ This page will give you an introduction to React Compiler and how to try it out -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to use the compiler. +React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. -React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. +React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. -The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. +eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. -The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: +The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: -npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} Or, if you're using Yarn: -yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta +{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. @@ -112,7 +112,7 @@ So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). +The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). **You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. @@ -120,43 +120,15 @@ Please note that the compiler is still in Beta and has many rough edges. While i In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. -### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/} +### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} -React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler. +React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. -npm install -D eslint-plugin-react-compiler@beta +{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} -Then, add it to your ESLint config: - -```js -import reactCompiler from 'eslint-plugin-react-compiler' - -export default [ - { - plugins: { - 'react-compiler': reactCompiler, - }, - rules: { - 'react-compiler/react-compiler': 'error', - }, - }, -] -``` - -Or, in the deprecated eslintrc config format: - -```js -module.exports = { - plugins: [ - 'eslint-plugin-react-compiler', - ], - rules: { - 'react-compiler/react-compiler': 'error', - }, -} -``` +See our [editor setup](/learn/editor-setup#linting) guide for more details. The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. @@ -190,7 +162,7 @@ If you're starting a new project, you can enable the compiler on your entire cod React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. -npm install react-compiler-runtime@beta +{`npm install react-compiler-runtime@rc`} You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -225,7 +197,7 @@ Similarly to apps, it is not necessary to fully compile 100% of your components ### Babel {/*usage-with-babel*/} -npm install babel-plugin-react-compiler@beta +{`npm install babel-plugin-react-compiler@rc`} The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. @@ -280,7 +252,7 @@ Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/nex Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: -npm install vite-plugin-babel +{`npm install vite-plugin-babel`} ```js {2,14} From cf06465019ed9e3967847b3f86ac42cbdedb3235 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:50:41 -0400 Subject: [PATCH 025/129] More compiler blog post tweaks Summary: Test Plan: Reviewers: Subscribers: Tasks: Tags: --- src/content/blog/2025/04/21/react-compiler-rc.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..3c6eedf9a 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -100,11 +100,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that needs to run in response to very specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* From 71780af8c425ae53d7eb5ea349960e62de2fa8e3 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:52:24 -0400 Subject: [PATCH 026/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..14a862f09 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,6 +50,9 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + ### Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that needs to run in response to very specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. From 5115e7eba57d79dd61e20e6e102f4e2a69bd72e6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:53:47 -0400 Subject: [PATCH 027/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..e47b59ce8 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,6 +50,9 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + ### Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example, you may have an effect that needs to only run in response to specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. From 933915a8cbd8d910f3a4baa93e05f4aa5071b1a7 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:53:47 -0400 Subject: [PATCH 028/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..6bee8fcdf 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,6 +50,9 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + ### Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example, you may have an effect that needs to only run in response to specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- -Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://x.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. From 44b85237f477cae0bb65add52da8823875d9be4d Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:56:20 -0400 Subject: [PATCH 029/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..de39fdccc 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,6 +50,9 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + ### Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases such as effects that needs to only run in response to specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- -Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://x.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. From 161246aa43dff6224ecd1b6740f6a428ac7dc791 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:56:20 -0400 Subject: [PATCH 030/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 14 +++++++------- src/content/blog/index.md | 3 +-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..de39fdccc 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,6 +50,9 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + ### Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases such as effects that needs to only run in response to specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- -Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://x.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 4707e5f48..fadb95243 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -14,11 +14,10 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account -We are releasing the compiler's first Release Candidate (RC) today. ... +We are releasing the compiler's first Release Candidate (RC) today. - Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... From c8e35ffecaed13d9355ae3de909792091f5a40b6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 21 Apr 2025 17:56:20 -0400 Subject: [PATCH 031/129] More compiler blog post tweaks More small tweaks. --- src/content/blog/2025/04/21/react-compiler-rc.md | 16 ++++++++-------- src/content/blog/index.md | 3 +-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/content/blog/2025/04/21/react-compiler-rc.md b/src/content/blog/2025/04/21/react-compiler-rc.md index fe9e3c6c1..55c238a93 100644 --- a/src/content/blog/2025/04/21/react-compiler-rc.md +++ b/src/content/blog/2025/04/21/react-compiler-rc.md @@ -24,7 +24,7 @@ The React team is excited to share new updates: [React Compiler](https://react.dev/learn/react-compiler) is a build-time tool that optimizes your React app through automatic memoization. Last year, we published React Compiler’s [first beta](https://react.dev/blog/2024/10/21/react-compiler-beta-release) and received lots of great feedback and contributions. We’re excited about the wins we’ve seen from folks adopting the compiler (see case studies from [Sanity Studio](https://github.com/reactwg/react-compiler/discussions/33) and [Wakelet](https://github.com/reactwg/react-compiler/discussions/52)) and are working towards a stable release. -We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to use in production for all React users. +We are releasing the compiler's first Release Candidate (RC) today. The RC is intended to be a stable and near-final version of the compiler, and safe to try out in production. ## Use React Compiler RC today {/*use-react-compiler-rc-today*/} To install the RC: @@ -50,7 +50,10 @@ We have also heard from the community that the ref-in-render validation sometime You can find more details on using the Compiler in [our docs](https://react.dev/learn/react-compiler). -### Backwards Compatibility {/*backwards-compatibility*/} +## Feedback {/*feedback*/} +During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). + +## Backwards Compatibility {/*backwards-compatibility*/} As noted in the Beta announcement, React Compiler is compatible with React 17 and up. If you are not yet on React 19, you can use React Compiler by specifying a minimum target in your compiler config, and adding `react-compiler-runtime` as a dependency. You can find docs on this [here](https://react.dev/learn/react-compiler#using-react-compiler-with-react-17-or-18). ## Migrating from eslint-plugin-react-compiler to eslint-plugin-react-hooks {/*migrating-from-eslint-plugin-react-compiler-to-eslint-plugin-react-hooks*/} @@ -100,11 +103,11 @@ Vite users can continue to use [vite-plugin-react](https://github.com/vitejs/vit ## Upgrading React Compiler {/*upgrading-react-compiler*/} React Compiler works best when the auto-memoization applied is strictly for performance. Future versions of the compiler may change how memoization is applied, for example it could become more granular and precise. -However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases. For example you may have an effect that runs in response to some value changing (breaks the rules of React). +However, because product code may sometimes break the [rules of React](https://react.dev/reference/rules) in ways that aren't always statically detectable in JavaScript, changing memoization can occasionally have unexpected results. For example, a previously memoized value might be used as a dependency for a useEffect somewhere in the component tree. Changing how or whether this value is memoized can cause over or under-firing of that useEffect. While we encourage [useEffect only for synchronization](https://react.dev/learn/synchronizing-with-effects), your codebase may have useEffects that cover other use-cases such as effects that needs to only run in response to specific values changing. In other words, changing memoization may under rare circumstances cause unexpected behavior. For this reason, we recommend following the Rules of React and employing continuous end-to-end testing of your app so you can upgrade the compiler with confidence and identify any rules of React violations that might cause issues. -If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.0.0`) rather than a SemVer range (eg `^19.0.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. +If you don't have good test coverage, we recommend pinning the compiler to an exact version (eg `19.1.0`) rather than a SemVer range (eg `^19.1.0`). You can do this by passing the `--save-exact` (npm/pnpm) or `--exact` flags (yarn) when upgrading the compiler. You should then do any upgrades of the compiler manually, taking care to check that your app still works as expected. ## Roadmap to Stable {/*roadmap-to-stable*/} *This is not a final roadmap, and is subject to change.* @@ -118,9 +121,6 @@ After a period of final feedback from the community on the RC, we plan on a Stab Post-Stable, we plan to add more compiler optimizations and improvements. This includes both continual improvements to automatic memoization, and new optimizations altogether, with minimal to no change of product code. Each upgrade will continue to improve performance and add better handling of diverse JavaScript and React patterns. -## Feedback {/*feedback*/} -During the RC period, we encourage all React users to try the compiler and provide feedback in the React repo. Please [open an issue](https://github.com/facebook/react/issues) if you encounter any bugs or unexpected behavior. If you have a general question or suggestion, please post them in the [React Compiler Working Group](https://github.com/reactwg/react-compiler/discussions). - --- -Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://twitter.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. +Thanks to [Joe Savona](https://x.com/en_JS), [Jason Bonta](https://x.com/someextent), [Jimmy Lai](https://x.com/feedthejim), and [Kang Dongyoon](https://x.com/kdy1dev) (@kdy1dev) for reviewing and editing this post. diff --git a/src/content/blog/index.md b/src/content/blog/index.md index 4707e5f48..fadb95243 100644 --- a/src/content/blog/index.md +++ b/src/content/blog/index.md @@ -14,11 +14,10 @@ You can also follow the [@react.dev](https://bsky.app/profile/react.dev) account -We are releasing the compiler's first Release Candidate (RC) today. ... +We are releasing the compiler's first Release Candidate (RC) today. - Today, we’re deprecating Create React App for new apps, and encouraging existing apps to migrate to a framework, or to migrate to a build tool like Vite, Parcel, or RSBuild. We’re also providing docs for when a framework isn’t a good fit for your project, you want to build your own framework, or you just want to learn how React works by building a React app from scratch ... From db38a718cb0d3ca8a741db201006b7c8fd59016e Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 11 Jul 2025 12:12:17 -0400 Subject: [PATCH 032/129] Update .gitignore to include claude related artifacts I am trying out Claude for writing docs and to do so effectively it needs to create some markdown files and other local settings. I would like to start filtering out these artifacts in our .gitignore settings as AI usage becomes more commonplace for contributing. Optionally we could also commit the [CLAUDE.md](https://www.anthropic.com/engineering/claude-code-best-practices) file to aid other developers contributing with the assistance of AI to help improve the quality of any PRs. But I'm omitting that for now since I think that may be contentious. --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 7bf71dbc5..bdf6d5031 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ public/fonts/**/Optimistic_*.woff2 # rss public/rss.xml + +# ai +.claude +CLAUDE.md From c1354d0e06cf0d9b4196dffe909d0fa3581e38a8 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 11 Jul 2025 16:19:01 -0400 Subject: [PATCH 033/129] [compiler] Rewrite React Compiler Docs We've received feedback that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. --- .../learn/react-compiler-deep-dive-backup.md | 59 +++ src/content/learn/react-compiler.md | 346 ------------------ .../learn/react-compiler/compatibility.md | 74 ++++ .../learn/react-compiler/configuration.md | 79 ++++ src/content/learn/react-compiler/debugging.md | 93 +++++ .../learn/react-compiler/getting-started.md | 256 +++++++++++++ .../react-compiler/incremental-adoption.md | 211 +++++++++++ src/content/learn/react-compiler/index.md | 98 +++++ .../learn/react-compiler/library-authors.md | 91 +++++ .../learn/you-might-not-need-an-effect.md | 6 + src/content/reference/react/memo.md | 6 + src/content/reference/react/react-compiler.md | 270 ++++++++++++++ src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 32 +- src/sidebarReference.json | 8 + 16 files changed, 1292 insertions(+), 349 deletions(-) create mode 100644 src/content/learn/react-compiler-deep-dive-backup.md delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/compatibility.md create mode 100644 src/content/learn/react-compiler/configuration.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/getting-started.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/library-authors.md create mode 100644 src/content/reference/react/react-compiler.md diff --git a/src/content/learn/react-compiler-deep-dive-backup.md b/src/content/learn/react-compiler-deep-dive-backup.md new file mode 100644 index 000000000..6895789df --- /dev/null +++ b/src/content/learn/react-compiler-deep-dive-backup.md @@ -0,0 +1,59 @@ + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize for expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
\ No newline at end of file diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/compatibility.md b/src/content/learn/react-compiler/compatibility.md new file mode 100644 index 000000000..a576b1115 --- /dev/null +++ b/src/content/learn/react-compiler/compatibility.md @@ -0,0 +1,74 @@ +--- +title: Backwards Compatibility +--- + + +React Compiler works best with React 19, but it also supports React 17 and 18 with additional configuration. + + + + +* How to configure React Compiler for React 17 and 18 + + + +## Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} + +React Compiler works out of the box with React 19. For React 17 or 18, you need two things: + +### 1. Install the runtime package {/*install-runtime-package*/} + + +npm install react-compiler-runtime@rc + + +### 2. Configure the target version {/*configure-target-version*/} + +```js {5} +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // or '17' for React 17 + }], + ], +}; +``` + +Always use the major version number as a string for the `target` option. Use `'17'` not `17` or `'17.0.2'`. + +## Framework-specific configuration {/*framework-specific-configuration*/} + +### Next.js {/*nextjs*/} + +```js {5} +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js {10} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { target: '17' }], + ], + }, + }), + ], +}); +``` + diff --git a/src/content/learn/react-compiler/configuration.md b/src/content/learn/react-compiler/configuration.md new file mode 100644 index 000000000..1c5a54a2e --- /dev/null +++ b/src/content/learn/react-compiler/configuration.md @@ -0,0 +1,79 @@ +--- +title: Configuration +--- + + +React Compiler is designed to work out of the box with no configuration needed. Most users will not need to configure the compiler. However, if you need to customize its behavior, various configuration options are available. + + + + +* Available configuration options +* How to configure the compiler + + + +## Configuration Options Overview {/*configuration-options-overview*/} + +React Compiler accepts several options to customize its behavior. See the [API reference](/reference/react/react-compiler) for detailed documentation of each option. + +- **`compilationMode`** - Controls which functions to compile +- **`target`** - Specifies the React version for compatibility (17, 18, or 19) +- **`sources`** - Limits compilation to specific files or directories +- **`gating`** - Enables runtime feature flags for [incremental adoption](/learn/react-compiler/incremental-adoption) +- **`logger`** - Configures logging output for debugging +- **`panicThreshold`** - Sets when the compiler should halt on errors +- **`noEmit`** - Disables code generation + +## Basic Configuration {/*basic-configuration*/} + +Pass options to the Babel plugin: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // For React 18 compatibility + }], + ], +}; +``` + +## Framework Examples {/*framework-examples*/} + +### Next.js {/*nextjs*/} + +```js +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js +// vite.config.js +export default { + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { /* options */ }], + ], + }, + }), + ], +}; +``` + +## Learn More {/*learn-more*/} + +For detailed documentation of all configuration options, see the [React Compiler API reference](/reference/react/react-compiler). + +For incremental adoption strategies using these options, see the [incremental adoption guide](/learn/react-compiler/incremental-adoption). \ No newline at end of file diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..0dd2016a7 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/getting-started.md b/src/content/learn/react-compiler/getting-started.md new file mode 100644 index 000000000..88482fd1b --- /dev/null +++ b/src/content/learn/react-compiler/getting-started.md @@ -0,0 +1,256 @@ +--- +title: Getting Started with React Compiler +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [backwards compatibility](/learn/react-compiler/compatibility). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work out of the box without configuration. However, if you need to configure it (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react/react-compiler). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@6.0.0-rc.1 + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [Backwards compatibility](/learn/react-compiler/compatibility) for React 17 and 18 +- [Configuration options](/learn/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Library authors guide](/learn/react-compiler/library-authors) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..2135aabed --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,211 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* How to use the `sources` option for gradual rollout +* Using the "use no memo" directive +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Directory-Based Rollout {/*directory-based-rollout*/} + +The `sources` option lets you specify which files the compiler should process. This is the recommended approach for existing applications. + +### Start Small {/*start-small*/} + +Begin with a new feature or a well-tested part of your application: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: ['src/features/new-dashboard/**'], + }], + ], +}; +``` + +### Expand Gradually {/*expand-gradually*/} + +As you verify the compiler works well, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: [ + 'src/features/new-dashboard/**', + 'src/components/common/**', + 'src/hooks/**', + ], + }], + ], +}; +``` + +### Full Adoption {/*full-adoption*/} + +Once you're confident, remove the `sources` option to compile your entire codebase: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // Now compiles everything + ], +}; +``` + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach is more tedious as you need to add the directive to every component and hook you want to compile. It's only recommended when trying the compiler on a very small scale. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +For most projects, the directory-based approach with `sources` is more practical. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +### Example: Percentage-Based Rollout {/*example-percentage-based-rollout*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable for 20% of users + const userId = getUserId(); + return hashUserId(userId) % 100 < 20; +} +``` + +### Example: Environment-Based Gating {/*example-environment-based-gating*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable in staging, disable in production initially + return process.env.REACT_APP_ENV === 'staging'; +} +``` + +### Performance Testing with Gating {/*performance-testing-with-gating*/} + +Gating is particularly useful for measuring performance impact: + +1. Enable the compiler for a subset of users +2. Compare metrics between compiled and non-compiled versions +3. Monitor for any issues or regressions +4. Gradually increase the rollout percentage + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider adopting more gradually with a smaller `sources` pattern + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/learn/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..22776f967 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,98 @@ +--- +title: React Compiler +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in RC. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). + +**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can provide feedback to us to help make the compiler better. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Getting Started](/learn/react-compiler/getting-started)** - Install React Compiler and configure it for your build tools +* **[Backwards Compatibility](/learn/react-compiler/compatibility)** - Support for React 17, 18, and 19 +* **[Configuration](/learn/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Library Authors Guide](/learn/react-compiler/library-authors)** - Best practices for shipping compiled code +* **[API Reference](/reference/react/react-compiler)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/library-authors.md b/src/content/learn/react-compiler/library-authors.md new file mode 100644 index 000000000..1c7090531 --- /dev/null +++ b/src/content/learn/react-compiler/library-authors.md @@ -0,0 +1,91 @@ +--- +title: Library Authors Guide +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +* Why libraries should ship compiled code +* How to set up compilation in your build pipeline +* Testing strategies for compiled libraries +* Publishing and documentation best practices + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code without needing to enable the compiler themselves +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile the library code. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '17', // Minimum React version + }], + ], +}; +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/react-compiler.md b/src/content/reference/react/react-compiler.md new file mode 100644 index 000000000..106499ed3 --- /dev/null +++ b/src/content/reference/react/react-compiler.md @@ -0,0 +1,270 @@ +--- +title: React Compiler Options +--- + + + +React Compiler is a build-time tool that automatically optimizes your React application by adding memoization. + + + +```js +// babel.config.js +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], + ], + }; +}; +``` + + + +--- + +## Reference {/*reference*/} + +### Configuration Options {/*configuration-options*/} + +The React Compiler accepts configuration options to control its behavior. These options are passed to the Babel plugin. + +```js +const ReactCompilerConfig = { + compilationMode: 'infer', + target: '19', + sources: (filename) => { + return filename.indexOf('src/path/to/dir') !== -1; + }, + // Additional options... +}; +``` + +#### `compilationMode` {/*compilationmode*/} + +Controls how the compiler selects functions for compilation. + +- **Type:** `'infer' | 'syntax' | 'annotation' | 'all'` +- **Default:** `'infer'` + +```js +const ReactCompilerConfig = { + compilationMode: 'infer' // Default mode +}; +``` + +**Options:** +- `'infer'` (default): The compiler will compile: + - Functions explicitly annotated with `"use memo"` directive + - Component and hook functions that are named like a component or hook _and_ create JSX and/or call other hooks +- `'syntax'`: Only compile components using [Flow component syntax](https://flow.org/en/docs/react/component-syntax/) and hooks using [Flow hook syntax](https://flow.org/en/docs/react/hook-syntax/) +- `'annotation'`: Only compile functions that are explicitly annotated with `"use memo"` directive. This can be useful if you are incrementally adopting the compiler. +- `'all'`: Compile all top-level functions (not recommended, as it may mistakenly compile non-React functions) + +#### `target` {/*target*/} + +Specifies the React version for compatibility. + +- **Type:** `'17' | '18' | '19'` +- **Default:** `'19'` + +```js +const ReactCompilerConfig = { + target: '18' +}; +``` + +When targeting older React versions, install `react-compiler-runtime`: + + +npm install react-compiler-runtime@rc + + +#### `sources` {/*sources*/} + +Filters which files to compile, enabling incremental adoption. If overriden, you must manually ignore the node_modules directory as it is not recommended to compile transformed JS. + +- **Type:** `string[] | (filename: string) => boolean` +- **Default:** Excludes `node_modules` + +```js +// Compile specific directories +const ReactCompilerConfig = { + sources: (filename) => { + return filename.indexOf('src/components') !== -1; + } +}; + +// Compile specific file patterns +const ReactCompilerConfig = { + sources: ['src/**/*.jsx', 'src/**/*.tsx'] +}; +``` + +Alternatively, use Babel's builtin [`overrides`](https://babeljs.io/docs/options#overrides) option: + +```js + // babel.config.js + module.exports = { + plugins: [ + // Global plugins that run on all files + ], + overrides: [ + { + test: "./src/specific-directory/**/*.{js,jsx,ts,tsx}", + plugins: [ + "babel-plugin-react-compiler" + ] + } + ] + }; +``` + +#### `panicThreshold` {/*panicthreshold*/} + +Controls compiler behavior when encountering errors. + +- **Type:** `'all_errors' | 'critical_errors' | 'none'` +- **Default:** `'none'` + +```js +const ReactCompilerConfig = { + panicThreshold: 'none' // Recommended for production +}; +``` + +**Options:** +- `'none'` (recommended): The compiler automatically skips components and hooks that break the Rules of React, allowing the rest of your code to be optimized +- `'critical_errors'`: Causes build failures when critical errors are found +- `'all_errors'`: Causes build failures when any diagnostic errors are found + + +**Important:** The default value `'none'` is the best choice for most applications. Using `'all_errors'` or `'critical_errors'` will cause build failures and should only be used for debugging during development. Production builds should always use `'none'`. + + +#### `noEmit` {/*noemit*/} + +Runs analysis without generating code. + +- **Type:** `boolean` +- **Default:** `false` + +```js +const ReactCompilerConfig = { + noEmit: true // Analysis only, no code generation +}; +``` + +#### `logger` {/*logger*/} + +Provides custom logging for compiler events. + +- **Type:** `Logger | null` +- **Default:** `null` + +```js +const ReactCompilerConfig = { + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${filename}: ${event.kind}`); + } + } +}; +``` + +#### `gating` {/*gating*/} + +Enables conditional compilation based on an external feature flag. + +- **Type:** `{ source: string, importSpecifierName: string } | null` +- **Default:** `null` + +```js +const ReactCompilerConfig = { + gating: { + source: 'ReactCompilerFeatureFlag', + importSpecifierName: 'isCompilerEnabled' + } +}; +``` + +When configured, the compiler creates two versions of each compiled function: one optimized and one original. The optimized version is conditionally used based on the imported feature flag. + +**Example gating module implementation:** + +```js +// ReactCompilerFeatureFlag.js +export function isCompilerEnabled() { + // Your logic to determine if the compiler should be enabled + return process.env.REACT_COMPILER_ENABLED === 'true' || + Math.random() < 0.5; // A/B testing example +} +``` + +With this configuration, compiled components will conditionally use optimizations: + +```js +// Before compilation +function MyComponent(props) { + return
{props.text}
; +} + +// After compilation (simplified) +import { isCompilerEnabled } from 'ReactCompilerFeatureFlag'; +import { c as _c } from 'react/compiler-runtime'; + +const MyComponent = isCompilerEnabled() + ? function MyComponent(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.text) { + t0 =
{props.text}
; + $[0] = props.text; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; + } + : function MyComponent(props) { + return
{props.text}
; + }; +``` + +### Directives {/*directives*/} + +Directives are special string literals that control compiler behavior for specific functions. + +#### `"use memo"` {/*use-memo*/} + +Opts in a component or hook for compilation. + +```js +function MyComponent() { + "use memo"; + // This component will be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Forces compilation when using `compilationMode: 'annotation'` +- In `compilationMode: 'infer'`, explicitly marks function for optimization + +#### `"use no memo"` {/*use-no-memo*/} + +Opts out a component or hook from compilation. + +```js +function MyComponent() { + "use no memo"; + // This component will not be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Use when debugging compilation issues +- Temporary escape hatch, not meant for permanent use \ No newline at end of file diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..c860dd55f 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,37 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Getting Started", + "path": "/learn/react-compiler/getting-started" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Backwards Compatibility", + "path": "/learn/react-compiler/compatibility" + }, + { + "title": "Configuration", + "path": "/learn/react-compiler/configuration" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" + }, + { + "title": "Library Authors Guide", + "path": "/learn/react-compiler/library-authors" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..cf10194ea 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,14 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "React Compiler Options", + "path": "/reference/react/react-compiler" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From d6af998dd142395d3733df0bc448e1682fdd7ac1 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 14 Jul 2025 11:46:35 -0400 Subject: [PATCH 034/129] [compiler] Rewrite React Compiler Docs We've received feedback that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. --- src/content/learn/react-compiler.md | 346 ------------------ .../learn/react-compiler/compatibility.md | 74 ++++ .../learn/react-compiler/configuration.md | 79 ++++ src/content/learn/react-compiler/debugging.md | 93 +++++ .../learn/react-compiler/getting-started.md | 256 +++++++++++++ .../react-compiler/incremental-adoption.md | 211 +++++++++++ src/content/learn/react-compiler/index.md | 168 +++++++++ .../learn/react-compiler/library-authors.md | 91 +++++ .../learn/you-might-not-need-an-effect.md | 6 + src/content/reference/react/memo.md | 6 + src/content/reference/react/react-compiler.md | 284 ++++++++++++++ src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 32 +- src/sidebarReference.json | 8 + 15 files changed, 1317 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/compatibility.md create mode 100644 src/content/learn/react-compiler/configuration.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/getting-started.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/library-authors.md create mode 100644 src/content/reference/react/react-compiler.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/compatibility.md b/src/content/learn/react-compiler/compatibility.md new file mode 100644 index 000000000..aa509e19b --- /dev/null +++ b/src/content/learn/react-compiler/compatibility.md @@ -0,0 +1,74 @@ +--- +title: Backwards Compatibility +--- + + +React Compiler works best with React 19, but it also supports React 17 and 18 with additional configuration. + + + + +* How to configure React Compiler for React 17 and 18 + + + +## Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} + +React Compiler does not require any special configuration to work with React 19. For React 17 or 18, you need two things: + +### 1. Install the runtime package {/*install-runtime-package*/} + + +npm install react-compiler-runtime@rc + + +### 2. Configure the target version {/*configure-target-version*/} + +```js {5} +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // or '17' for React 17 + }], + ], +}; +``` + +Always use the major version number as a string for the `target` option. Use `'17'` not `17` or `'17.0.2'`. + +## Framework-specific configuration {/*framework-specific-configuration*/} + +### Next.js {/*nextjs*/} + +```js {5} +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js {10} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { target: '17' }], + ], + }, + }), + ], +}); +``` + diff --git a/src/content/learn/react-compiler/configuration.md b/src/content/learn/react-compiler/configuration.md new file mode 100644 index 000000000..1c5a54a2e --- /dev/null +++ b/src/content/learn/react-compiler/configuration.md @@ -0,0 +1,79 @@ +--- +title: Configuration +--- + + +React Compiler is designed to work out of the box with no configuration needed. Most users will not need to configure the compiler. However, if you need to customize its behavior, various configuration options are available. + + + + +* Available configuration options +* How to configure the compiler + + + +## Configuration Options Overview {/*configuration-options-overview*/} + +React Compiler accepts several options to customize its behavior. See the [API reference](/reference/react/react-compiler) for detailed documentation of each option. + +- **`compilationMode`** - Controls which functions to compile +- **`target`** - Specifies the React version for compatibility (17, 18, or 19) +- **`sources`** - Limits compilation to specific files or directories +- **`gating`** - Enables runtime feature flags for [incremental adoption](/learn/react-compiler/incremental-adoption) +- **`logger`** - Configures logging output for debugging +- **`panicThreshold`** - Sets when the compiler should halt on errors +- **`noEmit`** - Disables code generation + +## Basic Configuration {/*basic-configuration*/} + +Pass options to the Babel plugin: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // For React 18 compatibility + }], + ], +}; +``` + +## Framework Examples {/*framework-examples*/} + +### Next.js {/*nextjs*/} + +```js +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js +// vite.config.js +export default { + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { /* options */ }], + ], + }, + }), + ], +}; +``` + +## Learn More {/*learn-more*/} + +For detailed documentation of all configuration options, see the [React Compiler API reference](/reference/react/react-compiler). + +For incremental adoption strategies using these options, see the [incremental adoption guide](/learn/react-compiler/incremental-adoption). \ No newline at end of file diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..0dd2016a7 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/getting-started.md b/src/content/learn/react-compiler/getting-started.md new file mode 100644 index 000000000..9b328515b --- /dev/null +++ b/src/content/learn/react-compiler/getting-started.md @@ -0,0 +1,256 @@ +--- +title: Getting Started with React Compiler +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [backwards compatibility](/learn/react-compiler/compatibility). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react/react-compiler). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@6.0.0-rc.1 + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [Backwards compatibility](/learn/react-compiler/compatibility) for React 17 and 18 +- [Configuration options](/learn/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Library authors guide](/learn/react-compiler/library-authors) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..2135aabed --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,211 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* How to use the `sources` option for gradual rollout +* Using the "use no memo" directive +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Directory-Based Rollout {/*directory-based-rollout*/} + +The `sources` option lets you specify which files the compiler should process. This is the recommended approach for existing applications. + +### Start Small {/*start-small*/} + +Begin with a new feature or a well-tested part of your application: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: ['src/features/new-dashboard/**'], + }], + ], +}; +``` + +### Expand Gradually {/*expand-gradually*/} + +As you verify the compiler works well, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: [ + 'src/features/new-dashboard/**', + 'src/components/common/**', + 'src/hooks/**', + ], + }], + ], +}; +``` + +### Full Adoption {/*full-adoption*/} + +Once you're confident, remove the `sources` option to compile your entire codebase: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // Now compiles everything + ], +}; +``` + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach is more tedious as you need to add the directive to every component and hook you want to compile. It's only recommended when trying the compiler on a very small scale. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +For most projects, the directory-based approach with `sources` is more practical. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +### Example: Percentage-Based Rollout {/*example-percentage-based-rollout*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable for 20% of users + const userId = getUserId(); + return hashUserId(userId) % 100 < 20; +} +``` + +### Example: Environment-Based Gating {/*example-environment-based-gating*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable in staging, disable in production initially + return process.env.REACT_APP_ENV === 'staging'; +} +``` + +### Performance Testing with Gating {/*performance-testing-with-gating*/} + +Gating is particularly useful for measuring performance impact: + +1. Enable the compiler for a subset of users +2. Compare metrics between compiled and non-compiled versions +3. Monitor for any issues or regressions +4. Gradually increase the rollout percentage + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider adopting more gradually with a smaller `sources` pattern + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/learn/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..15e091960 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,168 @@ +--- +title: React Compiler +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in RC. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +## What build tools are supported? + +React Compiler can be installed across [several build tools](/learn/react-compiler/getting-started) such as Babel, Vite, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Getting Started](/learn/react-compiler/getting-started)** - Install React Compiler and configure it for your build tools +* **[Backwards Compatibility](/learn/react-compiler/compatibility)** - Support for React 17, 18, and 19 +* **[Configuration](/learn/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Library Authors Guide](/learn/react-compiler/library-authors)** - Best practices for shipping compiled code +* **[API Reference](/reference/react/react-compiler)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/library-authors.md b/src/content/learn/react-compiler/library-authors.md new file mode 100644 index 000000000..1c7090531 --- /dev/null +++ b/src/content/learn/react-compiler/library-authors.md @@ -0,0 +1,91 @@ +--- +title: Library Authors Guide +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +* Why libraries should ship compiled code +* How to set up compilation in your build pipeline +* Testing strategies for compiled libraries +* Publishing and documentation best practices + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code without needing to enable the compiler themselves +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile the library code. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '17', // Minimum React version + }], + ], +}; +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/react-compiler.md b/src/content/reference/react/react-compiler.md new file mode 100644 index 000000000..ec8e2dc5b --- /dev/null +++ b/src/content/reference/react/react-compiler.md @@ -0,0 +1,284 @@ +--- +title: React Compiler Options +--- + + + +React Compiler is a build-time tool that automatically optimizes your React application by adding memoization. + + + +```js +// babel.config.js +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], + ], + }; +}; +``` + + + +--- + +## Reference {/*reference*/} + +### Configuration Options {/*configuration-options*/} + +The React Compiler accepts configuration options to control its behavior. These options are passed to the Babel plugin. + +```js +const ReactCompilerConfig = { + compilationMode: 'infer', + target: '19', + sources: (filename) => { + return filename.indexOf('src/path/to/dir') !== -1; + }, + // Additional options... +}; +``` + +#### `compilationMode` {/*compilationmode*/} + +Controls how the compiler selects functions for compilation. + +- **Type:** `'infer' | 'syntax' | 'annotation' | 'all'` +- **Default:** `'infer'` + +```js +const ReactCompilerConfig = { + compilationMode: 'infer' // Default mode +}; +``` + +**Options:** +- `'infer'` (default): The compiler will compile: + - Functions explicitly annotated with `"use memo"` directive + - Component and hook functions that are named like a component or hook _and_ create JSX and/or call other hooks +- `'syntax'`: Only compile components using [Flow component syntax](https://flow.org/en/docs/react/component-syntax/) and hooks using [Flow hook syntax](https://flow.org/en/docs/react/hook-syntax/) +- `'annotation'`: Only compile functions that are explicitly annotated with `"use memo"` directive. This can be useful if you are incrementally adopting the compiler. +- `'all'`: Compile all top-level functions (not recommended, as it may mistakenly compile non-React functions) + +#### `target` {/*target*/} + +Specifies the React version for compatibility. + +- **Type:** `'17' | '18' | '19'` +- **Default:** `'19'` + +```js +const ReactCompilerConfig = { + target: '18' +}; +``` + +When targeting older React versions, install `react-compiler-runtime`: + + +npm install react-compiler-runtime@rc + + +#### `sources` {/*sources*/} + +Filters which files to compile, enabling incremental adoption. If overriden, you must manually ignore the node_modules directory as it is not recommended to compile transformed JS. + +- **Type:** `string[] | (filename: string) => boolean` +- **Default:** Excludes `node_modules` + +```js +// Compile specific directories +const ReactCompilerConfig = { + sources: (filename) => { + return filename.indexOf('src/components') !== -1; + } +}; + +// Compile specific file patterns +const ReactCompilerConfig = { + sources: ['src/**/*.jsx', 'src/**/*.tsx'] +}; +``` + +Alternatively, use Babel's builtin [`overrides`](https://babeljs.io/docs/options#overrides) option: + +```js + // babel.config.js + module.exports = { + plugins: [ + // Global plugins that run on all files + ], + overrides: [ + { + test: "./src/specific-directory/**/*.{js,jsx,ts,tsx}", + plugins: [ + "babel-plugin-react-compiler" + ] + } + ] + }; +``` + +#### `panicThreshold` {/*panicthreshold*/} + +Controls compiler behavior when encountering errors. + +- **Type:** `'all_errors' | 'critical_errors' | 'none'` +- **Default:** `'none'` + +```js +const ReactCompilerConfig = { + panicThreshold: 'none' // Recommended for production +}; +``` + +**Options:** +- `'none'` (recommended): The compiler automatically skips components and hooks that break the Rules of React, allowing the rest of your code to be optimized +- `'critical_errors'`: Causes build failures when critical errors are found +- `'all_errors'`: Causes build failures when any diagnostic errors are found + + +**Important:** The default value `'none'` is the best choice for most applications. Using `'all_errors'` or `'critical_errors'` will cause build failures and should only be used for debugging during development. Production builds should always use `'none'`. + + +#### `noEmit` {/*noemit*/} + +Runs analysis without generating code. + +- **Type:** `boolean` +- **Default:** `false` + +```js +const ReactCompilerConfig = { + noEmit: true // Analysis only, no code generation +}; +``` + +#### `logger` {/*logger*/} + +Provides custom logging for compiler events. + +- **Type:** `Logger | null` +- **Default:** `null` + +For example: + +```ts +const ReactCompilerConfig = { + logger: { + logEvent(filename: string | null, event: LoggerEvent) { + switch (event.kind) { + case "CompileSuccess": { + console.log("✨ React Compiler successfully compiled: ", filename); + break; + } + case "CompileError": { + console.warn("⚠️ React Compiler failed to compile: " + filename); + console.warn(filename, JSON.stringify(event, null, 2)); + } + default: { + console.log(`React Compiler: ${filename}: ${event.kind}`); + } + } + } + } +}; +``` + +#### `gating` {/*gating*/} + +Enables conditional compilation based on an external feature flag. + +- **Type:** `{ source: string, importSpecifierName: string } | null` +- **Default:** `null` + +```js +const ReactCompilerConfig = { + gating: { + source: 'ReactCompilerFeatureFlag', + importSpecifierName: 'isCompilerEnabled' + } +}; +``` + +When configured, the compiler creates two versions of each compiled function: one optimized and one original. The optimized version is conditionally used based on the imported feature flag. + +**Example gating module implementation:** + +```js +// ReactCompilerFeatureFlag.js +export function isCompilerEnabled() { + // Your logic to determine if the compiler should be enabled + return process.env.REACT_COMPILER_ENABLED === 'true' || + Math.random() < 0.5; // A/B testing example +} +``` + +With this configuration, compiled components will conditionally use optimizations: + +```js +// Before compilation +function MyComponent(props) { + return
{props.text}
; +} + +// After compilation (simplified) +import { isCompilerEnabled } from 'ReactCompilerFeatureFlag'; +import { c as _c } from 'react/compiler-runtime'; + +const MyComponent = isCompilerEnabled() + ? function MyComponent(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.text) { + t0 =
{props.text}
; + $[0] = props.text; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; + } + : function MyComponent(props) { + return
{props.text}
; + }; +``` + +### Directives {/*directives*/} + +Directives are special string literals that control compiler behavior for specific functions. + +#### `"use memo"` {/*use-memo*/} + +Opts in a component or hook for compilation. + +```js +function MyComponent() { + "use memo"; + // This component will be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Forces compilation when using `compilationMode: 'annotation'` +- In `compilationMode: 'infer'`, explicitly marks function for optimization + +#### `"use no memo"` {/*use-no-memo*/} + +Opts out a component or hook from compilation. + +```js +function MyComponent() { + "use no memo"; + // This component will not be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Use when debugging compilation issues +- Temporary escape hatch, not meant for permanent use \ No newline at end of file diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..c860dd55f 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,37 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Getting Started", + "path": "/learn/react-compiler/getting-started" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Backwards Compatibility", + "path": "/learn/react-compiler/compatibility" + }, + { + "title": "Configuration", + "path": "/learn/react-compiler/configuration" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" + }, + { + "title": "Library Authors Guide", + "path": "/learn/react-compiler/library-authors" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..cf10194ea 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,14 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "React Compiler Options", + "path": "/reference/react/react-compiler" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 8ab07e9bb110cc610f81450f36908dadca0f6e68 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 14 Jul 2025 11:46:35 -0400 Subject: [PATCH 035/129] [compiler] Rewrite React Compiler Docs We've received feedback that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. --- src/content/learn/react-compiler.md | 346 ------------------ .../learn/react-compiler/compatibility.md | 74 ++++ .../learn/react-compiler/configuration.md | 79 ++++ src/content/learn/react-compiler/debugging.md | 93 +++++ .../learn/react-compiler/getting-started.md | 256 +++++++++++++ .../react-compiler/incremental-adoption.md | 211 +++++++++++ src/content/learn/react-compiler/index.md | 168 +++++++++ .../learn/react-compiler/library-authors.md | 91 +++++ .../learn/you-might-not-need-an-effect.md | 6 + src/content/reference/react/memo.md | 6 + src/content/reference/react/react-compiler.md | 284 ++++++++++++++ src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 32 +- src/sidebarReference.json | 8 + 15 files changed, 1317 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/compatibility.md create mode 100644 src/content/learn/react-compiler/configuration.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/getting-started.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/library-authors.md create mode 100644 src/content/reference/react/react-compiler.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/compatibility.md b/src/content/learn/react-compiler/compatibility.md new file mode 100644 index 000000000..aa509e19b --- /dev/null +++ b/src/content/learn/react-compiler/compatibility.md @@ -0,0 +1,74 @@ +--- +title: Backwards Compatibility +--- + + +React Compiler works best with React 19, but it also supports React 17 and 18 with additional configuration. + + + + +* How to configure React Compiler for React 17 and 18 + + + +## Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} + +React Compiler does not require any special configuration to work with React 19. For React 17 or 18, you need two things: + +### 1. Install the runtime package {/*install-runtime-package*/} + + +npm install react-compiler-runtime@rc + + +### 2. Configure the target version {/*configure-target-version*/} + +```js {5} +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // or '17' for React 17 + }], + ], +}; +``` + +Always use the major version number as a string for the `target` option. Use `'17'` not `17` or `'17.0.2'`. + +## Framework-specific configuration {/*framework-specific-configuration*/} + +### Next.js {/*nextjs*/} + +```js {5} +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js {10} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { target: '17' }], + ], + }, + }), + ], +}); +``` + diff --git a/src/content/learn/react-compiler/configuration.md b/src/content/learn/react-compiler/configuration.md new file mode 100644 index 000000000..1c5a54a2e --- /dev/null +++ b/src/content/learn/react-compiler/configuration.md @@ -0,0 +1,79 @@ +--- +title: Configuration +--- + + +React Compiler is designed to work out of the box with no configuration needed. Most users will not need to configure the compiler. However, if you need to customize its behavior, various configuration options are available. + + + + +* Available configuration options +* How to configure the compiler + + + +## Configuration Options Overview {/*configuration-options-overview*/} + +React Compiler accepts several options to customize its behavior. See the [API reference](/reference/react/react-compiler) for detailed documentation of each option. + +- **`compilationMode`** - Controls which functions to compile +- **`target`** - Specifies the React version for compatibility (17, 18, or 19) +- **`sources`** - Limits compilation to specific files or directories +- **`gating`** - Enables runtime feature flags for [incremental adoption](/learn/react-compiler/incremental-adoption) +- **`logger`** - Configures logging output for debugging +- **`panicThreshold`** - Sets when the compiler should halt on errors +- **`noEmit`** - Disables code generation + +## Basic Configuration {/*basic-configuration*/} + +Pass options to the Babel plugin: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // For React 18 compatibility + }], + ], +}; +``` + +## Framework Examples {/*framework-examples*/} + +### Next.js {/*nextjs*/} + +```js +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js +// vite.config.js +export default { + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { /* options */ }], + ], + }, + }), + ], +}; +``` + +## Learn More {/*learn-more*/} + +For detailed documentation of all configuration options, see the [React Compiler API reference](/reference/react/react-compiler). + +For incremental adoption strategies using these options, see the [incremental adoption guide](/learn/react-compiler/incremental-adoption). \ No newline at end of file diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..0dd2016a7 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/getting-started.md b/src/content/learn/react-compiler/getting-started.md new file mode 100644 index 000000000..9b328515b --- /dev/null +++ b/src/content/learn/react-compiler/getting-started.md @@ -0,0 +1,256 @@ +--- +title: Getting Started with React Compiler +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [backwards compatibility](/learn/react-compiler/compatibility). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react/react-compiler). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@6.0.0-rc.1 + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [Backwards compatibility](/learn/react-compiler/compatibility) for React 17 and 18 +- [Configuration options](/learn/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Library authors guide](/learn/react-compiler/library-authors) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..2135aabed --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,211 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* How to use the `sources` option for gradual rollout +* Using the "use no memo" directive +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Directory-Based Rollout {/*directory-based-rollout*/} + +The `sources` option lets you specify which files the compiler should process. This is the recommended approach for existing applications. + +### Start Small {/*start-small*/} + +Begin with a new feature or a well-tested part of your application: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: ['src/features/new-dashboard/**'], + }], + ], +}; +``` + +### Expand Gradually {/*expand-gradually*/} + +As you verify the compiler works well, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: [ + 'src/features/new-dashboard/**', + 'src/components/common/**', + 'src/hooks/**', + ], + }], + ], +}; +``` + +### Full Adoption {/*full-adoption*/} + +Once you're confident, remove the `sources` option to compile your entire codebase: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // Now compiles everything + ], +}; +``` + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach is more tedious as you need to add the directive to every component and hook you want to compile. It's only recommended when trying the compiler on a very small scale. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +For most projects, the directory-based approach with `sources` is more practical. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +### Example: Percentage-Based Rollout {/*example-percentage-based-rollout*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable for 20% of users + const userId = getUserId(); + return hashUserId(userId) % 100 < 20; +} +``` + +### Example: Environment-Based Gating {/*example-environment-based-gating*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable in staging, disable in production initially + return process.env.REACT_APP_ENV === 'staging'; +} +``` + +### Performance Testing with Gating {/*performance-testing-with-gating*/} + +Gating is particularly useful for measuring performance impact: + +1. Enable the compiler for a subset of users +2. Compare metrics between compiled and non-compiled versions +3. Monitor for any issues or regressions +4. Gradually increase the rollout percentage + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider adopting more gradually with a smaller `sources` pattern + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/learn/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..c24db962e --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,168 @@ +--- +title: React Compiler +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in RC. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/getting-started) such as Babel, Vite, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Getting Started](/learn/react-compiler/getting-started)** - Install React Compiler and configure it for your build tools +* **[Backwards Compatibility](/learn/react-compiler/compatibility)** - Support for React 17, 18, and 19 +* **[Configuration](/learn/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Library Authors Guide](/learn/react-compiler/library-authors)** - Best practices for shipping compiled code +* **[API Reference](/reference/react/react-compiler)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/library-authors.md b/src/content/learn/react-compiler/library-authors.md new file mode 100644 index 000000000..1c7090531 --- /dev/null +++ b/src/content/learn/react-compiler/library-authors.md @@ -0,0 +1,91 @@ +--- +title: Library Authors Guide +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +* Why libraries should ship compiled code +* How to set up compilation in your build pipeline +* Testing strategies for compiled libraries +* Publishing and documentation best practices + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code without needing to enable the compiler themselves +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile the library code. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '17', // Minimum React version + }], + ], +}; +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/react-compiler.md b/src/content/reference/react/react-compiler.md new file mode 100644 index 000000000..ec8e2dc5b --- /dev/null +++ b/src/content/reference/react/react-compiler.md @@ -0,0 +1,284 @@ +--- +title: React Compiler Options +--- + + + +React Compiler is a build-time tool that automatically optimizes your React application by adding memoization. + + + +```js +// babel.config.js +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], + ], + }; +}; +``` + + + +--- + +## Reference {/*reference*/} + +### Configuration Options {/*configuration-options*/} + +The React Compiler accepts configuration options to control its behavior. These options are passed to the Babel plugin. + +```js +const ReactCompilerConfig = { + compilationMode: 'infer', + target: '19', + sources: (filename) => { + return filename.indexOf('src/path/to/dir') !== -1; + }, + // Additional options... +}; +``` + +#### `compilationMode` {/*compilationmode*/} + +Controls how the compiler selects functions for compilation. + +- **Type:** `'infer' | 'syntax' | 'annotation' | 'all'` +- **Default:** `'infer'` + +```js +const ReactCompilerConfig = { + compilationMode: 'infer' // Default mode +}; +``` + +**Options:** +- `'infer'` (default): The compiler will compile: + - Functions explicitly annotated with `"use memo"` directive + - Component and hook functions that are named like a component or hook _and_ create JSX and/or call other hooks +- `'syntax'`: Only compile components using [Flow component syntax](https://flow.org/en/docs/react/component-syntax/) and hooks using [Flow hook syntax](https://flow.org/en/docs/react/hook-syntax/) +- `'annotation'`: Only compile functions that are explicitly annotated with `"use memo"` directive. This can be useful if you are incrementally adopting the compiler. +- `'all'`: Compile all top-level functions (not recommended, as it may mistakenly compile non-React functions) + +#### `target` {/*target*/} + +Specifies the React version for compatibility. + +- **Type:** `'17' | '18' | '19'` +- **Default:** `'19'` + +```js +const ReactCompilerConfig = { + target: '18' +}; +``` + +When targeting older React versions, install `react-compiler-runtime`: + + +npm install react-compiler-runtime@rc + + +#### `sources` {/*sources*/} + +Filters which files to compile, enabling incremental adoption. If overriden, you must manually ignore the node_modules directory as it is not recommended to compile transformed JS. + +- **Type:** `string[] | (filename: string) => boolean` +- **Default:** Excludes `node_modules` + +```js +// Compile specific directories +const ReactCompilerConfig = { + sources: (filename) => { + return filename.indexOf('src/components') !== -1; + } +}; + +// Compile specific file patterns +const ReactCompilerConfig = { + sources: ['src/**/*.jsx', 'src/**/*.tsx'] +}; +``` + +Alternatively, use Babel's builtin [`overrides`](https://babeljs.io/docs/options#overrides) option: + +```js + // babel.config.js + module.exports = { + plugins: [ + // Global plugins that run on all files + ], + overrides: [ + { + test: "./src/specific-directory/**/*.{js,jsx,ts,tsx}", + plugins: [ + "babel-plugin-react-compiler" + ] + } + ] + }; +``` + +#### `panicThreshold` {/*panicthreshold*/} + +Controls compiler behavior when encountering errors. + +- **Type:** `'all_errors' | 'critical_errors' | 'none'` +- **Default:** `'none'` + +```js +const ReactCompilerConfig = { + panicThreshold: 'none' // Recommended for production +}; +``` + +**Options:** +- `'none'` (recommended): The compiler automatically skips components and hooks that break the Rules of React, allowing the rest of your code to be optimized +- `'critical_errors'`: Causes build failures when critical errors are found +- `'all_errors'`: Causes build failures when any diagnostic errors are found + + +**Important:** The default value `'none'` is the best choice for most applications. Using `'all_errors'` or `'critical_errors'` will cause build failures and should only be used for debugging during development. Production builds should always use `'none'`. + + +#### `noEmit` {/*noemit*/} + +Runs analysis without generating code. + +- **Type:** `boolean` +- **Default:** `false` + +```js +const ReactCompilerConfig = { + noEmit: true // Analysis only, no code generation +}; +``` + +#### `logger` {/*logger*/} + +Provides custom logging for compiler events. + +- **Type:** `Logger | null` +- **Default:** `null` + +For example: + +```ts +const ReactCompilerConfig = { + logger: { + logEvent(filename: string | null, event: LoggerEvent) { + switch (event.kind) { + case "CompileSuccess": { + console.log("✨ React Compiler successfully compiled: ", filename); + break; + } + case "CompileError": { + console.warn("⚠️ React Compiler failed to compile: " + filename); + console.warn(filename, JSON.stringify(event, null, 2)); + } + default: { + console.log(`React Compiler: ${filename}: ${event.kind}`); + } + } + } + } +}; +``` + +#### `gating` {/*gating*/} + +Enables conditional compilation based on an external feature flag. + +- **Type:** `{ source: string, importSpecifierName: string } | null` +- **Default:** `null` + +```js +const ReactCompilerConfig = { + gating: { + source: 'ReactCompilerFeatureFlag', + importSpecifierName: 'isCompilerEnabled' + } +}; +``` + +When configured, the compiler creates two versions of each compiled function: one optimized and one original. The optimized version is conditionally used based on the imported feature flag. + +**Example gating module implementation:** + +```js +// ReactCompilerFeatureFlag.js +export function isCompilerEnabled() { + // Your logic to determine if the compiler should be enabled + return process.env.REACT_COMPILER_ENABLED === 'true' || + Math.random() < 0.5; // A/B testing example +} +``` + +With this configuration, compiled components will conditionally use optimizations: + +```js +// Before compilation +function MyComponent(props) { + return
{props.text}
; +} + +// After compilation (simplified) +import { isCompilerEnabled } from 'ReactCompilerFeatureFlag'; +import { c as _c } from 'react/compiler-runtime'; + +const MyComponent = isCompilerEnabled() + ? function MyComponent(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.text) { + t0 =
{props.text}
; + $[0] = props.text; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; + } + : function MyComponent(props) { + return
{props.text}
; + }; +``` + +### Directives {/*directives*/} + +Directives are special string literals that control compiler behavior for specific functions. + +#### `"use memo"` {/*use-memo*/} + +Opts in a component or hook for compilation. + +```js +function MyComponent() { + "use memo"; + // This component will be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Forces compilation when using `compilationMode: 'annotation'` +- In `compilationMode: 'infer'`, explicitly marks function for optimization + +#### `"use no memo"` {/*use-no-memo*/} + +Opts out a component or hook from compilation. + +```js +function MyComponent() { + "use no memo"; + // This component will not be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Use when debugging compilation issues +- Temporary escape hatch, not meant for permanent use \ No newline at end of file diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..c860dd55f 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,37 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Getting Started", + "path": "/learn/react-compiler/getting-started" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Backwards Compatibility", + "path": "/learn/react-compiler/compatibility" + }, + { + "title": "Configuration", + "path": "/learn/react-compiler/configuration" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" + }, + { + "title": "Library Authors Guide", + "path": "/learn/react-compiler/library-authors" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..cf10194ea 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,14 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "React Compiler Options", + "path": "/reference/react/react-compiler" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 5f9a481560151303b77b4c646c8c89ed95f16f5d Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Mon, 14 Jul 2025 14:48:24 -0400 Subject: [PATCH 036/129] [compiler] Rewrite React Compiler Docs We've received feedback that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. --- src/content/learn/react-compiler.md | 346 ------------------ .../learn/react-compiler/compatibility.md | 74 ++++ .../learn/react-compiler/configuration.md | 79 ++++ src/content/learn/react-compiler/debugging.md | 93 +++++ .../learn/react-compiler/getting-started.md | 256 +++++++++++++ .../react-compiler/incremental-adoption.md | 211 +++++++++++ src/content/learn/react-compiler/index.md | 168 +++++++++ .../learn/react-compiler/library-authors.md | 91 +++++ .../learn/you-might-not-need-an-effect.md | 6 + src/content/reference/react/memo.md | 6 + src/content/reference/react/react-compiler.md | 284 ++++++++++++++ src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 32 +- src/sidebarReference.json | 8 + 15 files changed, 1317 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/compatibility.md create mode 100644 src/content/learn/react-compiler/configuration.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/getting-started.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/library-authors.md create mode 100644 src/content/reference/react/react-compiler.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/compatibility.md b/src/content/learn/react-compiler/compatibility.md new file mode 100644 index 000000000..aa509e19b --- /dev/null +++ b/src/content/learn/react-compiler/compatibility.md @@ -0,0 +1,74 @@ +--- +title: Backwards Compatibility +--- + + +React Compiler works best with React 19, but it also supports React 17 and 18 with additional configuration. + + + + +* How to configure React Compiler for React 17 and 18 + + + +## Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} + +React Compiler does not require any special configuration to work with React 19. For React 17 or 18, you need two things: + +### 1. Install the runtime package {/*install-runtime-package*/} + + +npm install react-compiler-runtime@rc + + +### 2. Configure the target version {/*configure-target-version*/} + +```js {5} +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // or '17' for React 17 + }], + ], +}; +``` + +Always use the major version number as a string for the `target` option. Use `'17'` not `17` or `'17.0.2'`. + +## Framework-specific configuration {/*framework-specific-configuration*/} + +### Next.js {/*nextjs*/} + +```js {5} +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js {10} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { target: '17' }], + ], + }, + }), + ], +}); +``` + diff --git a/src/content/learn/react-compiler/configuration.md b/src/content/learn/react-compiler/configuration.md new file mode 100644 index 000000000..1c5a54a2e --- /dev/null +++ b/src/content/learn/react-compiler/configuration.md @@ -0,0 +1,79 @@ +--- +title: Configuration +--- + + +React Compiler is designed to work out of the box with no configuration needed. Most users will not need to configure the compiler. However, if you need to customize its behavior, various configuration options are available. + + + + +* Available configuration options +* How to configure the compiler + + + +## Configuration Options Overview {/*configuration-options-overview*/} + +React Compiler accepts several options to customize its behavior. See the [API reference](/reference/react/react-compiler) for detailed documentation of each option. + +- **`compilationMode`** - Controls which functions to compile +- **`target`** - Specifies the React version for compatibility (17, 18, or 19) +- **`sources`** - Limits compilation to specific files or directories +- **`gating`** - Enables runtime feature flags for [incremental adoption](/learn/react-compiler/incremental-adoption) +- **`logger`** - Configures logging output for debugging +- **`panicThreshold`** - Sets when the compiler should halt on errors +- **`noEmit`** - Disables code generation + +## Basic Configuration {/*basic-configuration*/} + +Pass options to the Babel plugin: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '18', // For React 18 compatibility + }], + ], +}; +``` + +## Framework Examples {/*framework-examples*/} + +### Next.js {/*nextjs*/} + +```js +// next.config.js +module.exports = { + experimental: { + reactCompiler: { + target: '18', + }, + }, +}; +``` + +### Vite {/*vite*/} + +```js +// vite.config.js +export default { + plugins: [ + react({ + babel: { + plugins: [ + ['babel-plugin-react-compiler', { /* options */ }], + ], + }, + }), + ], +}; +``` + +## Learn More {/*learn-more*/} + +For detailed documentation of all configuration options, see the [React Compiler API reference](/reference/react/react-compiler). + +For incremental adoption strategies using these options, see the [incremental adoption guide](/learn/react-compiler/incremental-adoption). \ No newline at end of file diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..0dd2016a7 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/getting-started.md b/src/content/learn/react-compiler/getting-started.md new file mode 100644 index 000000000..9b328515b --- /dev/null +++ b/src/content/learn/react-compiler/getting-started.md @@ -0,0 +1,256 @@ +--- +title: Getting Started with React Compiler +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [backwards compatibility](/learn/react-compiler/compatibility). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react/react-compiler). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@6.0.0-rc.1 + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [Backwards compatibility](/learn/react-compiler/compatibility) for React 17 and 18 +- [Configuration options](/learn/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Library authors guide](/learn/react-compiler/library-authors) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..2135aabed --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,211 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* How to use the `sources` option for gradual rollout +* Using the "use no memo" directive +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Directory-Based Rollout {/*directory-based-rollout*/} + +The `sources` option lets you specify which files the compiler should process. This is the recommended approach for existing applications. + +### Start Small {/*start-small*/} + +Begin with a new feature or a well-tested part of your application: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: ['src/features/new-dashboard/**'], + }], + ], +}; +``` + +### Expand Gradually {/*expand-gradually*/} + +As you verify the compiler works well, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + sources: [ + 'src/features/new-dashboard/**', + 'src/components/common/**', + 'src/hooks/**', + ], + }], + ], +}; +``` + +### Full Adoption {/*full-adoption*/} + +Once you're confident, remove the `sources` option to compile your entire codebase: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // Now compiles everything + ], +}; +``` + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach is more tedious as you need to add the directive to every component and hook you want to compile. It's only recommended when trying the compiler on a very small scale. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +For most projects, the directory-based approach with `sources` is more practical. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +### Example: Percentage-Based Rollout {/*example-percentage-based-rollout*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable for 20% of users + const userId = getUserId(); + return hashUserId(userId) % 100 < 20; +} +``` + +### Example: Environment-Based Gating {/*example-environment-based-gating*/} + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Enable in staging, disable in production initially + return process.env.REACT_APP_ENV === 'staging'; +} +``` + +### Performance Testing with Gating {/*performance-testing-with-gating*/} + +Gating is particularly useful for measuring performance impact: + +1. Enable the compiler for a subset of users +2. Compare metrics between compiled and non-compiled versions +3. Monitor for any issues or regressions +4. Gradually increase the rollout percentage + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider adopting more gradually with a smaller `sources` pattern + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/learn/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..3efc622c0 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,168 @@ +--- +title: React Compiler +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in RC. We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/getting-started) such as Babel, Vite, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Getting Started](/learn/react-compiler/getting-started)** - Install React Compiler and configure it for your build tools +* **[Backwards Compatibility](/learn/react-compiler/compatibility)** - Support for React 17, 18, and 19 +* **[Configuration](/learn/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Library Authors Guide](/learn/react-compiler/library-authors)** - Best practices for shipping compiled code +* **[API Reference](/reference/react/react-compiler)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/library-authors.md b/src/content/learn/react-compiler/library-authors.md new file mode 100644 index 000000000..1c7090531 --- /dev/null +++ b/src/content/learn/react-compiler/library-authors.md @@ -0,0 +1,91 @@ +--- +title: Library Authors Guide +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +* Why libraries should ship compiled code +* How to set up compilation in your build pipeline +* Testing strategies for compiled libraries +* Publishing and documentation best practices + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code without needing to enable the compiler themselves +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile the library code. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + target: '17', // Minimum React version + }], + ], +}; +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [API reference](/reference/react/react-compiler) for all compiler options \ No newline at end of file diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/react-compiler.md b/src/content/reference/react/react-compiler.md new file mode 100644 index 000000000..ec8e2dc5b --- /dev/null +++ b/src/content/reference/react/react-compiler.md @@ -0,0 +1,284 @@ +--- +title: React Compiler Options +--- + + + +React Compiler is a build-time tool that automatically optimizes your React application by adding memoization. + + + +```js +// babel.config.js +module.exports = function () { + return { + plugins: [ + ['babel-plugin-react-compiler', ReactCompilerConfig], + ], + }; +}; +``` + + + +--- + +## Reference {/*reference*/} + +### Configuration Options {/*configuration-options*/} + +The React Compiler accepts configuration options to control its behavior. These options are passed to the Babel plugin. + +```js +const ReactCompilerConfig = { + compilationMode: 'infer', + target: '19', + sources: (filename) => { + return filename.indexOf('src/path/to/dir') !== -1; + }, + // Additional options... +}; +``` + +#### `compilationMode` {/*compilationmode*/} + +Controls how the compiler selects functions for compilation. + +- **Type:** `'infer' | 'syntax' | 'annotation' | 'all'` +- **Default:** `'infer'` + +```js +const ReactCompilerConfig = { + compilationMode: 'infer' // Default mode +}; +``` + +**Options:** +- `'infer'` (default): The compiler will compile: + - Functions explicitly annotated with `"use memo"` directive + - Component and hook functions that are named like a component or hook _and_ create JSX and/or call other hooks +- `'syntax'`: Only compile components using [Flow component syntax](https://flow.org/en/docs/react/component-syntax/) and hooks using [Flow hook syntax](https://flow.org/en/docs/react/hook-syntax/) +- `'annotation'`: Only compile functions that are explicitly annotated with `"use memo"` directive. This can be useful if you are incrementally adopting the compiler. +- `'all'`: Compile all top-level functions (not recommended, as it may mistakenly compile non-React functions) + +#### `target` {/*target*/} + +Specifies the React version for compatibility. + +- **Type:** `'17' | '18' | '19'` +- **Default:** `'19'` + +```js +const ReactCompilerConfig = { + target: '18' +}; +``` + +When targeting older React versions, install `react-compiler-runtime`: + + +npm install react-compiler-runtime@rc + + +#### `sources` {/*sources*/} + +Filters which files to compile, enabling incremental adoption. If overriden, you must manually ignore the node_modules directory as it is not recommended to compile transformed JS. + +- **Type:** `string[] | (filename: string) => boolean` +- **Default:** Excludes `node_modules` + +```js +// Compile specific directories +const ReactCompilerConfig = { + sources: (filename) => { + return filename.indexOf('src/components') !== -1; + } +}; + +// Compile specific file patterns +const ReactCompilerConfig = { + sources: ['src/**/*.jsx', 'src/**/*.tsx'] +}; +``` + +Alternatively, use Babel's builtin [`overrides`](https://babeljs.io/docs/options#overrides) option: + +```js + // babel.config.js + module.exports = { + plugins: [ + // Global plugins that run on all files + ], + overrides: [ + { + test: "./src/specific-directory/**/*.{js,jsx,ts,tsx}", + plugins: [ + "babel-plugin-react-compiler" + ] + } + ] + }; +``` + +#### `panicThreshold` {/*panicthreshold*/} + +Controls compiler behavior when encountering errors. + +- **Type:** `'all_errors' | 'critical_errors' | 'none'` +- **Default:** `'none'` + +```js +const ReactCompilerConfig = { + panicThreshold: 'none' // Recommended for production +}; +``` + +**Options:** +- `'none'` (recommended): The compiler automatically skips components and hooks that break the Rules of React, allowing the rest of your code to be optimized +- `'critical_errors'`: Causes build failures when critical errors are found +- `'all_errors'`: Causes build failures when any diagnostic errors are found + + +**Important:** The default value `'none'` is the best choice for most applications. Using `'all_errors'` or `'critical_errors'` will cause build failures and should only be used for debugging during development. Production builds should always use `'none'`. + + +#### `noEmit` {/*noemit*/} + +Runs analysis without generating code. + +- **Type:** `boolean` +- **Default:** `false` + +```js +const ReactCompilerConfig = { + noEmit: true // Analysis only, no code generation +}; +``` + +#### `logger` {/*logger*/} + +Provides custom logging for compiler events. + +- **Type:** `Logger | null` +- **Default:** `null` + +For example: + +```ts +const ReactCompilerConfig = { + logger: { + logEvent(filename: string | null, event: LoggerEvent) { + switch (event.kind) { + case "CompileSuccess": { + console.log("✨ React Compiler successfully compiled: ", filename); + break; + } + case "CompileError": { + console.warn("⚠️ React Compiler failed to compile: " + filename); + console.warn(filename, JSON.stringify(event, null, 2)); + } + default: { + console.log(`React Compiler: ${filename}: ${event.kind}`); + } + } + } + } +}; +``` + +#### `gating` {/*gating*/} + +Enables conditional compilation based on an external feature flag. + +- **Type:** `{ source: string, importSpecifierName: string } | null` +- **Default:** `null` + +```js +const ReactCompilerConfig = { + gating: { + source: 'ReactCompilerFeatureFlag', + importSpecifierName: 'isCompilerEnabled' + } +}; +``` + +When configured, the compiler creates two versions of each compiled function: one optimized and one original. The optimized version is conditionally used based on the imported feature flag. + +**Example gating module implementation:** + +```js +// ReactCompilerFeatureFlag.js +export function isCompilerEnabled() { + // Your logic to determine if the compiler should be enabled + return process.env.REACT_COMPILER_ENABLED === 'true' || + Math.random() < 0.5; // A/B testing example +} +``` + +With this configuration, compiled components will conditionally use optimizations: + +```js +// Before compilation +function MyComponent(props) { + return
{props.text}
; +} + +// After compilation (simplified) +import { isCompilerEnabled } from 'ReactCompilerFeatureFlag'; +import { c as _c } from 'react/compiler-runtime'; + +const MyComponent = isCompilerEnabled() + ? function MyComponent(props) { + const $ = _c(2); + let t0; + if ($[0] !== props.text) { + t0 =
{props.text}
; + $[0] = props.text; + $[1] = t0; + } else { + t0 = $[1]; + } + return t0; + } + : function MyComponent(props) { + return
{props.text}
; + }; +``` + +### Directives {/*directives*/} + +Directives are special string literals that control compiler behavior for specific functions. + +#### `"use memo"` {/*use-memo*/} + +Opts in a component or hook for compilation. + +```js +function MyComponent() { + "use memo"; + // This component will be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Forces compilation when using `compilationMode: 'annotation'` +- In `compilationMode: 'infer'`, explicitly marks function for optimization + +#### `"use no memo"` {/*use-no-memo*/} + +Opts out a component or hook from compilation. + +```js +function MyComponent() { + "use no memo"; + // This component will not be optimized by the compiler + return
{/* ... */}
; +} +``` + +**Usage:** +- Place at the beginning of the function body +- Use when debugging compilation issues +- Temporary escape hatch, not meant for permanent use \ No newline at end of file diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..c860dd55f 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,37 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Getting Started", + "path": "/learn/react-compiler/getting-started" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Backwards Compatibility", + "path": "/learn/react-compiler/compatibility" + }, + { + "title": "Configuration", + "path": "/learn/react-compiler/configuration" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" + }, + { + "title": "Library Authors Guide", + "path": "/learn/react-compiler/library-authors" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..cf10194ea 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,14 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "React Compiler Options", + "path": "/reference/react/react-compiler" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From e63b0aac3f1aebb3c31c9a64e0302d6a1c6dbed1 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Tue, 15 Jul 2025 12:44:44 -0400 Subject: [PATCH 037/129] [compiler] Rewrite React Compiler Docs We've received feedback that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 34 ++ .../learn/react-compiler/installation.md | 256 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 6 + src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2331 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..8397de53b --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,34 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase by using the `sources` option to enable the compiler for specific directories first. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Library Authors Guide](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..1f1542e97 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,256 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..77dd54df8 --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 2a171f6a571fb179d57eefe011822225602a4ec5 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 16 Jul 2025 15:22:02 -0400 Subject: [PATCH 038/129] [compiler] Rewrite React Compiler Docs We've received [feedback](https://bsky.app/profile/danabra.mov/post/3lr46ciujjs2r) that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. Preview: https://react-dev-git-pr7868-fbopensource.vercel.app/ --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 33 ++ .../learn/react-compiler/installation.md | 256 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 6 + src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2330 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..480187ed5 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..1f1542e97 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,256 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..77dd54df8 --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. This is sometimes referred to as "fine-grained reactivity." + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 61ba325531968c17831628b5d5bfc88e451f053b Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 16 Jul 2025 15:22:02 -0400 Subject: [PATCH 039/129] [compiler] Rewrite React Compiler Docs We've received [feedback](https://bsky.app/profile/danabra.mov/post/3lr46ciujjs2r) that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. Preview: https://react-dev-git-pr7868-fbopensource.vercel.app/ --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 33 ++ .../learn/react-compiler/installation.md | 256 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 6 + src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2330 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..480187ed5 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..1f1542e97 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,256 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..b749bd6ee --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). We are still working on a Stable Release in the very near future. + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From c8c6b3a812542c02ef8886afd387b6a6cb8697ae Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 16 Jul 2025 15:22:02 -0400 Subject: [PATCH 040/129] [compiler] Rewrite React Compiler Docs We've received [feedback](https://bsky.app/profile/danabra.mov/post/3lr46ciujjs2r) that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. Preview: https://react-dev-git-pr7868-fbopensource.vercel.app/ --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 33 ++ .../learn/react-compiler/installation.md | 256 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 6 + src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2330 insertions(+), 349 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..480187ed5 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..1f1542e97 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,256 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..b853f3d71 --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..7f16db156 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 095fd3611a7ec0881fa7bc5c04fca2d722a5a10a Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 16 Jul 2025 15:22:02 -0400 Subject: [PATCH 041/129] [compiler] Rewrite React Compiler Docs We've received [feedback](https://bsky.app/profile/danabra.mov/post/3lr46ciujjs2r) that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. Preview: https://react-dev-git-pr7868-fbopensource.vercel.app/ --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 33 ++ .../learn/react-compiler/installation.md | 256 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 91 ++++- src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2413 insertions(+), 351 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..480187ed5 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..1f1542e97 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,256 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### Remix {/*usage-with-remix*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {2,14} +// vite.config.js +import babel from "vite-plugin-babel"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + remix({ /* ... */}), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..b853f3d71 --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..b91171e8f 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- @@ -112,7 +118,7 @@ label { #### Should you add memo everywhere? {/*should-you-add-memo-everywhere*/} -If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. +If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. Optimizing with `memo` is only valuable when your component re-renders often with the same exact props, and its re-rendering logic is expensive. If there is no perceptible lag when your component re-renders, `memo` is unnecessary. Keep in mind that `memo` is completely useless if the props passed to your component are *always different,* such as if you pass an object or a plain function defined during rendering. This is why you will often need [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-components) and [`useCallback`](/reference/react/useCallback#skipping-re-rendering-of-components) together with `memo`. @@ -222,7 +228,7 @@ export default function MyApp() { const [theme, setTheme] = useState('dark'); function handleClick() { - setTheme(theme === 'dark' ? 'light' : 'dark'); + setTheme(theme === 'dark' ? 'light' : 'dark'); } return ( @@ -357,6 +363,87 @@ Avoid doing deep equality checks inside `arePropsEqual` unless you are 100% sure --- +### Do I still need React.memo if I use React Compiler? {/*react-compiler-memo*/} + +When you enable [React Compiler](/learn/react-compiler), you typically don't need `React.memo` anymore. The compiler automatically optimizes component re-rendering for you. + +Here's how it works: + +**Without React Compiler**, you need `React.memo` to prevent unnecessary re-renders: + +```js +// Parent re-renders every second +function Parent() { + const [seconds, setSeconds] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setSeconds(s => s + 1); + }, 1000); + return () => clearInterval(interval); + }, []); + + return ( + <> +

Seconds: {seconds}

+ + + ); +} + +// Without memo, this re-renders every second even though props don't change +const ExpensiveChild = memo(function ExpensiveChild({ name }) { + console.log('ExpensiveChild rendered'); + return
Hello, {name}!
; +}); +``` + +**With React Compiler enabled**, the same optimization happens automatically: + +```js +// No memo needed - compiler prevents re-renders automatically +function ExpensiveChild({ name }) { + console.log('ExpensiveChild rendered'); + return
Hello, {name}!
; +} +``` + +Here's the key part of what the React Compiler generates: + +```js {6-12} +function Parent() { + const $ = _c(7); + const [seconds, setSeconds] = useState(0); + // ... other code ... + + let t3; + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + t3 = ; + $[4] = t3; + } else { + t3 = $[4]; + } + // ... return statement ... +} +``` + +Notice the highlighted lines: The compiler wraps `` in a cache check. Since the `name` prop is always `"John"`, this JSX is created once and reused on every parent re-render. This is exactly what `React.memo` does - it prevents the child from re-rendering when its props haven't changed. + +The React Compiler automatically: +1. Tracks that the `name` prop passed to `ExpensiveChild` hasn't changed +2. Reuses the previously created JSX for `` +3. Skips re-rendering `ExpensiveChild` entirely + +This means **you can safely remove `React.memo` from your components when using React Compiler**. The compiler provides the same optimization automatically, making your code cleaner and easier to maintain. + + + +The compiler's optimization is actually more comprehensive than `React.memo`. It also memoizes intermediate values and expensive computations within your components, similar to combining `React.memo` with `useMemo` throughout your component tree. + + + +--- + ## Troubleshooting {/*troubleshooting*/} ### My component re-renders when a prop is an object, array, or function {/*my-component-rerenders-when-a-prop-is-an-object-or-array*/} diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 1180495aa0d5a8f986527f21a441d7599a642167 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Wed, 16 Jul 2025 15:22:02 -0400 Subject: [PATCH 042/129] [compiler] Rewrite React Compiler Docs We've received [feedback](https://bsky.app/profile/danabra.mov/post/3lr46ciujjs2r) that the compiler docs are difficult to understand and not prominent enough that people don't realize the compiler is a serious project and is near stable. This PR rewrites the whole compiler doc section, giving it its own category as well as a standalone reference page. Preview: https://react-dev-git-pr7868-fbopensource.vercel.app/ --- src/content/learn/react-compiler.md | 346 ------------------ src/content/learn/react-compiler/debugging.md | 93 +++++ .../react-compiler/incremental-adoption.md | 225 ++++++++++++ src/content/learn/react-compiler/index.md | 33 ++ .../learn/react-compiler/installation.md | 258 +++++++++++++ .../learn/react-compiler/introduction.md | 170 +++++++++ .../learn/you-might-not-need-an-effect.md | 6 + .../react-compiler/compilationMode.md | 201 ++++++++++ .../react-compiler/compiling-libraries.md | 106 ++++++ .../reference/react-compiler/configuration.md | 151 ++++++++ .../reference/react-compiler/directives.md | 198 ++++++++++ .../react-compiler/directives/use-memo.md | 157 ++++++++ .../react-compiler/directives/use-no-memo.md | 147 ++++++++ .../reference/react-compiler/gating.md | 139 +++++++ .../reference/react-compiler/logger.md | 118 ++++++ .../react-compiler/panicThreshold.md | 87 +++++ .../reference/react-compiler/target.md | 148 ++++++++ src/content/reference/react/index.md | 8 + src/content/reference/react/memo.md | 91 ++++- src/content/reference/react/useCallback.md | 6 + src/content/reference/react/useMemo.md | 6 + src/sidebarLearn.json | 24 +- src/sidebarReference.json | 48 +++ 23 files changed, 2415 insertions(+), 351 deletions(-) delete mode 100644 src/content/learn/react-compiler.md create mode 100644 src/content/learn/react-compiler/debugging.md create mode 100644 src/content/learn/react-compiler/incremental-adoption.md create mode 100644 src/content/learn/react-compiler/index.md create mode 100644 src/content/learn/react-compiler/installation.md create mode 100644 src/content/learn/react-compiler/introduction.md create mode 100644 src/content/reference/react-compiler/compilationMode.md create mode 100644 src/content/reference/react-compiler/compiling-libraries.md create mode 100644 src/content/reference/react-compiler/configuration.md create mode 100644 src/content/reference/react-compiler/directives.md create mode 100644 src/content/reference/react-compiler/directives/use-memo.md create mode 100644 src/content/reference/react-compiler/directives/use-no-memo.md create mode 100644 src/content/reference/react-compiler/gating.md create mode 100644 src/content/reference/react-compiler/logger.md create mode 100644 src/content/reference/react-compiler/panicThreshold.md create mode 100644 src/content/reference/react-compiler/target.md diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d21..000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes. - -The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **Not** memoized by React Compiler, since this is not a component or hook -function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } - -// Memoized by React Compiler since this is a component -function TableContainer({ items }) { - // This function call would be memoized: - const data = expensivelyProcessAReallyLargeArrayOfObjects(items); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 000000000..1883125a6 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 000000000..4cf1b70cf --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'NONE' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'CRITICAL_ERRORS' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( +
    + {sortedTodos.map(todo => ( + + ))} +
+ ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 000000000..480187ed5 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 000000000..3606c9c6d --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,258 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {3,9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### React Router {/*usage-with-react-router*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {3-4,16} +// vite.config.js +import { defineConfig } from "vite"; +import babel from "vite-plugin-babel"; +import { reactRouter } from "@react-router/dev/vite"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + reactRouter(), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 000000000..b853f3d71 --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,170 @@ +--- +title: Introduction +--- + + +React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +import { useMemo, useCallback, memo } from 'react'; + +const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { + const processedData = useMemo(() => { + return expensiveProcessing(data); + }, [data]); + + const handleClick = useCallback((item) => { + onClick(item.id); + }, [onClick]); + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **Not** memoized by React Compiler, since this is not a component or hook +function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ } + +// Memoized by React Compiler since this is a component +function TableContainer({ items }) { + // This function call would be memoized: + const data = expensivelyProcessAReallyLargeArrayOfObjects(items); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work. + +### Is it safe to use? {/*is-it-safe-to-use*/} + +React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules). + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and [oxc](https://github.com/oxc-project/oxc/issues/10048) teams to build first class support for React Compiler so you won't have to add Babel back to your build pipelines in the future. + +Next.js users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab..486f6b8f8 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 000000000..5513d1c6a --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
    + {props.items.map(item => ( +
  • {item.name}
  • + ))} +
+ ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
{props.content}
; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
Content
; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 000000000..f09ffcb72 --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 000000000..f38f1afc0 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 000000000..705d0f620 --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
{/* ... */}
; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
This will be optimized
; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
This won't be optimized
; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
Compiled
; +} + +function Component2() { + return
Also compiled
; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
Not compiled
; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 000000000..431862682 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 000000000..e6c419bc6 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 000000000..2959c49fa --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 000000000..41e2a1da0 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 000000000..e20f5c0c5 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 000000000..381748513 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index a68ddc014..ae823b119 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -19,6 +19,14 @@ Programmatic React features: * [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/rsc/directives) - Provide instructions to bundlers compatible with React Server Components. +## React Compiler {/*react-compiler*/} + +The React Compiler is a build-time optimization tool that automatically memoizes your React components and values: + +* [Configuration](/reference/react-compiler/configuration) - Configuration options for React Compiler. +* [Directives](/reference/react-compiler/directives) - Function-level directives to control compilation. +* [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Guide for shipping pre-compiled library code. + ## React DOM {/*react-dom*/} React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: diff --git a/src/content/reference/react/memo.md b/src/content/reference/react/memo.md index 01d6290f1..b91171e8f 100644 --- a/src/content/reference/react/memo.md +++ b/src/content/reference/react/memo.md @@ -12,6 +12,12 @@ const MemoizedComponent = memo(SomeComponent, arePropsEqual?) + + +[React Compiler](/learn/react-compiler) automatically applies the equivalent of `memo` to all components, reducing the need for manual memoization. You can use the compiler to handle component memoization automatically. + + + --- @@ -112,7 +118,7 @@ label { #### Should you add memo everywhere? {/*should-you-add-memo-everywhere*/} -If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. +If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. Optimizing with `memo` is only valuable when your component re-renders often with the same exact props, and its re-rendering logic is expensive. If there is no perceptible lag when your component re-renders, `memo` is unnecessary. Keep in mind that `memo` is completely useless if the props passed to your component are *always different,* such as if you pass an object or a plain function defined during rendering. This is why you will often need [`useMemo`](/reference/react/useMemo#skipping-re-rendering-of-components) and [`useCallback`](/reference/react/useCallback#skipping-re-rendering-of-components) together with `memo`. @@ -222,7 +228,7 @@ export default function MyApp() { const [theme, setTheme] = useState('dark'); function handleClick() { - setTheme(theme === 'dark' ? 'light' : 'dark'); + setTheme(theme === 'dark' ? 'light' : 'dark'); } return ( @@ -357,6 +363,87 @@ Avoid doing deep equality checks inside `arePropsEqual` unless you are 100% sure --- +### Do I still need React.memo if I use React Compiler? {/*react-compiler-memo*/} + +When you enable [React Compiler](/learn/react-compiler), you typically don't need `React.memo` anymore. The compiler automatically optimizes component re-rendering for you. + +Here's how it works: + +**Without React Compiler**, you need `React.memo` to prevent unnecessary re-renders: + +```js +// Parent re-renders every second +function Parent() { + const [seconds, setSeconds] = useState(0); + + useEffect(() => { + const interval = setInterval(() => { + setSeconds(s => s + 1); + }, 1000); + return () => clearInterval(interval); + }, []); + + return ( + <> +

Seconds: {seconds}

+ + + ); +} + +// Without memo, this re-renders every second even though props don't change +const ExpensiveChild = memo(function ExpensiveChild({ name }) { + console.log('ExpensiveChild rendered'); + return
Hello, {name}!
; +}); +``` + +**With React Compiler enabled**, the same optimization happens automatically: + +```js +// No memo needed - compiler prevents re-renders automatically +function ExpensiveChild({ name }) { + console.log('ExpensiveChild rendered'); + return
Hello, {name}!
; +} +``` + +Here's the key part of what the React Compiler generates: + +```js {6-12} +function Parent() { + const $ = _c(7); + const [seconds, setSeconds] = useState(0); + // ... other code ... + + let t3; + if ($[4] === Symbol.for("react.memo_cache_sentinel")) { + t3 = ; + $[4] = t3; + } else { + t3 = $[4]; + } + // ... return statement ... +} +``` + +Notice the highlighted lines: The compiler wraps `` in a cache check. Since the `name` prop is always `"John"`, this JSX is created once and reused on every parent re-render. This is exactly what `React.memo` does - it prevents the child from re-rendering when its props haven't changed. + +The React Compiler automatically: +1. Tracks that the `name` prop passed to `ExpensiveChild` hasn't changed +2. Reuses the previously created JSX for `` +3. Skips re-rendering `ExpensiveChild` entirely + +This means **you can safely remove `React.memo` from your components when using React Compiler**. The compiler provides the same optimization automatically, making your code cleaner and easier to maintain. + + + +The compiler's optimization is actually more comprehensive than `React.memo`. It also memoizes intermediate values and expensive computations within your components, similar to combining `React.memo` with `useMemo` throughout your component tree. + + + +--- + ## Troubleshooting {/*troubleshooting*/} ### My component re-renders when a prop is an object, array, or function {/*my-component-rerenders-when-a-prop-is-an-object-or-array*/} diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index abcd474df..acae804ec 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -12,6 +12,12 @@ const cachedFn = useCallback(fn, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index 6bfaba8ee..f0bdd77fb 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -12,6 +12,12 @@ const cachedValue = useMemo(calculateValue, dependencies) + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + --- diff --git a/src/sidebarLearn.json b/src/sidebarLearn.json index c83fdb189..bd14a83ea 100644 --- a/src/sidebarLearn.json +++ b/src/sidebarLearn.json @@ -53,11 +53,29 @@ { "title": "React Developer Tools", "path": "/learn/react-developer-tools" + } + ] + }, + { + "title": "React Compiler", + "path": "/learn/react-compiler", + "canary": true, + "routes": [ + { + "title": "Introduction", + "path": "/learn/react-compiler/introduction" }, { - "title": "React Compiler", - "path": "/learn/react-compiler", - "canary": true + "title": "Installation", + "path": "/learn/react-compiler/installation" + }, + { + "title": "Incremental Adoption", + "path": "/learn/react-compiler/incremental-adoption" + }, + { + "title": "Debugging and Troubleshooting", + "path": "/learn/react-compiler/debugging" } ] }, diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5e3939842..152fca00d 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -168,6 +168,54 @@ } ] }, + { + "hasSectionHeader": true, + "sectionHeader": "React Compiler" + }, + { + "title": "Configuration", + "path": "/reference/react-compiler/configuration", + "routes": [ + { + "title": "compilationMode", + "path": "/reference/react-compiler/compilationMode" + }, + { + "title": "gating", + "path": "/reference/react-compiler/gating" + }, + { + "title": "logger", + "path": "/reference/react-compiler/logger" + }, + { + "title": "panicThreshold", + "path": "/reference/react-compiler/panicThreshold" + }, + { + "title": "target", + "path": "/reference/react-compiler/target" + } + ] + }, + { + "title": "Directives", + "path": "/reference/react-compiler/directives", + "routes": [ + { + "title": "\"use memo\"", + "path": "/reference/react-compiler/directives/use-memo" + }, + { + "title": "\"use no memo\"", + "path": "/reference/react-compiler/directives/use-no-memo" + } + ] + }, + { + "title": "Compiling Libraries", + "path": "/reference/react-compiler/compiling-libraries" + }, { "hasSectionHeader": true, "sectionHeader": "react-dom@{{version}}" From 8fe2bfd168de8ce700975501d8fecd1c84e012c5 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 18 Jul 2025 16:42:34 -0400 Subject: [PATCH 043/129] [be] Add deadlinks script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While rewriting the compiler docs I happened to notice some deadlinks. This PR adds a new `yarn deadlinks` script to identify all deadlinks. The script handles: - [x] checks images correctly (images are stored in /public but links can omit the /public) - [x] looks up React error codes for dynamic error pages - [x] lints links to contributors and uses URL from acknowledgements page if the member is no longer active on the core team - [x] special injected anchor tags like #recap and #challenges Example: ``` yarn run v1.22.22 $ node scripts/deadLinkChecker.js Checking 177 markdown files... src/content/errors/index.md:10:22 Link text: https://react.dev/errors/149 URL: /errors/421 ✗ Target file not found for: /errors/421 src/content/learn/add-react-to-an-existing-project.md:23:58 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/add-react-to-an-existing-project.md:27:45 Link text: benefit from the best practices URL: /learn/start-a-new-react-project#can-i-use-react-without-a-framework ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/add-react-to-an-existing-project.md:152:269 Link text: a React framework URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/importing-and-exporting-components.md:135:2 Link text: Default and named exports URL: /images/docs/illustrations/i_import-export.svg ✗ Target file not found for: /images/docs/illustrations/i_import-export.svg src/content/learn/react-developer-tools.md:27:2 Link text: React Developer Tools extension URL: /images/docs/react-devtools-extension.png ✗ Target file not found for: /images/docs/react-devtools-extension.png src/content/learn/react-developer-tools.md:53:2 Link text: React Developer Tools standalone URL: /images/docs/react-devtools-standalone.png ✗ Target file not found for: /images/docs/react-devtools-standalone.png src/content/learn/synchronizing-with-effects.md:735:18 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/typescript.md:16:3 Link text: Common types from `@types/react` URL: /learn/typescript/#useful-types ✗ Target file not found for: /learn/typescript/ src/content/learn/typescript.md:17:3 Link text: Further learning locations URL: /learn/typescript/#further-learning ✗ Target file not found for: /learn/typescript/ src/content/learn/typescript.md:23:5 Link text: production-grade React frameworks URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/you-might-not-need-an-effect.md:29:399 Link text: frameworks URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/you-might-not-need-an-effect.md:754:106 Link text: frameworks URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/learn/your-first-component.md:218:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react/ViewTransition.md:146:248 Link text: reveal content URL: /link-to-suspense-below ✗ Target file not found for: /link-to-suspense-below src/content/reference/react/captureOwnerStack.md:60:94 Link text: `errorInfo.componentStack` in `onUncaughtError` URL: /reference/react-dom/client/hydrateRoot#show-a-dialog-for-uncaught-errors ✗ Anchor #show-a-dialog-for-uncaught-errors not found in reference/react-dom/client/hydrateRoot.md src/content/reference/react/forwardRef.md:9:65 Link text: here URL: /blog/2024/04/25/react-19#ref-as-a-prop ✗ Target file not found for: /blog/2024/04/25/react-19 src/content/reference/react/use.md:315:24 Link text: Server Component URL: /reference/react/components#server-components ✗ Anchor #server-components not found in reference/react/components.md src/content/reference/react/useDebugValue.md:64:2 Link text: A screenshot of React DevTools showing the debug value URL: /images/docs/react-devtools-usedebugvalue.png ✗ Target file not found for: /images/docs/react-devtools-usedebugvalue.png src/content/reference/react/useEffect.md:899:67 Link text: if you use a framework, URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react/useEffect.md:1051:18 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react/useEffect.md:1736:92 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react/useInsertionEffect.md:136:65 Link text: non-blocking update, URL: /reference/react/useTransition#marking-a-state-update-as-a-non-blocking-transition ✗ Anchor #marking-a-state-update-as-a-non-blocking-transition not found in reference/react/useTransition.md src/content/reference/react-dom/createPortal.md:53:76 Link text: key. URL: /learn/rendering-lists/#keeping-list-items-in-order-with-key ✗ Target file not found for: /learn/rendering-lists/ src/content/reference/react-dom/index.md:24:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/index.md:51:3 Link text: `unmountComponentAtNode` URL: /reference/react-dom/unmountComponentAtNode ✗ Target file not found for: /reference/react-dom/unmountComponentAtNode src/content/reference/react-dom/preinit.md:7:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/preinitModule.md:7:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/preload.md:7:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/preloadModule.md:7:1 Link text: React-based frameworks URL: /learn/start-a-new-react-project ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/rsc/directives.md:13:36 Link text: bundlers compatible with React Server Components URL: /learn/start-a-new-react-project#full-stack-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/rsc/server-components.md:7:34 Link text: React Server Components URL: /learn/start-a-new-react-project#full-stack-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/rsc/server-functions.md:198:28 Link text: `useActionState` URL: /reference/react-dom/hooks/useFormState ✗ Target file not found for: /reference/react-dom/hooks/useFormState src/content/reference/rsc/server-functions.md:222:28 Link text: `useActionState` URL: /reference/react-dom/hooks/useFormState ✗ Target file not found for: /reference/react-dom/hooks/useFormState src/content/reference/rsc/use-client.md:44:77 Link text: compatible bundlers URL: /learn/start-a-new-react-project#full-stack-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/rsc/use-server.md:98:54 Link text: serializable props URL: /reference/rsc/use-client#passing-props-from-server-to-client-components ✗ Anchor #passing-props-from-server-to-client-components not found in reference/rsc/use-client.md src/content/reference/react-dom/client/createRoot.md:212:278 Link text: using a framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/client/index.md:7:185 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/components/common.md:919:89 Link text: check out more examples. URL: /reference/react/useRef#examples-dom ✗ Anchor #examples-dom not found in reference/react/useRef.md src/content/reference/react-dom/components/form.md:39:23 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/form.md:233:63 Link text: reference documentation URL: /reference/react/hooks/useOptimistic ✗ Target file not found for: /reference/react/hooks/useOptimistic src/content/reference/react-dom/components/input.md:33:24 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/link.md:33:23 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/meta.md:33:23 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/option.md:39:25 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/progress.md:33:27 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/script.md:34:25 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/select.md:39:25 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/style.md:33:24 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/textarea.md:33:27 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/components/title.md:33:24 Link text: common element props. URL: /reference/react-dom/components/common#props ✗ Anchor #props not found in reference/react-dom/components/common.md src/content/reference/react-dom/server/index.md:7:182 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/reference/react-dom/static/index.md:7:146 Link text: framework URL: /learn/start-a-new-react-project#production-grade-react-frameworks ✗ Target file not found for: /learn/start-a-new-react-project src/content/blog/2023/03/16/introducing-react-dev.md:45:5 Link text: API Reference URL: /reference ✗ Target file not found for: /reference src/content/blog/2023/03/16/introducing-react-dev.md:256:147 Link text: Conditional Rendering URL: /learn/conditional-rendering#challenges ✗ Anchor #challenges not found in learn/conditional-rendering.md src/content/blog/2023/03/16/introducing-react-dev.md:610:117 Link text: Alternatives URL: /reference/react-dom/findDOMNode#alternatives ✗ Target file not found for: /reference/react-dom/findDOMNode src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md:34:40 Link text: Next.js App Router URL: /learn/start-a-new-react-project#nextjs-app-router ✗ Target file not found for: /learn/start-a-new-react-project src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md:95:605 Link text: Next.js App Router URL: /learn/start-a-new-react-project#nextjs-app-router ✗ Target file not found for: /learn/start-a-new-react-project src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md:110:3 Link text: Sathya Gunasekaran URL: /community/team#sathya-gunasekaran ✗ Anchor #sathya-gunasekaran not found in community/team.md src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md:112:3 Link text: Dan Abramov URL: /community/team#dan-abramov ✗ Anchor #dan-abramov not found in community/team.md src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md:114:3 Link text: Dan Abramov URL: /community/team#dan-abramov ✗ Anchor #dan-abramov not found in community/team.md src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md:116:3 Link text: Matt Carroll URL: /community/team#matt-carroll ✗ Anchor #matt-carroll not found in community/team.md src/content/blog/2024/04/25/react-19-upgrade-guide.md:132:20 Link text: improved how errors are handled URL: /blog/2024/04/25/react-19#error-handling ✗ Target file not found for: /blog/2024/04/25/react-19 src/content/blog/2024/04/25/react-19-upgrade-guide.md:502:19 Link text: `ref` as a prop URL: /blog/2024/04/25/react-19#ref-as-a-prop ✗ Target file not found for: /blog/2024/04/25/react-19 src/content/blog/2024/12/05/react-19.md:358:391 Link text: Full-stack React Architecture URL: /learn/start-a-new-react-project#which-features-make-up-the-react-teams-full-stack-architecture-vision ✗ Target file not found for: /learn/start-a-new-react-project src/content/blog/2024/12/05/react-19.md:392:28 Link text: React Server Actions URL: /reference/rsc/server-actions ✗ Target file not found for: /reference/rsc/server-actions src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md:2498:37 Link text: view transition classes URL: /reference/react/ViewTransition#view-transition-classes ✗ Anchor #view-transition-classes not found in reference/react/ViewTransition.md Found 67 dead links out of 1555 total links info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command. ``` --- package.json | 6 +- scripts/deadLinkChecker.js | 342 +++++++++++++++++++++++++++++++++++++ yarn.lock | 16 +- 3 files changed, 354 insertions(+), 10 deletions(-) create mode 100644 scripts/deadLinkChecker.js diff --git a/package.json b/package.json index 918d42fa2..c1cd16741 100644 --- a/package.json +++ b/package.json @@ -15,12 +15,13 @@ "prettier:diff": "yarn nit:source", "lint-heading-ids": "node scripts/headingIdLinter.js", "fix-headings": "node scripts/headingIdLinter.js --fix", - "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids rss", + "ci-check": "npm-run-all prettier:diff --parallel lint tsc lint-heading-ids rss deadlinks", "tsc": "tsc --noEmit", "start": "next start", "postinstall": "is-ci || husky install .husky", "check-all": "npm-run-all prettier lint:fix tsc rss", - "rss": "node scripts/generateRss.js" + "rss": "node scripts/generateRss.js", + "deadlinks": "node scripts/deadLinkChecker.js" }, "dependencies": { "@codesandbox/sandpack-react": "2.13.5", @@ -61,6 +62,7 @@ "autoprefixer": "^10.4.2", "babel-eslint": "10.x", "babel-plugin-react-compiler": "19.0.0-beta-e552027-20250112", + "chalk": "4.1.2", "eslint": "7.x", "eslint-config-next": "12.0.3", "eslint-config-react-app": "^5.2.1", diff --git a/scripts/deadLinkChecker.js b/scripts/deadLinkChecker.js new file mode 100644 index 000000000..ab8761e26 --- /dev/null +++ b/scripts/deadLinkChecker.js @@ -0,0 +1,342 @@ +#!/usr/bin/env node + +const fs = require('fs'); +const path = require('path'); +const globby = require('globby'); +const chalk = require('chalk'); + +const CONTENT_DIR = path.join(__dirname, '../src/content'); +const PUBLIC_DIR = path.join(__dirname, '../public'); +const fileCache = new Map(); +const anchorMap = new Map(); // Map> +const contributorMap = new Map(); // Map +let errorCodes = new Set(); + +async function readFileWithCache(filePath) { + if (!fileCache.has(filePath)) { + try { + const content = await fs.promises.readFile(filePath, 'utf8'); + fileCache.set(filePath, content); + } catch (error) { + throw new Error(`Failed to read file ${filePath}: ${error.message}`); + } + } + return fileCache.get(filePath); +} + +async function fileExists(filePath) { + try { + await fs.promises.access(filePath, fs.constants.R_OK); + return true; + } catch { + return false; + } +} + +function getMarkdownFiles() { + // Convert Windows paths to POSIX for globby compatibility + const baseDir = CONTENT_DIR.replace(/\\/g, '/'); + const patterns = [ + path.posix.join(baseDir, '**/*.md'), + path.posix.join(baseDir, '**/*.mdx'), + ]; + return globby.sync(patterns); +} + +function extractAnchorsFromContent(content) { + const anchors = new Set(); + + // MDX-style heading IDs: {/*anchor-id*/} + const mdxPattern = /\{\/\*([a-zA-Z0-9-_]+)\*\/\}/g; + let match; + while ((match = mdxPattern.exec(content)) !== null) { + anchors.add(match[1].toLowerCase()); + } + + // HTML id attributes + const htmlIdPattern = /\sid=["']([a-zA-Z0-9-_]+)["']/g; + while ((match = htmlIdPattern.exec(content)) !== null) { + anchors.add(match[1].toLowerCase()); + } + + // Markdown heading with explicit ID: ## Heading {#anchor-id} + const markdownHeadingPattern = /^#+\s+.*\{#([a-zA-Z0-9-_]+)\}/gm; + while ((match = markdownHeadingPattern.exec(content)) !== null) { + anchors.add(match[1].toLowerCase()); + } + + return anchors; +} + +async function buildAnchorMap(files) { + for (const filePath of files) { + const content = await readFileWithCache(filePath); + const anchors = extractAnchorsFromContent(content); + if (anchors.size > 0) { + anchorMap.set(filePath, anchors); + } + } +} + +function extractLinksFromContent(content) { + const linkPattern = /\[([^\]]*)\]\(([^)]+)\)/g; + const links = []; + let match; + + while ((match = linkPattern.exec(content)) !== null) { + const [, linkText, linkUrl] = match; + if (linkUrl.startsWith('/') && !linkUrl.startsWith('//')) { + const lines = content.substring(0, match.index).split('\n'); + const line = lines.length; + const lastLineStart = + lines.length > 1 ? content.lastIndexOf('\n', match.index - 1) + 1 : 0; + const column = match.index - lastLineStart + 1; + + links.push({ + text: linkText, + url: linkUrl, + line, + column, + }); + } + } + + return links; +} + +async function findTargetFile(urlPath) { + // Check if it's an image or static asset that might be in the public directory + const imageExtensions = [ + '.png', + '.jpg', + '.jpeg', + '.gif', + '.svg', + '.ico', + '.webp', + ]; + const hasImageExtension = imageExtensions.some((ext) => + urlPath.toLowerCase().endsWith(ext) + ); + + if (hasImageExtension || urlPath.includes('.')) { + // Check in public directory (with and without leading slash) + const publicPaths = [ + path.join(PUBLIC_DIR, urlPath), + path.join(PUBLIC_DIR, urlPath.substring(1)), + ]; + + for (const p of publicPaths) { + if (await fileExists(p)) { + return p; + } + } + } + + const possiblePaths = [ + path.join(CONTENT_DIR, urlPath + '.md'), + path.join(CONTENT_DIR, urlPath + '.mdx'), + path.join(CONTENT_DIR, urlPath, 'index.md'), + path.join(CONTENT_DIR, urlPath, 'index.mdx'), + // Without leading slash + path.join(CONTENT_DIR, urlPath.substring(1) + '.md'), + path.join(CONTENT_DIR, urlPath.substring(1) + '.mdx'), + path.join(CONTENT_DIR, urlPath.substring(1), 'index.md'), + path.join(CONTENT_DIR, urlPath.substring(1), 'index.mdx'), + ]; + + for (const p of possiblePaths) { + if (await fileExists(p)) { + return p; + } + } + return null; +} + +async function validateLink(link) { + const urlAnchorPattern = /#([a-zA-Z0-9-_]+)$/; + const anchorMatch = link.url.match(urlAnchorPattern); + const urlWithoutAnchor = link.url.replace(urlAnchorPattern, ''); + + if (urlWithoutAnchor === '/') { + return {valid: true}; + } + + // Check if it's an error code link + const errorCodeMatch = urlWithoutAnchor.match(/^\/errors\/(\d+)$/); + if (errorCodeMatch) { + const code = errorCodeMatch[1]; + if (!errorCodes.has(code)) { + return { + valid: false, + reason: `Error code ${code} not found in React error codes`, + }; + } + return {valid: true}; + } + + // Check if it's a contributor link on the team or acknowledgements page + if ( + anchorMatch && + (urlWithoutAnchor === '/community/team' || + urlWithoutAnchor === '/community/acknowledgements') + ) { + const anchorId = anchorMatch[1].toLowerCase(); + if (contributorMap.has(anchorId)) { + const correctUrl = contributorMap.get(anchorId); + if (correctUrl !== link.url) { + return { + valid: false, + reason: `Contributor link should be updated to: ${correctUrl}`, + }; + } + return {valid: true}; + } else { + return { + valid: false, + reason: `Contributor link not found`, + }; + } + } + + const targetFile = await findTargetFile(urlWithoutAnchor); + + if (!targetFile) { + return { + valid: false, + reason: `Target file not found for: ${urlWithoutAnchor}`, + }; + } + + // Only check anchors for content files, not static assets + if (anchorMatch && targetFile.startsWith(CONTENT_DIR)) { + const anchorId = anchorMatch[1].toLowerCase(); + + // TODO handle more special cases. These are usually from custom MDX components that include + // a Heading from src/components/MDX/Heading.tsx which automatically injects an anchor tag. + switch (anchorId) { + case 'challenges': + case 'recap': { + return {valid: true}; + } + } + + const fileAnchors = anchorMap.get(targetFile); + + if (!fileAnchors || !fileAnchors.has(anchorId)) { + return { + valid: false, + reason: `Anchor #${anchorMatch[1]} not found in ${path.relative( + CONTENT_DIR, + targetFile + )}`, + }; + } + } + + return {valid: true}; +} + +async function processFile(filePath) { + const content = await readFileWithCache(filePath); + const links = extractLinksFromContent(content); + const deadLinks = []; + + for (const link of links) { + const result = await validateLink(link); + if (!result.valid) { + deadLinks.push({ + file: path.relative(process.cwd(), filePath), + line: link.line, + column: link.column, + text: link.text, + url: link.url, + reason: result.reason, + }); + } + } + + return {deadLinks, totalLinks: links.length}; +} + +async function buildContributorMap() { + const teamFile = path.join(CONTENT_DIR, 'community/team.md'); + const teamContent = await readFileWithCache(teamFile); + + const teamMemberPattern = /]*permalink=["']([^"']+)["']/g; + let match; + + while ((match = teamMemberPattern.exec(teamContent)) !== null) { + const permalink = match[1]; + contributorMap.set(permalink, `/community/team#${permalink}`); + } + + const ackFile = path.join(CONTENT_DIR, 'community/acknowledgements.md'); + const ackContent = await readFileWithCache(ackFile); + const contributorPattern = /\*\s*\[([^\]]+)\]\(([^)]+)\)/g; + + while ((match = contributorPattern.exec(ackContent)) !== null) { + const name = match[1]; + const url = match[2]; + const hyphenatedName = name.toLowerCase().replace(/\s+/g, '-'); + if (!contributorMap.has(hyphenatedName)) { + contributorMap.set(hyphenatedName, url); + } + } +} + +async function fetchErrorCodes() { + try { + const response = await fetch( + 'https://raw.githubusercontent.com/facebook/react/main/scripts/error-codes/codes.json' + ); + if (!response.ok) { + throw new Error(`Failed to fetch error codes: ${response.status}`); + } + const codes = await response.json(); + errorCodes = new Set(Object.keys(codes)); + console.log(chalk.gray(`Fetched ${errorCodes.size} React error codes\n`)); + } catch (error) { + throw new Error(`Failed to fetch error codes: ${error.message}`); + } +} + +async function main() { + const files = getMarkdownFiles(); + console.log(chalk.gray(`Checking ${files.length} markdown files...`)); + + await fetchErrorCodes(); + await buildContributorMap(); + await buildAnchorMap(files); + + const filePromises = files.map((filePath) => processFile(filePath)); + const results = await Promise.all(filePromises); + const deadLinks = results.flatMap((r) => r.deadLinks); + const totalLinks = results.reduce((sum, r) => sum + r.totalLinks, 0); + + if (deadLinks.length > 0) { + for (const link of deadLinks) { + console.log(chalk.yellow(`${link.file}:${link.line}:${link.column}`)); + console.log(chalk.reset(` Link text: ${link.text}`)); + console.log(chalk.reset(` URL: ${link.url}`)); + console.log(` ${chalk.red('✗')} ${chalk.red(link.reason)}\n`); + } + + console.log( + chalk.red( + `\nFound ${deadLinks.length} dead link${ + deadLinks.length > 1 ? 's' : '' + } out of ${totalLinks} total links\n` + ) + ); + process.exit(1); + } + + console.log(chalk.green(`\n✓ All ${totalLinks} links are valid!\n`)); + process.exit(0); +} + +main().catch((error) => { + console.log(chalk.red(`Error: ${error.message}`)); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index e866a206b..e5eecaac2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2443,6 +2443,14 @@ ccount@^2.0.0: resolved "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz" integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== +chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + chalk@^2.0.0, chalk@^2.4.1: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" @@ -2452,14 +2460,6 @@ chalk@^2.0.0, chalk@^2.4.1: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - character-entities-html4@^1.0.0: version "1.1.4" resolved "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz" From ab32092308cd171ab68b7b024616cce40f0c28f6 Mon Sep 17 00:00:00 2001 From: Lauren Tan Date: Fri, 18 Jul 2025 16:42:36 -0400 Subject: [PATCH 044/129] Fix deadlinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Following `yarn deadlinks` as a guide, I fixed the following deadlinks: | File | Link Text | Current URL | Issue Type | Actual Fix Applied | Status | |------|-----------|-------------|------------|-------------------|--------| | `add-react-to-an-existing-project.md:23` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `add-react-to-an-existing-project.md:27` | benefit from the best practices | `/learn/start-a-new-react-project#can-i-use-react-without-a-framework` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `add-react-to-an-existing-project.md:152` | a React framework | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `synchronizing-with-effects.md:735` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `typescript.md:16` | Common types from `@types/react` | `/learn/typescript/#useful-types` | Trailing slash | `/learn/typescript#useful-types` | ✅ Fixed | | `typescript.md:17` | Further learning locations | `/learn/typescript/#further-learning` | Trailing slash | `/learn/typescript#further-learning` | ✅ Fixed | | `typescript.md:23` | production-grade React frameworks | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `you-might-not-need-an-effect.md:29` | frameworks | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `you-might-not-need-an-effect.md:754` | frameworks | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `your-first-component.md:218` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `ViewTransition.md:146` | reveal content | `/link-to-suspense-below` | Placeholder URL | `/reference/react/Suspense#revealing-content-together-at-once` | ✅ Fixed | | `captureOwnerStack.md:60` | `errorInfo.componentStack` in `onUncaughtError` | `/reference/react-dom/client/hydrateRoot#show-a-dialog-for-uncaught-errors` | Missing anchor | `/reference/react-dom/client/hydrateRoot#error-logging-in-production` | ✅ Fixed | | `forwardRef.md:9` | here | `/blog/2024/04/25/react-19#ref-as-a-prop` | Missing file + anchor | `/blog/2024/12/05/react-19#ref-as-a-prop` | ✅ Fixed | | `use.md:315` | Server Component | `/reference/react/components#server-components` | Missing anchor | `/reference/rsc/server-components` | ✅ Fixed | | `useEffect.md:899` | if you use a framework, | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `useEffect.md:1051` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `useEffect.md:1736` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `useInsertionEffect.md:136` | non-blocking update, | `/reference/react/useTransition#marking-a-state-update-as-a-non-blocking-transition` | Wrong anchor | `/reference/react/useTransition#perform-non-blocking-updates-with-actions` | ✅ Fixed | | `createPortal.md:53` | key. | `/learn/rendering-lists/#keeping-list-items-in-order-with-key` | Trailing slash | `/learn/rendering-lists#keeping-list-items-in-order-with-key` | ✅ Fixed | | `react-dom/index.md:24` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `react-dom/index.md:51` | `unmountComponentAtNode` | `/reference/react-dom/unmountComponentAtNode` | Missing file | `https://18.react.dev/reference/react-dom/unmountComponentAtNode` | ✅ Fixed | | `preinit.md:7` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `preinitModule.md:7` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `preload.md:7` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | `preloadModule.md:7` | React-based frameworks | `/learn/start-a-new-react-project` | Missing file | `/learn/creating-a-react-app` | ✅ Fixed | | 11 component files | common element props. | `/reference/react-dom/components/common#props` | Wrong anchor | `/reference/react-dom/components/common#common-props` | ✅ Fixed | | `server/index.md:7` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `static/index.md:7` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file + anchor | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `introducing-react-dev.md:45` | API Reference | `/reference` | Missing index | `/reference/react` | ✅ Fixed | | `introducing-react-dev.md:610` | Alternatives | `/reference/react-dom/findDOMNode#alternatives` | Missing file | `https://18.react.dev/reference/react-dom/findDOMNode#alternatives` | ✅ Fixed | | `react-labs-march-2023.md:34` | Next.js App Router | `/learn/start-a-new-react-project#nextjs-app-router` | Missing file + anchor | `/learn/creating-a-react-app#nextjs-app-router` | ✅ Fixed | | `react-labs-march-2023.md:95` | Next.js App Router | `/learn/start-a-new-react-project#nextjs-app-router` | Missing file + anchor | `/learn/creating-a-react-app#nextjs-app-router` | ✅ Fixed | | `react-labs-february-2024.md:110` | Sathya Gunasekaran | `/community/team#sathya-gunasekaran` | Contributor link | `https://github.com/gsathya` | ✅ Fixed | | `react-19-upgrade-guide.md:132` | improved how errors are handled | `/blog/2024/04/25/react-19#error-handling` | Missing file + anchor | `/blog/2024/12/05/react-19#error-handling` | ✅ Fixed | | `react-19-upgrade-guide.md:502` | `ref` as a prop | `/blog/2024/04/25/react-19#ref-as-a-prop` | Missing file + anchor | `/blog/2024/12/05/react-19#ref-as-a-prop` | ✅ Fixed | | `react-19.md:358` | Full-stack React Architecture | `/learn/start-a-new-react-project#which-features-make-up-the-react-teams-full-stack-architecture-vision` | Missing file + anchor | `/learn/creating-a-react-app#which-features-make-up-the-react-teams-full-stack-architecture-vision` | ✅ Fixed | | `react-19.md:392` | React Server Actions | `/reference/rsc/server-actions` | Missing file | `/reference/rsc/server-functions` | ✅ Fixed | | `view-transitions-activity.md:2498` | view transition classes | `/reference/react/ViewTransition#view-transition-classes` | Missing anchor | `/reference/react/ViewTransition#view-transition-class` | ✅ Fixed | | `rsc/directives.md:13` | bundlers compatible with React Server Components | `/learn/start-a-new-react-project#full-stack-frameworks` | Missing file | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `rsc/server-components.md:7` | React Server Components | `/learn/start-a-new-react-project#full-stack-frameworks` | Missing file | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `rsc/use-client.md:44` | compatible bundlers | `/learn/start-a-new-react-project#full-stack-frameworks` | Missing file | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `react-dom/client/createRoot.md:212` | using a framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `react-dom/client/index.md:7` | framework | `/learn/start-a-new-react-project#production-grade-react-frameworks` | Missing file | `/learn/creating-a-react-app#full-stack-frameworks` | ✅ Fixed | | `rsc/server-functions.md:198` | `useActionState` | `/reference/react-dom/hooks/useFormState` | Missing file | /reference/react/useActionState | ✅ Fixed | | `rsc/server-functions.md:222` | `useActionState` | `/reference/react-dom/hooks/useFormState` | Missing file | /reference/react/useActionState | ✅ Fixed | | `rsc/use-server.md:98` | serializable props | `/reference/rsc/use-client#passing-props-from-server-to-client-components` | Missing anchor | /reference/rsc/use-client#serializable-types | ✅ Fixed | | `react-dom/components/common.md:919` | check out more examples. | `/reference/react/useRef#examples-dom` | Missing anchor | /reference/react/useRef#usage | ✅ Fixed | | `react-dom/components/form.md:233` | reference documentation | `/reference/react/hooks/useOptimistic` | Missing file | /reference/react/useOptimistic | ✅ Fixed | ``` $ yarn deadlinks yarn run v1.22.22 $ node scripts/deadLinkChecker.js Checking 177 markdown files... Fetched 552 React error codes ✓ All 1552 links are valid! ✨ Done in 1.07s. ``` --- src/content/blog/2023/03/16/introducing-react-dev.md | 4 ++-- .../react-labs-what-we-have-been-working-on-march-2023.md | 4 ++-- ...react-labs-what-we-have-been-working-on-february-2024.md | 2 +- src/content/blog/2024/04/25/react-19-upgrade-guide.md | 4 ++-- src/content/blog/2024/12/05/react-19.md | 4 ++-- .../04/23/react-labs-view-transitions-activity-and-more.md | 2 +- src/content/learn/add-react-to-an-existing-project.md | 6 +++--- src/content/learn/synchronizing-with-effects.md | 2 +- src/content/learn/typescript.md | 6 +++--- src/content/learn/you-might-not-need-an-effect.md | 4 ++-- src/content/learn/your-first-component.md | 2 +- src/content/reference/react-dom/client/createRoot.md | 2 +- src/content/reference/react-dom/client/index.md | 2 +- src/content/reference/react-dom/components/common.md | 2 +- src/content/reference/react-dom/components/form.md | 4 ++-- src/content/reference/react-dom/components/input.md | 2 +- src/content/reference/react-dom/components/link.md | 2 +- src/content/reference/react-dom/components/meta.md | 2 +- src/content/reference/react-dom/components/option.md | 2 +- src/content/reference/react-dom/components/progress.md | 2 +- src/content/reference/react-dom/components/script.md | 2 +- src/content/reference/react-dom/components/select.md | 2 +- src/content/reference/react-dom/components/style.md | 2 +- src/content/reference/react-dom/components/textarea.md | 2 +- src/content/reference/react-dom/components/title.md | 2 +- src/content/reference/react-dom/createPortal.md | 2 +- src/content/reference/react-dom/index.md | 4 ++-- src/content/reference/react-dom/preinit.md | 2 +- src/content/reference/react-dom/preinitModule.md | 2 +- src/content/reference/react-dom/preload.md | 2 +- src/content/reference/react-dom/preloadModule.md | 2 +- src/content/reference/react-dom/server/index.md | 2 +- src/content/reference/react-dom/static/index.md | 2 +- src/content/reference/react/ViewTransition.md | 2 +- src/content/reference/react/captureOwnerStack.md | 2 +- src/content/reference/react/forwardRef.md | 2 +- src/content/reference/react/use.md | 2 +- src/content/reference/react/useEffect.md | 6 +++--- src/content/reference/react/useInsertionEffect.md | 2 +- src/content/reference/rsc/directives.md | 2 +- src/content/reference/rsc/server-components.md | 2 +- src/content/reference/rsc/server-functions.md | 4 ++-- src/content/reference/rsc/use-client.md | 2 +- src/content/reference/rsc/use-server.md | 2 +- 44 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/content/blog/2023/03/16/introducing-react-dev.md b/src/content/blog/2023/03/16/introducing-react-dev.md index f971ddafa..5437e1882 100644 --- a/src/content/blog/2023/03/16/introducing-react-dev.md +++ b/src/content/blog/2023/03/16/introducing-react-dev.md @@ -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)** provides the details and usage examples for every React API. +* **[API Reference](/reference/react)** provides the details and usage examples for every React API. Let's have a closer look at what you can find in each section. @@ -607,7 +607,7 @@ button { display: block; margin-top: 10px; } -Some API pages also include [Troubleshooting](/reference/react/useEffect#troubleshooting) (for common problems) and [Alternatives](/reference/react-dom/findDOMNode#alternatives) (for deprecated APIs). +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). 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. diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md index 1bc78149d..df1fd085d 100644 --- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md +++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md @@ -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/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. +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. 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. @@ -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/start-a-new-react-project#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/creating-a-react-app#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. diff --git a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md index ffe761624..9ec330e6b 100644 --- a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md +++ b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md @@ -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](/community/team#sathya-gunasekaran) spoke about the React Compiler at the [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) conference +- [Sathya Gunasekaran](https://github.com/gsathya) 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 diff --git a/src/content/blog/2024/04/25/react-19-upgrade-guide.md b/src/content/blog/2024/04/25/react-19-upgrade-guide.md index cb83a6176..2e9131eb3 100644 --- a/src/content/blog/2024/04/25/react-19-upgrade-guide.md +++ b/src/content/blog/2024/04/25/react-19-upgrade-guide.md @@ -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/04/25/react-19#error-handling) to reduce duplication by not re-throwing: +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: - **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`. @@ -499,7 +499,7 @@ function AutoselectingInput() { ### Deprecated: `element.ref` {/*deprecated-element-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`. +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`. Accessing `element.ref` will warn: diff --git a/src/content/blog/2024/12/05/react-19.md b/src/content/blog/2024/12/05/react-19.md index 65bf42757..1bbf2389c 100644 --- a/src/content/blog/2024/12/05/react-19.md +++ b/src/content/blog/2024/12/05/react-19.md @@ -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/start-a-new-react-project#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/creating-a-react-app#which-features-make-up-the-react-teams-full-stack-architecture-vision). @@ -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-actions). +For more, see the docs for [React Server Actions](/reference/rsc/server-functions). ## Improvements in React 19 {/*improvements-in-react-19*/} diff --git a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md index e4bb25a4a..0f54d02b4 100644 --- a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md +++ b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md @@ -2495,7 +2495,7 @@ For example, we can slow down the `default` cross fade animation: ``` -And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-classes): +And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-class): ```css ::view-transition-old(.slow-fade) { diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index 4684fb5b0..d2d8b1ad9 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -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/start-a-new-react-project). +1. **Build the React part of your app** using one of the [React-based frameworks](/learn/creating-a-react-app). 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/start-a-new-react-project#can-i-use-react-without-a-framework) baked into those frameworks. +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. 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. @@ -149,7 +149,7 @@ root.render(); Notice how the original HTML content from `index.html` is preserved, but your own `NavigationBar` React component now appears inside the `