diff --git a/.claude/instructions.md b/.claude/instructions.md new file mode 100644 index 000000000000..39573f6c4495 --- /dev/null +++ b/.claude/instructions.md @@ -0,0 +1,46 @@ +# React + +**Scope**: All code EXCEPT `/compiler/` (compiler has its own instructions). + +## Project Structure + +| Directory | Purpose | +|-----------|---------| +| `/packages/` | Publishable packages (react, react-dom, scheduler, etc.) | +| `/scripts/` | Build, test, and development scripts | +| `/fixtures/` | Test applications for manual testing | +| `/compiler/` | React Compiler (separate sub-project) | + +## Key Packages + +| Package | Purpose | +|---------|---------| +| `react` | Core React library | +| `react-dom` | DOM renderer | +| `react-reconciler` | Core reconciliation algorithm | +| `scheduler` | Cooperative scheduling | +| `react-server-dom-*` | Server Components | +| `react-devtools-*` | Developer Tools | +| `react-refresh` | Fast Refresh runtime | + +## Requirements + +- **Node**: Must be installed. Stop and prompt user if missing. +- **Package Manager**: Use `yarn` only. + +## Verification + +**IMPORTANT**: Use `/verify` to validate all changes before committing. + +## Commands + +| Command | Purpose | +|----------|----------------------| +| `/fix` | Lint and format code | +| `/test` | Run tests | +| `/flow` | Type check with Flow | +| `/flags` | Check feature flags | + +## Building + +Builds are handled by CI. Do not run locally unless instructed. diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 000000000000..f12f21abf44b --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,44 @@ +{ + "hooks": { + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "if [[ \"$PWD\" != */compiler* ]]; then cat .claude/instructions.md 2>/dev/null || true; fi" + } + ] + } + ] + }, + "permissions": { + "allow": [ + "Skill(extract-errors)", + "Skill(feature-flags)", + "Skill(fix)", + "Skill(flags)", + "Skill(flow)", + "Skill(test)", + "Skill(verify)", + "Bash(yarn test:*)", + "Bash(yarn test-www:*)", + "Bash(yarn test-classic:*)", + "Bash(yarn test-stable:*)", + "Bash(yarn linc:*)", + "Bash(yarn lint:*)", + "Bash(yarn flow:*)", + "Bash(yarn prettier:*)", + "Bash(yarn build:*)", + "Bash(yarn extract-errors:*)", + "Bash(yarn flags:*)" + ], + "deny": [ + "Bash(yarn download-build:*)", + "Bash(yarn download-build-for-head:*)", + "Bash(npm:*)", + "Bash(pnpm:*)", + "Bash(bun:*)", + "Bash(npx:*)" + ] + } +} diff --git a/.claude/skills/extract-errors/SKILL.md b/.claude/skills/extract-errors/SKILL.md new file mode 100644 index 000000000000..08bb1830eb49 --- /dev/null +++ b/.claude/skills/extract-errors/SKILL.md @@ -0,0 +1,12 @@ +--- +name: extract-errors +description: Use when adding new error messages to React, or seeing "unknown error code" warnings. +--- + +# Extract Error Codes + +## Instructions + +1. Run `yarn extract-errors` +2. Report if any new errors need codes assigned +3. Check if error codes are up to date diff --git a/.claude/skills/feature-flags/SKILL.md b/.claude/skills/feature-flags/SKILL.md new file mode 100644 index 000000000000..8e3281a1af28 --- /dev/null +++ b/.claude/skills/feature-flags/SKILL.md @@ -0,0 +1,79 @@ +--- +name: feature-flags +description: Use when feature flag tests fail, flags need updating, understanding @gate pragmas, debugging channel-specific test failures, or adding new flags to React. +--- + +# React Feature Flags + +## Flag Files + +| File | Purpose | +|------|---------| +| `packages/shared/ReactFeatureFlags.js` | Default flags (canary), `__EXPERIMENTAL__` overrides | +| `packages/shared/forks/ReactFeatureFlags.www.js` | www channel, `__VARIANT__` overrides | +| `packages/shared/forks/ReactFeatureFlags.native-fb.js` | React Native, `__VARIANT__` overrides | +| `packages/shared/forks/ReactFeatureFlags.test-renderer.js` | Test renderer | + +## Gating Tests + +### `@gate` pragma (test-level) + +Use when the feature is completely unavailable without the flag: + +```javascript +// @gate enableViewTransition +it('supports view transitions', () => { + // This test only runs when enableViewTransition is true + // and is SKIPPED (not failed) when false +}); +``` + +### `gate()` inline (assertion-level) + +Use when the feature exists but behavior differs based on flag: + +```javascript +it('renders component', async () => { + await act(() => root.render()); + + if (gate(flags => flags.enableNewBehavior)) { + expect(container.textContent).toBe('new output'); + } else { + expect(container.textContent).toBe('legacy output'); + } +}); +``` + +## Adding a New Flag + +1. Add to `ReactFeatureFlags.js` with default value +2. Add to each fork file (`*.www.js`, `*.native-fb.js`, etc.) +3. If it should vary in www/RN, set to `__VARIANT__` in the fork file +4. Gate tests with `@gate flagName` or inline `gate()` + +## Checking Flag States + +Use `/flags` to view states across channels. See the `flags` skill for full command options. + +## `__VARIANT__` Flags (GKs) + +Flags set to `__VARIANT__` simulate gatekeepers - tested twice (true and false): + +```bash +/test www # __VARIANT__ = true +/test www variant false # __VARIANT__ = false +``` + +## Debugging Channel-Specific Failures + +1. Run `/flags --diff ` to compare values +2. Check `@gate` conditions - test may be gated to specific channels +3. Run `/test ` to isolate the failure +4. Verify flag exists in all fork files if newly added + +## Common Mistakes + +- **Forgetting both variants** - Always test `www` AND `www variant false` for `__VARIANT__` flags +- **Using @gate for behavior differences** - Use inline `gate()` if both paths should run +- **Missing fork files** - New flags must be added to ALL fork files, not just the main one +- **Wrong gate syntax** - It's `gate(flags => flags.name)`, not `gate('name')` diff --git a/.claude/skills/fix/SKILL.md b/.claude/skills/fix/SKILL.md new file mode 100644 index 000000000000..9335409af1da --- /dev/null +++ b/.claude/skills/fix/SKILL.md @@ -0,0 +1,17 @@ +--- +name: fix +description: Use when you have lint errors, formatting issues, or before committing code to ensure it passes CI. +--- + +# Fix Lint and Formatting + +## Instructions + +1. Run `yarn prettier` to fix formatting +2. Run `yarn linc` to check for remaining lint issues +3. Report any remaining manual fixes needed + +## Common Mistakes + +- **Running prettier on wrong files** - `yarn prettier` only formats changed files +- **Ignoring linc errors** - These will fail CI, fix them before committing diff --git a/.claude/skills/flags/SKILL.md b/.claude/skills/flags/SKILL.md new file mode 100644 index 000000000000..a9ddc331ea98 --- /dev/null +++ b/.claude/skills/flags/SKILL.md @@ -0,0 +1,39 @@ +--- +name: flags +description: Use when you need to check feature flag states, compare channels, or debug why a feature behaves differently across release channels. +--- + +# Feature Flags + +Arguments: +- $ARGUMENTS: Optional flags + +## Options + +| Option | Purpose | +|--------|---------| +| (none) | Show all flags across all channels | +| `--diff ` | Compare flags between channels | +| `--cleanup` | Show flags grouped by cleanup status | +| `--csv` | Output in CSV format | + +## Channels + +- `www`, `www-modern` - Meta internal +- `canary`, `next`, `experimental` - OSS channels +- `rn`, `rn-fb`, `rn-next` - React Native + +## Legend + +βœ… enabled, ❌ disabled, πŸ§ͺ `__VARIANT__`, πŸ“Š profiling-only + +## Instructions + +1. Run `yarn flags $ARGUMENTS` +2. Explain the output to the user +3. For --diff, highlight meaningful differences + +## Common Mistakes + +- **Forgetting `__VARIANT__` flags** - These are tested both ways in www; check both variants +- **Comparing wrong channels** - Use `--diff` to see exact differences diff --git a/.claude/skills/flow/SKILL.md b/.claude/skills/flow/SKILL.md new file mode 100644 index 000000000000..5ef34a201299 --- /dev/null +++ b/.claude/skills/flow/SKILL.md @@ -0,0 +1,30 @@ +--- +name: flow +description: Use when you need to run Flow type checking, or when seeing Flow type errors in React code. +--- + +# Flow Type Checking + +Arguments: +- $ARGUMENTS: Renderer to check (default: dom-node) + +## Renderers + +| Renderer | When to Use | +|----------|-------------| +| `dom-node` | Default, recommended for most changes | +| `dom-browser` | Browser-specific DOM code | +| `native` | React Native | +| `fabric` | React Native Fabric | + +## Instructions + +1. Run `yarn flow $ARGUMENTS` (use `dom-node` if no argument) +2. Report type errors with file locations +3. For comprehensive checking (slow), use `yarn flow-ci` + +## Common Mistakes + +- **Running without a renderer** - Always specify or use default `dom-node` +- **Ignoring suppressions** - Check if `$FlowFixMe` comments are masking real issues +- **Missing type imports** - Ensure types are imported from the correct package diff --git a/.claude/skills/test/SKILL.md b/.claude/skills/test/SKILL.md new file mode 100644 index 000000000000..e150ad7e549e --- /dev/null +++ b/.claude/skills/test/SKILL.md @@ -0,0 +1,46 @@ +--- +name: test +description: Use when you need to run tests for React core. Supports source, www, stable, and experimental channels. +--- + +Run tests for the React codebase. + +Arguments: +- $ARGUMENTS: Channel, flags, and test pattern + +Usage Examples: +- `/test ReactFiberHooks` - Run with source channel (default) +- `/test experimental ReactFiberHooks` - Run with experimental channel +- `/test www ReactFiberHooks` - Run with www-modern channel +- `/test www variant false ReactFiberHooks` - Test __VARIANT__=false +- `/test stable ReactFiberHooks` - Run with stable channel +- `/test classic ReactFiberHooks` - Run with www-classic channel +- `/test watch ReactFiberHooks` - Run in watch mode (TDD) + +Release Channels: +- `(default)` - Source/canary channel, uses ReactFeatureFlags.js defaults +- `experimental` - Source/experimental channel with __EXPERIMENTAL__ flags = true +- `www` - www-modern channel with __VARIANT__ flags = true +- `www variant false` - www channel with __VARIANT__ flags = false +- `stable` - What ships to npm +- `classic` - Legacy www-classic (rarely needed) + +Instructions: +1. Parse channel from arguments (default: source) +2. Map to yarn command: + - (default) β†’ `yarn test --silent --no-watchman ` + - experimental β†’ `yarn test -r=experimental --silent --no-watchman ` + - stable β†’ `yarn test-stable --silent --no-watchman ` + - classic β†’ `yarn test-classic --silent --no-watchman ` + - www β†’ `yarn test-www --silent --no-watchman ` + - www variant false β†’ `yarn test-www --variant=false --silent --no-watchman ` +3. Report test results and any failures + +Hard Rules: +1. **Use --silent to see failures** - This limits the test output to only failures. +2. **Use --no-watchman** - This is a common failure in sandboxing. + +Common Mistakes: +- **Running without a pattern** - Runs ALL tests, very slow. Always specify a pattern. +- **Forgetting both www variants** - Test `www` AND `www variant false` for `__VARIANT__` flags. +- **Test skipped unexpectedly** - Check for `@gate` pragma; see `feature-flags` skill. diff --git a/.claude/skills/verify/SKILL.md b/.claude/skills/verify/SKILL.md new file mode 100644 index 000000000000..daed015e28e4 --- /dev/null +++ b/.claude/skills/verify/SKILL.md @@ -0,0 +1,24 @@ +--- +name: verify +description: Use when you want to validate changes before committing, or when you need to check all React contribution requirements. +--- + +# Verification + +Run all verification steps. + +Arguments: +- $ARGUMENTS: Test pattern for the test step + +## Instructions + +Run these first in sequence: +1. Run `yarn prettier` - format code (stop if fails) +2. Run `yarn linc` - lint changed files (stop if fails) + +Then run these with subagents in parallel: +1. Use `/flow` to type check (stop if fails) +2. Use `/test` to test changes in source (stop if fails) +3. Use `/test www` to test changes in www (stop if fails) + +If all pass, show success summary. On failure, stop immediately and report the issue with suggested fixes. diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index f644328ad927..2164efec0c8f 100644 --- a/.codesandbox/ci.json +++ b/.codesandbox/ci.json @@ -1,7 +1,7 @@ { "packages": ["packages/react", "packages/react-dom", "packages/react-server-dom-webpack", "packages/scheduler"], "buildCommand": "download-build-in-codesandbox-ci", - "node": "18", + "node": "20", "publishDirectory": { "react": "build/oss-experimental/react", "react-dom": "build/oss-experimental/react-dom", diff --git a/.eslintignore b/.eslintignore index c30542a3f7e2..fd9cc6bdca2f 100644 --- a/.eslintignore +++ b/.eslintignore @@ -28,3 +28,6 @@ packages/react-devtools-shared/src/hooks/__tests__/__source__/__untransformed__/ packages/react-devtools-shell/dist packages/react-devtools-timeline/dist packages/react-devtools-timeline/static + +# Imported third-party Flow types +flow-typed/ diff --git a/.eslintrc.js b/.eslintrc.js index 4e023cd9d333..a922421e83fb 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -331,6 +331,8 @@ module.exports = { 'packages/react-server-dom-turbopack/**/*.js', 'packages/react-server-dom-parcel/**/*.js', 'packages/react-server-dom-fb/**/*.js', + 'packages/react-flight-server-fb/**/*.js', + 'packages/react-server-dom-unbundled/**/*.js', 'packages/react-test-renderer/**/*.js', 'packages/react-debug-tools/**/*.js', 'packages/react-devtools-extensions/**/*.js', @@ -462,12 +464,14 @@ module.exports = { globals: { nativeFabricUIManager: 'readonly', RN$enableMicrotasksInReact: 'readonly', + RN$isNativeEventTargetEventDispatchingEnabled: 'readonly', }, }, { files: ['packages/react-server-dom-webpack/**/*.js'], globals: { __webpack_chunk_load__: 'readonly', + __webpack_get_script_filename__: 'readonly', __webpack_require__: 'readonly', }, }, @@ -505,7 +509,6 @@ module.exports = { __IS_FIREFOX__: 'readonly', __IS_EDGE__: 'readonly', __IS_NATIVE__: 'readonly', - __IS_INTERNAL_MCP_BUILD__: 'readonly', __IS_INTERNAL_VERSION__: 'readonly', chrome: 'readonly', }, @@ -516,6 +519,14 @@ module.exports = { __IS_INTERNAL_VERSION__: 'readonly', }, }, + { + files: ['packages/react-devtools-*/**/*.js'], + excludedFiles: '**/__tests__/**/*.js', + plugins: ['eslint-plugin-react-hooks-published'], + rules: { + 'react-hooks-published/rules-of-hooks': ERROR, + }, + }, { files: ['packages/eslint-plugin-react-hooks/src/**/*'], extends: ['plugin:@typescript-eslint/recommended'], @@ -546,13 +557,10 @@ module.exports = { }, globals: { - $Call: 'readonly', - $ElementType: 'readonly', $Flow$ModuleRef: 'readonly', $FlowFixMe: 'readonly', $Keys: 'readonly', $NonMaybeType: 'readonly', - $PropertyType: 'readonly', $ReadOnly: 'readonly', $ReadOnlyArray: 'readonly', $ArrayBufferView: 'readonly', @@ -560,6 +568,7 @@ module.exports = { CallSite: 'readonly', ConsoleTask: 'readonly', // TOOD: Figure out what the official name of this will be. ReturnType: 'readonly', + AggregateError: 'readonly', AnimationFrameID: 'readonly', WeakRef: 'readonly', // For Flow type annotation. Only `BigInt` is valid at runtime. @@ -567,6 +576,7 @@ module.exports = { BigInt: 'readonly', BigInt64Array: 'readonly', BigUint64Array: 'readonly', + CacheType: 'readonly', Class: 'readonly', ClientRect: 'readonly', CopyInspectedElementPath: 'readonly', @@ -578,16 +588,20 @@ module.exports = { $AsyncIterator: 'readonly', Iterator: 'readonly', AsyncIterator: 'readonly', + IntervalID: 'readonly', IteratorResult: 'readonly', JSONValue: 'readonly', JSResourceReference: 'readonly', + mixin$Animatable: 'readonly', MouseEventHandler: 'readonly', NavigateEvent: 'readonly', + Partial: 'readonly', + PerformanceMeasureOptions: 'readonly', PropagationPhases: 'readonly', PropertyDescriptor: 'readonly', - React$AbstractComponent: 'readonly', + PropertyDescriptorMap: 'readonly', + Proxy$traps: 'readonly', React$Component: 'readonly', - React$ComponentType: 'readonly', React$Config: 'readonly', React$Context: 'readonly', React$Element: 'readonly', @@ -608,22 +622,24 @@ module.exports = { symbol: 'readonly', SyntheticEvent: 'readonly', SyntheticMouseEvent: 'readonly', + SyntheticPointerEvent: 'readonly', Thenable: 'readonly', TimeoutID: 'readonly', WheelEventHandler: 'readonly', FinalizationRegistry: 'readonly', Exclude: 'readonly', Omit: 'readonly', + Pick: 'readonly', Keyframe: 'readonly', PropertyIndexedKeyframes: 'readonly', KeyframeAnimationOptions: 'readonly', GetAnimationsOptions: 'readonly', - Animatable: 'readonly', ScrollTimeline: 'readonly', EventListenerOptionsOrUseCapture: 'readonly', FocusOptions: 'readonly', OptionalEffectTiming: 'readonly', + __REACT_ROOT_PATH_TEST__: 'readonly', spyOnDev: 'readonly', spyOnDevAndProd: 'readonly', spyOnProd: 'readonly', diff --git a/.github/ISSUE_TEMPLATE/compiler_bug_report.yml b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml index 233201d3f5b1..a2c0e3d7aa38 100644 --- a/.github/ISSUE_TEMPLATE/compiler_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/compiler_bug_report.yml @@ -11,7 +11,7 @@ body: options: - label: React Compiler core (the JS output is incorrect, or your app works incorrectly after optimization) - label: babel-plugin-react-compiler (build issue installing or using the Babel plugin) - - label: eslint-plugin-react-compiler (build issue installing or using the eslint plugin) + - label: eslint-plugin-react-hooks (build issue installing or using the eslint plugin) - label: react-compiler-healthcheck (build issue installing or using the healthcheck script) - type: input attributes: diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index 34349f584ef2..a19e87e25e78 100644 --- a/.github/workflows/compiler_playground.yml +++ b/.github/workflows/compiler_playground.yml @@ -57,8 +57,6 @@ jobs: key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} - run: npx playwright install --with-deps chromium if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' - - run: npx playwright install-deps - if: steps.cache_playwright_browsers.outputs.cache-hit == 'true' - run: CI=true yarn test - run: ls -R test-results if: '!cancelled()' diff --git a/.github/workflows/compiler_prereleases.yml b/.github/workflows/compiler_prereleases.yml index bd6d003a4ccb..76cd3310b1a7 100644 --- a/.github/workflows/compiler_prereleases.yml +++ b/.github/workflows/compiler_prereleases.yml @@ -19,6 +19,9 @@ on: tag_version: required: false type: string + dry_run: + required: false + type: boolean secrets: NPM_TOKEN: required: true @@ -55,7 +58,13 @@ jobs: key: compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('compiler/yarn.lock') }} - run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' - - name: Publish packages to npm + - if: inputs.dry_run == true + name: Publish packages to npm (dry run) + run: | + cp ./scripts/release/ci-npmrc ~/.npmrc + scripts/release/publish.js --frfr --debug --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }} + - if: inputs.dry_run != true + name: Publish packages to npm run: | cp ./scripts/release/ci-npmrc ~/.npmrc scripts/release/publish.js --frfr --ci --versionName=${{ inputs.version_name }} --tag=${{ inputs.dist_tag }} ${{ inputs.tag_version && format('--tagVersion={0}', inputs.tag_version) || '' }} diff --git a/.github/workflows/compiler_prereleases_manual.yml b/.github/workflows/compiler_prereleases_manual.yml index 268b8f24f401..c4a7a16aca3b 100644 --- a/.github/workflows/compiler_prereleases_manual.yml +++ b/.github/workflows/compiler_prereleases_manual.yml @@ -17,6 +17,9 @@ on: tag_version: required: false type: string + dry_run: + required: false + type: boolean permissions: {} @@ -33,5 +36,6 @@ jobs: dist_tag: ${{ inputs.dist_tag }} version_name: ${{ inputs.version_name }} tag_version: ${{ inputs.tag_version }} + dry_run: ${{ inputs.dry_run }} secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/compiler_prereleases_nightly.yml b/.github/workflows/compiler_prereleases_nightly.yml index 07919d7843b2..ca2b5589def2 100644 --- a/.github/workflows/compiler_prereleases_nightly.yml +++ b/.github/workflows/compiler_prereleases_nightly.yml @@ -19,5 +19,6 @@ jobs: release_channel: experimental dist_tag: experimental version_name: '0.0.0' + dry_run: false secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/devtools_discord_notify.yml b/.github/workflows/devtools_discord_notify.yml new file mode 100644 index 000000000000..bb498f003710 --- /dev/null +++ b/.github/workflows/devtools_discord_notify.yml @@ -0,0 +1,49 @@ +name: (DevTools) Discord Notify + +on: + pull_request_target: + types: [opened, ready_for_review] + paths: + - packages/react-devtools** + - .github/workflows/devtools_**.yml + +permissions: {} + +jobs: + check_access: + if: ${{ github.event.pull_request.draft == false }} + runs-on: ubuntu-latest + outputs: + is_member_or_collaborator: ${{ steps.check_is_member_or_collaborator.outputs.is_member_or_collaborator }} + steps: + - run: echo ${{ github.event.pull_request.author_association }} + - name: Check is member or collaborator + id: check_is_member_or_collaborator + if: ${{ github.event.pull_request.author_association == 'MEMBER' || github.event.pull_request.author_association == 'COLLABORATOR' }} + run: echo "is_member_or_collaborator=true" >> "$GITHUB_OUTPUT" + + check_maintainer: + if: ${{ needs.check_access.outputs.is_member_or_collaborator == 'true' || needs.check_access.outputs.is_member_or_collaborator == true }} + needs: [check_access] + 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 }} + + notify: + if: ${{ needs.check_maintainer.outputs.is_core_team == 'true' }} + needs: check_maintainer + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DEVTOOLS_DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.pull_request.user.login }} + embed-author-url: ${{ github.event.pull_request.user.html_url }} + embed-author-icon-url: ${{ github.event.pull_request.user.avatar_url }} + embed-title: '#${{ github.event.number }} (+${{github.event.pull_request.additions}} -${{github.event.pull_request.deletions}}): ${{ github.event.pull_request.title }}' + embed-description: ${{ github.event.pull_request.body }} + embed-url: ${{ github.event.pull_request.html_url }} diff --git a/.github/workflows/devtools_regression_tests.yml b/.github/workflows/devtools_regression_tests.yml index 0b70cfaf4e9f..9fe0c55e0bd0 100644 --- a/.github/workflows/devtools_regression_tests.yml +++ b/.github/workflows/devtools_regression_tests.yml @@ -92,7 +92,7 @@ jobs: uses: actions/upload-artifact@v4 with: name: react-devtools - path: build/devtools.tgz + path: build/devtools if-no-files-found: error # Simplifies getting the extension for local testing - name: Archive chrome extension @@ -201,5 +201,5 @@ jobs: - uses: actions/upload-artifact@v4 with: name: screenshots - path: ./tmp/screenshots + path: ./tmp/playwright-artifacts if-no-files-found: warn diff --git a/.github/workflows/runtime_build_and_test.yml b/.github/workflows/runtime_build_and_test.yml index f0dbc069f082..09630c90a918 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -3,6 +3,10 @@ name: (Runtime) Build and Test on: push: branches: [main] + tags: + # To get CI for backport releases. + # This will duplicate CI for releases from main which is acceptable + - "v*" pull_request: paths-ignore: - compiler/** @@ -41,7 +45,7 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} lookup-only: true - uses: actions/setup-node@v4 if: steps.node_modules.outputs.cache-hit != 'true' @@ -55,10 +59,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' - name: Save cache @@ -67,7 +69,7 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} runtime_compiler_node_modules_cache: name: Cache Runtime, Compiler node_modules @@ -82,7 +84,7 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} lookup-only: true - uses: actions/setup-node@v4 if: steps.node_modules.outputs.cache-hit != 'true' @@ -98,10 +100,8 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} - restore-keys: | - runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-and-compiler-node_modules-v6- + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' - run: yarn --cwd compiler install --frozen-lockfile @@ -112,7 +112,7 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} # ----- FLOW ----- discover_flow_inline_configs: @@ -154,10 +154,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -184,17 +182,15 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' - run: | yarn generate-inline-fizz-runtime - git diff --quiet || (echo "There was a change to the Fizz runtime. Run `yarn generate-inline-fizz-runtime` and check in the result." && false) + git diff --exit-code || (echo "There was a change to the Fizz runtime. Run \`yarn generate-inline-fizz-runtime\` and check in the result." && false) # ----- FEATURE FLAGS ----- flags: @@ -216,7 +212,7 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -274,16 +270,15 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} - restore-keys: | - runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-and-compiler-node_modules-v6- + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' - run: yarn --cwd compiler install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' + - run: node --version - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }} # Hardcoded to improve parallelism @@ -306,7 +301,7 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} - name: Install runtime dependencies run: yarn install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' @@ -316,7 +311,7 @@ jobs: if: steps.node_modules.outputs.cache-hit != 'true' - run: ./scripts/react-compiler/build-compiler.sh && ./scripts/react-compiler/link-compiler.sh - run: yarn workspace eslint-plugin-react-hooks test - + # ----- BUILD ----- build_and_lint: name: yarn build and lint @@ -349,10 +344,8 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} - restore-keys: | - runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-and-compiler-node_modules-v6- + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -390,9 +383,6 @@ jobs: -r=experimental --env=development, -r=experimental --env=production, - # Dev Tools - --project=devtools -r=experimental, - # TODO: Update test config to support www build tests # - "-r=www-classic --env=development --variant=false" # - "-r=www-classic --env=production --variant=false" @@ -440,10 +430,8 @@ jobs: with: path: | **/node_modules - key: runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} - restore-keys: | - runtime-and-compiler-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-and-compiler-node_modules-v6- + key: runtime-and-compiler-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock', 'compiler/yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -458,8 +446,54 @@ jobs: merge-multiple: true - name: Display structure of build run: ls -R build + - run: node --version - run: yarn test --build ${{ matrix.test_params }} --shard=${{ matrix.shard }} --ci + test_build_devtools: + name: yarn test-build (devtools) + needs: [build_and_lint, runtime_node_modules_cache] + strategy: + fail-fast: false + matrix: + shard: + - 1/5 + - 2/5 + - 3/5 + - 4/5 + - 5/5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: yarn.lock + - name: Restore cached node_modules + uses: actions/cache/restore@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. + - name: Ensure clean build directory + run: rm -rf build + - run: yarn install --frozen-lockfile + if: steps.node_modules.outputs.cache-hit != 'true' + - name: Restore archived build + uses: actions/download-artifact@v4 + with: + pattern: _build_* + path: build + merge-multiple: true + - name: Display structure of build + run: ls -R build + - run: node --version + - run: yarn test --build --project=devtools -r=experimental --shard=${{ matrix.shard }} --ci + process_artifacts_combined: name: Process artifacts combined needs: [build_and_lint, runtime_node_modules_cache] @@ -483,10 +517,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -548,10 +580,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -567,7 +597,7 @@ jobs: - name: Search build artifacts for unminified errors run: | yarn extract-errors - git diff --quiet || (echo "Found unminified errors. Either update the error codes map or disable error minification for the affected build, if appropriate." && false) + git diff --exit-code || (echo "Found unminified errors. Either update the error codes map or disable error minification for the affected build, if appropriate." && false) check_release_dependencies: name: Check release dependencies @@ -588,10 +618,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -740,10 +768,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -766,6 +792,11 @@ jobs: name: react-devtools-${{ matrix.browser }}-extension path: build/devtools/${{ matrix.browser }}-extension.zip if-no-files-found: error + - name: Archive ${{ matrix.browser }} metadata + uses: actions/upload-artifact@v4 + with: + name: react-devtools-${{ matrix.browser }}-metadata + path: build/devtools/webpack-stats.*.json merge_devtools_artifacts: name: Merge DevTools artifacts @@ -776,7 +807,7 @@ jobs: uses: actions/upload-artifact/merge@v4 with: name: react-devtools - pattern: react-devtools-*-extension + pattern: react-devtools-* run_devtools_e2e_tests: name: Run DevTools e2e tests @@ -797,10 +828,8 @@ jobs: with: path: | **/node_modules - key: runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} - restore-keys: | - runtime-node_modules-v6-${{ runner.arch }}-${{ runner.os }}- - runtime-node_modules-v6- + key: runtime-node_modules-v8-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('yarn.lock') }} + # Don't use restore-keys here. Otherwise the cache grows indefinitely. - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -811,12 +840,27 @@ jobs: pattern: _build_* path: build merge-multiple: true - - run: | - npx playwright install - sudo npx playwright install-deps + - name: Check Playwright version + id: playwright_version + run: echo "playwright_version=$(npm ls @playwright/test | grep @playwright | sed 's/.*@//' | head -1)" >> "$GITHUB_OUTPUT" + - name: Cache Playwright Browsers for version ${{ steps.playwright_version.outputs.playwright_version }} + id: cache_playwright_browsers + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-browsers-v6-${{ runner.arch }}-${{ runner.os }}-${{ steps.playwright_version.outputs.playwright_version }} + - name: Playwright install deps + if: steps.cache_playwright_browsers.outputs.cache-hit != 'true' + run: npx playwright install --with-deps chromium - run: ./scripts/ci/run_devtools_e2e_tests.js env: RELEASE_CHANNEL: experimental + - name: Archive Playwright report + uses: actions/upload-artifact@v4 + with: + name: devtools-playwright-artifacts + path: tmp/playwright-artifacts + if-no-files-found: warn # ----- SIZEBOT ----- sizebot: diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index b982d561ed71..40fad235e804 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -116,11 +116,13 @@ jobs: run: | sed -i -e 's/ @license React*//' \ build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + build/facebook-www/ESLintPluginReactHooks-dev.modern.js \ build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js - name: Insert @headers into eslint plugin and react-refresh run: | sed -i -e 's/ LICENSE file in the root directory of this source tree./ LICENSE file in the root directory of this source tree.\n *\n * @noformat\n * @nolint\n * @lightSyntaxTransform\n * @preventMunge\n * @oncall react_core/' \ build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + build/facebook-www/ESLintPluginReactHooks-dev.modern.js \ build/oss-experimental/react-refresh/cjs/react-refresh-babel.development.js - name: Move relevant files for React in www into compiled run: | @@ -132,9 +134,9 @@ jobs: mkdir ./compiled/facebook-www/__test_utils__ mv build/__test_utils__/ReactAllWarnings.js ./compiled/facebook-www/__test_utils__/ReactAllWarnings.js - # Copy eslint-plugin-react-hooks + # Copy eslint-plugin-react-hooks (www build with feature flags) mkdir ./compiled/eslint-plugin-react-hooks - cp build/oss-experimental/eslint-plugin-react-hooks/cjs/eslint-plugin-react-hooks.development.js \ + cp ./compiled/facebook-www/ESLintPluginReactHooks-dev.modern.js \ ./compiled/eslint-plugin-react-hooks/index.js # Move unstable_server-external-runtime.js into facebook-www @@ -162,10 +164,9 @@ jobs: mv build/facebook-react-native/react-is/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-is/ mv build/facebook-react-native/react-test-renderer/cjs/ $BASE_FOLDER/RKJSModules/vendor/react/react-test-renderer/ - # Delete OSS renderer. OSS renderer is synced through internal script. + # Delete the OSS renderers, these are sync'd to RN separately. RENDERER_FOLDER=$BASE_FOLDER/react-native-github/Libraries/Renderer/implementations/ rm $RENDERER_FOLDER/ReactFabric-{dev,prod,profiling}.js - rm $RENDERER_FOLDER/ReactNativeRenderer-{dev,prod,profiling}.js # Copy eslint-plugin-react-hooks # NOTE: This is different from www, here we include the full package diff --git a/.github/workflows/runtime_discord_notify.yml b/.github/workflows/runtime_discord_notify.yml index 8d047e697640..ae9930adf114 100644 --- a/.github/workflows/runtime_discord_notify.yml +++ b/.github/workflows/runtime_discord_notify.yml @@ -4,8 +4,10 @@ on: pull_request_target: types: [opened, ready_for_review] paths-ignore: + - packages/react-devtools** - compiler/** - .github/workflows/compiler_**.yml + - .github/workflows/devtools**.yml permissions: {} diff --git a/.github/workflows/runtime_eslint_plugin_e2e.yml b/.github/workflows/runtime_eslint_plugin_e2e.yml index 92921646c1bc..bd6f0782066e 100644 --- a/.github/workflows/runtime_eslint_plugin_e2e.yml +++ b/.github/workflows/runtime_eslint_plugin_e2e.yml @@ -29,6 +29,7 @@ jobs: - "7" - "8" - "9" + - "10" steps: - uses: actions/checkout@v4 with: diff --git a/.github/workflows/runtime_prereleases.yml b/.github/workflows/runtime_prereleases.yml index ee340e079f3d..6559b1449971 100644 --- a/.github/workflows/runtime_prereleases.yml +++ b/.github/workflows/runtime_prereleases.yml @@ -82,7 +82,6 @@ jobs: run: | scripts/release/publish.js \ --ci \ - --skipTests \ --tags=${{ inputs.dist_tag }} \ --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} ${{ inputs.dry && '--dry' || '' }} @@ -91,11 +90,10 @@ jobs: run: | scripts/release/publish.js \ --ci \ - --skipTests \ --tags=${{ inputs.dist_tag }} \ --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}} ${{ inputs.dry && '--dry' || '' }} - - if: '${{ !(inputs.skip_packages && inputs.only_packages) }}' + - if: '${{ !inputs.skip_packages && !inputs.only_packages }}' name: 'Publish all packages' run: | scripts/release/publish.js \ diff --git a/.github/workflows/shared_close_direct_sync_branch_prs.yml b/.github/workflows/shared_close_direct_sync_branch_prs.yml index 01db0907401c..caa4da880b5f 100644 --- a/.github/workflows/shared_close_direct_sync_branch_prs.yml +++ b/.github/workflows/shared_close_direct_sync_branch_prs.yml @@ -18,6 +18,7 @@ jobs: permissions: # Used to create a review and close PRs pull-requests: write + contents: write steps: - name: Close PR uses: actions/github-script@v7 diff --git a/.github/workflows/shared_lint.yml b/.github/workflows/shared_lint.yml index 3c359cff2280..c778c7b2abe8 100644 --- a/.github/workflows/shared_lint.yml +++ b/.github/workflows/shared_lint.yml @@ -33,7 +33,7 @@ jobs: with: path: | **/node_modules - key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -56,7 +56,7 @@ jobs: with: path: | **/node_modules - key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -79,7 +79,7 @@ jobs: with: path: | **/node_modules - key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile @@ -102,7 +102,7 @@ jobs: with: path: | **/node_modules - key: shared-lint-node_modules-v6-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} + key: shared-lint-node_modules-v7-${{ runner.arch }}-${{ runner.os }}-${{ hashFiles('**/yarn.lock') }} - name: Ensure clean build directory run: rm -rf build - run: yarn install --frozen-lockfile diff --git a/.gitignore b/.gitignore index 6432df4f054d..16982164c421 100644 --- a/.gitignore +++ b/.gitignore @@ -21,8 +21,12 @@ chrome-user-data .idea *.iml .vscode +.zed *.swp *.swo +/tmp +/.worktrees +.claude/*.local.* packages/react-devtools-core/dist packages/react-devtools-extensions/chrome/build @@ -37,4 +41,3 @@ packages/react-devtools-fusebox/dist packages/react-devtools-inline/dist packages/react-devtools-shell/dist packages/react-devtools-timeline/dist - diff --git a/CHANGELOG.md b/CHANGELOG.md index a10cda01536b..5953fafc2786 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,93 @@ +## 19.2.1 (Dec 3, 2025) + +### React Server Components + +- Bring React Server Component fixes to Server Actions (@sebmarkbage [#35277](https://github.com/facebook/react/pull/35277)) + +## 19.2.0 (October 1st, 2025) + +Below is a list of all new features, APIs, and bug fixes. + +Read the [React 19.2 release post](https://react.dev/blog/2025/10/01/react-19-2) for more information. + +### New React Features + +- [``](https://react.dev/reference/react/Activity): A new API to hide and restore the UI and internal state of its children. +- [`useEffectEvent`](https://react.dev/reference/react/useEffectEvent) is a React Hook that lets you extract non-reactive logic into an [Effect Event](https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event). +- [`cacheSignal`](https://react.dev/reference/react/cacheSignal) (for RSCs) lets your know when the `cache()` lifetime is over. +- [React Performance tracks](https://react.dev/reference/dev-tools/react-performance-tracks) appear on the Performance panel’s timeline in your browser developer tools + +### New React DOM Features + +- Added resume APIs for partial pre-rendering with Web Streams: + - [`resume`](https://react.dev/reference/react-dom/server/resume): to resume a prerender to a stream. + - [`resumeAndPrerender`](https://react.dev/reference/react-dom/static/resumeAndPrerender): to resume a prerender to HTML. +- Added resume APIs for partial pre-rendering with Node Streams: + - [`resumeToPipeableStream`](https://react.dev/reference/react-dom/server/resumeToPipeableStream): to resume a prerender to a stream. + - [`resumeAndPrerenderToNodeStream`](https://react.dev/reference/react-dom/static/resumeAndPrerenderToNodeStream): to resume a prerender to HTML. +- Updated [`prerender`](https://react.dev/reference/react-dom/static/prerender) APIs to return a `postponed` state that can be passed to the `resume` APIs. + +### Notable changes + +- React DOM now batches suspense boundary reveals, matching the behavior of client side rendering. This change is especially noticeable when animating the reveal of Suspense boundaries e.g. with the upcoming `` Component. React will batch as much reveals as possible before the first paint while trying to hit popular first-contentful paint metrics. +- Add Node Web Streams (`prerender`, `renderToReadableStream`) to server-side-rendering APIs for Node.js +- Use underscore instead of `:` IDs generated by useId + +### All Changes + +#### React + +- `` was developed over many years, starting before `ClassComponent.setState` (@acdlite @sebmarkbage and many others) +- Stringify context as "SomeContext" instead of "SomeContext.Provider" (@kassens [#33507](https://github.com/facebook/react/pull/33507)) +- Include stack of cause of React instrumentation errors with `%o` placeholder (@eps1lon [#34198](https://github.com/facebook/react/pull/34198)) +- Fix infinite `useDeferredValue` loop in popstate event (@acdlite [#32821](https://github.com/facebook/react/pull/32821)) +- Fix a bug when an initial value was passed to `useDeferredValue` (@acdlite [#34376](https://github.com/facebook/react/pull/34376)) +- Fix a crash when submitting forms with Client Actions (@sebmarkbage [#33055](https://github.com/facebook/react/pull/33055)) +- Hide/unhide the content of dehydrated suspense boundaries if they resuspend (@sebmarkbage [#32900](https://github.com/facebook/react/pull/32900)) +- Avoid stack overflow on wide trees during Hot Reload (@sophiebits [#34145](https://github.com/facebook/react/pull/34145)) +- Improve Owner and Component stacks in various places (@sebmarkbage, @eps1lon: [#33629](https://github.com/facebook/react/pull/33629), [#33724](https://github.com/facebook/react/pull/33724), [#32735](https://github.com/facebook/react/pull/32735), [#33723](https://github.com/facebook/react/pull/33723)) +- Add `cacheSignal` (@sebmarkbage [#33557](https://github.com/facebook/react/pull/33557)) + +#### React DOM + +- Block on Suspensey Fonts during reveal of server-side-rendered content (@sebmarkbage [#33342](https://github.com/facebook/react/pull/33342)) +- Use underscore instead of `:` for IDs generated by `useId` (@sebmarkbage, @eps1lon: [#32001](https://github.com/facebook/react/pull/32001), [https://github.com/facebook/react/pull/33342](https://github.com/facebook/react/pull/33342)[#33099](https://github.com/facebook/react/pull/33099), [#33422](https://github.com/facebook/react/pull/33422)) +- Stop warning when ARIA 1.3 attributes are used (@Abdul-Omira [#34264](https://github.com/facebook/react/pull/34264)) +- Allow `nonce` to be used on hoistable styles (@Andarist [#32461](https://github.com/facebook/react/pull/32461)) +- Warn for using a React owned node as a Container if it also has text content (@sebmarkbage [#32774](https://github.com/facebook/react/pull/32774)) +- s/HTML/text for for error messages if text hydration mismatches (@rickhanlonii [#32763](https://github.com/facebook/react/pull/32763)) +- Fix a bug with `React.use` inside `React.lazy`\-ed Component (@hi-ogawa [#33941](https://github.com/facebook/react/pull/33941)) +- Enable the `progressiveChunkSize` option for server-side-rendering APIs (@sebmarkbage [#33027](https://github.com/facebook/react/pull/33027)) +- Fix a bug with deeply nested Suspense inside Suspense fallback when server-side-rendering (@gnoff [#33467](https://github.com/facebook/react/pull/33467)) +- Avoid hanging when suspending after aborting while rendering (@gnoff [#34192](https://github.com/facebook/react/pull/34192)) +- Add Node Web Streams to server-side-rendering APIs for Node.js (@sebmarkbage [#33475](https://github.com/facebook/react/pull/33475)) + +#### React Server Components + +- Preload `` and `` using hints before they're rendered (@sebmarkbage [#34604](https://github.com/facebook/react/pull/34604)) +- Log error if production elements are rendered during development (@eps1lon [#34189](https://github.com/facebook/react/pull/34189)) +- Fix a bug when returning a Temporary reference (e.g. a Client Reference) from Server Functions (@sebmarkbage [#34084](https://github.com/facebook/react/pull/34084), @denk0403 [#33761](https://github.com/facebook/react/pull/33761)) +- Pass line/column to `filterStackFrame` (@eps1lon [#33707](https://github.com/facebook/react/pull/33707)) +- Support Async Modules in Turbopack Server References (@lubieowoce [#34531](https://github.com/facebook/react/pull/34531)) +- Add support for .mjs file extension in Webpack (@jennyscript [#33028](https://github.com/facebook/react/pull/33028)) +- Fix a wrong missing key warning (@unstubbable [#34350](https://github.com/facebook/react/pull/34350)) +- Make console log resolve in predictable order (@sebmarkbage [#33665](https://github.com/facebook/react/pull/33665)) + +#### React Reconciler + +- [createContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L255-L261) and [createHydrationContainer](https://github.com/facebook/react/blob/v19.2.0/packages/react-reconciler/src/ReactFiberReconciler.js#L305-L312) had their parameter order adjusted after `on*` handlers to account for upcoming experimental APIs + +## 19.1.2 (Dec 3, 2025) + +### React Server Components + +- Bring React Server Component fixes to Server Actions (@sebmarkbage [#35277](https://github.com/facebook/react/pull/35277)) + +## 19.1.1 (July 28, 2025) + +### React +* Fixed Owner Stacks to work with ES2015 function.name semantics ([#33680](https://github.com/facebook/react/pull/33680) by @hoxyq) + ## 19.1.0 (March 28, 2025) ### Owner Stack @@ -45,6 +135,12 @@ An Owner Stack is a string representing the components that are directly respons * Exposed `registerServerReference` in client builds to handle server references in different environments. [#32534](https://github.com/facebook/react/pull/32534) * Added react-server-dom-parcel package which integrates Server Components with the [Parcel bundler](https://parceljs.org/) [#31725](https://github.com/facebook/react/pull/31725), [#32132](https://github.com/facebook/react/pull/32132), [#31799](https://github.com/facebook/react/pull/31799), [#32294](https://github.com/facebook/react/pull/32294), [#31741](https://github.com/facebook/react/pull/31741) +## 19.0.1 (Dec 3, 2025) + +### React Server Components + +- Bring React Server Component fixes to Server Actions (@sebmarkbage [#35277](https://github.com/facebook/react/pull/35277)) + ## 19.0.0 (December 5, 2024) Below is a list of all new features, APIs, deprecations, and breaking changes. Read [React 19 release post](https://react.dev/blog/2024/04/25/react-19) and [React 19 upgrade guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) for more information. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000000..81f9b4217235 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,8 @@ +# React + +React is a JavaScript library for building user interfaces. + +## Monorepo Overview + +- **React**: All files outside `/compiler/` +- **React Compiler**: `/compiler/` directory (has its own instructions) diff --git a/MAINTAINERS b/MAINTAINERS index 5ad514035dd5..e48736bc1ca4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,5 +1,6 @@ acdlite eps1lon +EugeneChoi4 gaearon gnoff unstubbable diff --git a/ReactVersions.js b/ReactVersions.js index 79e23e1d4b10..a486ccf2d91e 100644 --- a/ReactVersions.js +++ b/ReactVersions.js @@ -7,18 +7,18 @@ // // The @latest channel uses the version as-is, e.g.: // -// 19.1.0 +// 19.3.0 // // The @canary channel appends additional information, with the scheme // -