diff --git a/.codesandbox/ci.json b/.codesandbox/ci.json index f644328ad927e..2164efec0c8fa 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 c30542a3f7e2c..fd9cc6bdca2fe 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 49846c1f5e9bc..9d142d359afc3 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -468,13 +468,14 @@ module.exports = { files: ['packages/react-server-dom-webpack/**/*.js'], globals: { __webpack_chunk_load__: 'readonly', + __webpack_get_script_filename__: 'readonly', __webpack_require__: 'readonly', }, }, { files: ['packages/react-server-dom-turbopack/**/*.js'], globals: { - __turbopack_load__: 'readonly', + __turbopack_load_by_url__: 'readonly', __turbopack_require__: 'readonly', }, }, @@ -496,6 +497,7 @@ module.exports = { 'packages/react-devtools-shared/src/devtools/views/**/*.js', 'packages/react-devtools-shared/src/hook.js', 'packages/react-devtools-shared/src/backend/console.js', + 'packages/react-devtools-shared/src/backend/fiber/renderer.js', 'packages/react-devtools-shared/src/backend/shared/DevToolsComponentStackFrame.js', 'packages/react-devtools-shared/src/frontend/utils/withPermissionsCheck.js', ], @@ -504,6 +506,7 @@ module.exports = { __IS_FIREFOX__: 'readonly', __IS_EDGE__: 'readonly', __IS_NATIVE__: 'readonly', + __IS_INTERNAL_MCP_BUILD__: 'readonly', __IS_INTERNAL_VERSION__: 'readonly', chrome: 'readonly', }, @@ -514,6 +517,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'], @@ -544,13 +555,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', @@ -559,11 +567,13 @@ module.exports = { ConsoleTask: 'readonly', // TOOD: Figure out what the official name of this will be. ReturnType: 'readonly', AnimationFrameID: 'readonly', + WeakRef: 'readonly', // For Flow type annotation. Only `BigInt` is valid at runtime. bigint: 'readonly', BigInt: 'readonly', BigInt64Array: 'readonly', BigUint64Array: 'readonly', + CacheType: 'readonly', Class: 'readonly', ClientRect: 'readonly', CopyInspectedElementPath: 'readonly', @@ -575,15 +585,19 @@ module.exports = { $AsyncIterator: 'readonly', Iterator: 'readonly', AsyncIterator: 'readonly', + IntervalID: 'readonly', IteratorResult: 'readonly', JSONValue: 'readonly', JSResourceReference: 'readonly', + mixin$Animatable: 'readonly', MouseEventHandler: 'readonly', + NavigateEvent: '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', @@ -604,19 +618,21 @@ module.exports = { symbol: 'readonly', SyntheticEvent: 'readonly', SyntheticMouseEvent: 'readonly', + SyntheticPointerEvent: 'readonly', Thenable: 'readonly', TimeoutID: 'readonly', WheelEventHandler: 'readonly', FinalizationRegistry: 'readonly', + Exclude: 'readonly', Omit: 'readonly', Keyframe: 'readonly', PropertyIndexedKeyframes: 'readonly', KeyframeAnimationOptions: 'readonly', GetAnimationsOptions: 'readonly', - Animatable: 'readonly', ScrollTimeline: 'readonly', EventListenerOptionsOrUseCapture: 'readonly', FocusOptions: 'readonly', + OptionalEffectTiming: 'readonly', spyOnDev: 'readonly', spyOnDevAndProd: 'readonly', @@ -634,5 +650,6 @@ module.exports = { AsyncLocalStorage: 'readonly', async_hooks: 'readonly', globalThis: 'readonly', + navigation: 'readonly', }, }; diff --git a/.github/workflows/compiler_discord_notify.yml b/.github/workflows/compiler_discord_notify.yml index 71aea56e8492f..5a57cf6a32c19 100644 --- a/.github/workflows/compiler_discord_notify.yml +++ b/.github/workflows/compiler_discord_notify.yml @@ -11,10 +11,12 @@ 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' }} diff --git a/.github/workflows/compiler_playground.yml b/.github/workflows/compiler_playground.yml index 34349f584ef26..a19e87e25e78e 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/devtools_discord_notify.yml b/.github/workflows/devtools_discord_notify.yml new file mode 100644 index 0000000000000..bb498f0037104 --- /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 0b70cfaf4e9ff..9fe0c55e0bd00 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 1d0a896984e26..ce11f76530243 100644 --- a/.github/workflows/runtime_build_and_test.yml +++ b/.github/workflows/runtime_build_and_test.yml @@ -6,6 +6,12 @@ on: pull_request: paths-ignore: - compiler/** + workflow_dispatch: + inputs: + commit_sha: + required: false + type: string + default: '' permissions: {} @@ -28,7 +34,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} - name: Check cache hit uses: actions/cache/restore@v4 id: node_modules @@ -69,7 +75,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} - name: Check cache hit uses: actions/cache/restore@v4 id: node_modules @@ -117,7 +123,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + ref: ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} - uses: actions/github-script@v7 id: set-matrix with: @@ -136,7 +142,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -166,7 +172,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -188,7 +194,7 @@ jobs: 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: @@ -198,7 +204,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -254,7 +260,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -280,6 +286,37 @@ jobs: if: steps.node_modules.outputs.cache-hit != 'true' - run: yarn test ${{ matrix.params }} --ci --shard=${{ matrix.shard }} + # Hardcoded to improve parallelism + test-linter: + name: Test eslint-plugin-react-hooks + needs: [runtime_compiler_node_modules_cache] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version-file: '.nvmrc' + cache: yarn + cache-dependency-path: | + yarn.lock + compiler/yarn.lock + - name: Restore cached node_modules + uses: actions/cache@v4 + id: node_modules + with: + path: | + **/node_modules + key: runtime-and-compiler-node_modules-v6-${{ 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' + - name: Install compiler dependencies + run: yarn install --frozen-lockfile + working-directory: compiler + 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 @@ -294,7 +331,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -389,7 +426,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -434,7 +471,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -462,7 +499,7 @@ jobs: merge-multiple: true - name: Display structure of build run: ls -R build - - run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA + - run: echo ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA - name: Scrape warning messages run: | mkdir -p ./build/__test_utils__ @@ -499,7 +536,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -530,7 +567,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 @@ -539,7 +576,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -576,7 +613,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -617,7 +654,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -691,7 +728,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -729,6 +766,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 @@ -739,7 +781,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 @@ -748,7 +790,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -774,12 +816,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: @@ -793,7 +850,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} + 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' @@ -842,7 +899,7 @@ jobs: node ./scripts/print-warnings/print-warnings.js > build/__test_utils__/ReactAllWarnings.js - name: Display structure of build for PR run: ls -R build - - run: echo ${{ github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA + - run: echo ${{ github.event.inputs.commit_sha != '' && github.event.inputs.commit_sha || github.event.pull_request.head.sha || github.sha }} >> build/COMMIT_SHA - run: node ./scripts/tasks/danger - name: Archive sizebot results uses: actions/upload-artifact@v4 diff --git a/.github/workflows/runtime_commit_artifacts.yml b/.github/workflows/runtime_commit_artifacts.yml index ab0e71b83cfc7..b982d561ed71c 100644 --- a/.github/workflows/runtime_commit_artifacts.yml +++ b/.github/workflows/runtime_commit_artifacts.yml @@ -332,10 +332,10 @@ jobs: git --no-pager diff -U0 --cached | grep '^[+-]' | head -n 100 echo "====================" # Ignore REVISION or lines removing @generated headers. - if git diff --cached ':(exclude)*REVISION' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" > /dev/null; then + if git diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" > /dev/null; then echo "Changes detected" echo "===== Changes =====" - git --no-pager diff --cached ':(exclude)*REVISION' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" | head -n 50 + git --no-pager diff --cached ':(exclude)*REVISION' ':(exclude)*/eslint-plugin-react-hooks/package.json' | grep -vE "^(@@|diff|index|\-\-\-|\+\+\+|\- \* @generated SignedSource)" | grep "^[+-]" | head -n 50 echo "===================" echo "should_commit=true" >> "$GITHUB_OUTPUT" else diff --git a/.github/workflows/runtime_discord_notify.yml b/.github/workflows/runtime_discord_notify.yml index 44775fbe78880..ae9930adf114f 100644 --- a/.github/workflows/runtime_discord_notify.yml +++ b/.github/workflows/runtime_discord_notify.yml @@ -4,17 +4,21 @@ on: pull_request_target: types: [opened, ready_for_review] paths-ignore: + - packages/react-devtools** - compiler/** - .github/workflows/compiler_**.yml + - .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' }} diff --git a/.github/workflows/runtime_prereleases.yml b/.github/workflows/runtime_prereleases.yml index ee8dd72ce9665..6559b1449971a 100644 --- a/.github/workflows/runtime_prereleases.yml +++ b/.github/workflows/runtime_prereleases.yml @@ -17,6 +17,17 @@ on: description: 'Whether to notify the team on Discord when the release fails. Useful if this workflow is called from an automation.' required: false type: boolean + only_packages: + description: Packages to publish (space separated) + type: string + skip_packages: + description: Packages to NOT publish (space separated) + type: string + dry: + required: true + description: Dry run instead of publish? + type: boolean + default: true secrets: DISCORD_WEBHOOK_URL: description: 'Discord webhook URL to notify on failure. Only required if enableFailureNotification is true.' @@ -61,15 +72,39 @@ jobs: if: steps.node_modules.outputs.cache-hit != 'true' - run: yarn --cwd scripts/release install --frozen-lockfile if: steps.node_modules.outputs.cache-hit != 'true' + - run: cp ./scripts/release/ci-npmrc ~/.npmrc - run: | GH_TOKEN=${{ secrets.GH_TOKEN }} scripts/release/prepare-release-from-ci.js --skipTests -r ${{ inputs.release_channel }} --commit=${{ inputs.commit_sha }} - cp ./scripts/release/ci-npmrc ~/.npmrc - scripts/release/publish.js --ci --tags ${{ inputs.dist_tag }} + - name: Check prepared files + run: ls -R build/node_modules + - if: '${{ inputs.only_packages }}' + name: 'Publish ${{ inputs.only_packages }}' + run: | + scripts/release/publish.js \ + --ci \ + --tags=${{ inputs.dist_tag }} \ + --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} + ${{ inputs.dry && '--dry' || '' }} + - if: '${{ inputs.skip_packages }}' + name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}' + run: | + scripts/release/publish.js \ + --ci \ + --tags=${{ inputs.dist_tag }} \ + --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}} + ${{ inputs.dry && '--dry' || '' }} + - if: '${{ !inputs.skip_packages && !inputs.only_packages }}' + name: 'Publish all packages' + run: | + scripts/release/publish.js \ + --ci \ + --tags=${{ inputs.dist_tag }} ${{ (inputs.dry && '') || '\'}} + ${{ inputs.dry && '--dry' || '' }} - name: Notify Discord on failure if: failure() && inputs.enableFailureNotification == true uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 with: webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} embed-author-name: "GitHub Actions" - embed-title: 'Publish of $${{ inputs.release_channel }} release failed' + embed-title: '[Runtime] Publish of ${{ inputs.release_channel }}@${{ inputs.dist_tag}} release failed' embed-url: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}/attempts/${{ github.run_attempt }} diff --git a/.github/workflows/runtime_prereleases_manual.yml b/.github/workflows/runtime_prereleases_manual.yml index 71e25ba073a83..407d931e90738 100644 --- a/.github/workflows/runtime_prereleases_manual.yml +++ b/.github/workflows/runtime_prereleases_manual.yml @@ -5,6 +5,25 @@ on: inputs: prerelease_commit_sha: required: true + only_packages: + description: Packages to publish (space separated) + type: string + skip_packages: + description: Packages to NOT publish (space separated) + type: string + dry: + required: true + description: Dry run instead of publish? + type: boolean + default: true + experimental_only: + type: boolean + description: Only publish to the experimental tag + default: false + force_notify: + description: Force a Discord notification? + type: boolean + default: false permissions: {} @@ -12,8 +31,26 @@ env: TZ: /usr/share/zoneinfo/America/Los_Angeles jobs: + notify: + if: ${{ inputs.force_notify || inputs.dry == false || inputs.dry == 'false' }} + runs-on: ubuntu-latest + steps: + - name: Discord Webhook Action + uses: tsickert/discord-webhook@86dc739f3f165f16dadc5666051c367efa1692f4 + with: + webhook-url: ${{ secrets.DISCORD_WEBHOOK_URL }} + embed-author-name: ${{ github.event.sender.login }} + embed-author-url: ${{ github.event.sender.html_url }} + embed-author-icon-url: ${{ github.event.sender.avatar_url }} + embed-title: "⚠️ Publishing ${{ inputs.experimental_only && 'EXPERIMENTAL' || 'CANARY & EXPERIMENTAL' }} release ${{ (inputs.dry && ' (dry run)') || '' }}" + embed-description: | + ```json + ${{ toJson(inputs) }} + ``` + embed-url: https://github.com/facebook/react/actions/runs/${{ github.run_id }} publish_prerelease_canary: + if: ${{ !inputs.experimental_only }} name: Publish to Canary channel uses: facebook/react/.github/workflows/runtime_prereleases.yml@main permissions: @@ -33,6 +70,9 @@ jobs: # downstream consumers might still expect that tag. We can remove this # after some time has elapsed and the change has been communicated. dist_tag: canary,next + only_packages: ${{ inputs.only_packages }} + skip_packages: ${{ inputs.skip_packages }} + dry: ${{ inputs.dry }} secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -48,10 +88,15 @@ jobs: # different versions of the same package, even if they use different # dist tags. needs: publish_prerelease_canary + # Ensures the job runs even if canary is skipped + if: always() with: commit_sha: ${{ inputs.prerelease_commit_sha }} release_channel: experimental dist_tag: experimental + only_packages: ${{ inputs.only_packages }} + skip_packages: ${{ inputs.skip_packages }} + dry: ${{ inputs.dry }} secrets: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/runtime_prereleases_nightly.yml b/.github/workflows/runtime_prereleases_nightly.yml index a38e241d53996..f13a92e46f401 100644 --- a/.github/workflows/runtime_prereleases_nightly.yml +++ b/.github/workflows/runtime_prereleases_nightly.yml @@ -22,6 +22,7 @@ jobs: release_channel: stable dist_tag: canary,next enableFailureNotification: true + dry: false secrets: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} @@ -43,6 +44,7 @@ jobs: release_channel: experimental dist_tag: experimental enableFailureNotification: true + dry: false secrets: DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/runtime_releases_from_npm_manual.yml b/.github/workflows/runtime_releases_from_npm_manual.yml index 51e38439553de..f164e9f080660 100644 --- a/.github/workflows/runtime_releases_from_npm_manual.yml +++ b/.github/workflows/runtime_releases_from_npm_manual.yml @@ -110,7 +110,7 @@ jobs: --tags=${{ inputs.tags }} \ --publishVersion=${{ inputs.version_to_publish }} \ --onlyPackages=${{ inputs.only_packages }} ${{ (inputs.dry && '') || '\'}} - ${{ inputs.dry && '--dry'}} + ${{ inputs.dry && '--dry' || '' }} - if: '${{ inputs.skip_packages }}' name: 'Publish all packages EXCEPT ${{ inputs.skip_packages }}' run: | @@ -119,7 +119,7 @@ jobs: --tags=${{ inputs.tags }} \ --publishVersion=${{ inputs.version_to_publish }} \ --skipPackages=${{ inputs.skip_packages }} ${{ (inputs.dry && '') || '\'}} - ${{ inputs.dry && '--dry'}} + ${{ inputs.dry && '--dry' || '' }} - name: Archive released package for debugging uses: actions/upload-artifact@v4 with: diff --git a/.github/workflows/shared_close_direct_sync_branch_prs.yml b/.github/workflows/shared_close_direct_sync_branch_prs.yml index 01db0907401c0..caa4da880b5ff 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_label_core_team_prs.yml b/.github/workflows/shared_label_core_team_prs.yml index fd4aa9399e386..cc10e87dcc2cf 100644 --- a/.github/workflows/shared_label_core_team_prs.yml +++ b/.github/workflows/shared_label_core_team_prs.yml @@ -17,6 +17,7 @@ jobs: 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' }} diff --git a/.github/workflows/shared_stale.yml b/.github/workflows/shared_stale.yml index a2c707973c927..c24895edc5da7 100644 --- a/.github/workflows/shared_stale.yml +++ b/.github/workflows/shared_stale.yml @@ -6,7 +6,10 @@ on: - cron: '0 * * * *' workflow_dispatch: -permissions: {} +permissions: + # https://github.com/actions/stale/tree/v9/?tab=readme-ov-file#recommended-permissions + issues: write + pull-requests: write env: TZ: /usr/share/zoneinfo/America/Los_Angeles diff --git a/.gitignore b/.gitignore index 6432df4f054d8..d2aefb620263b 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ chrome-user-data .vscode *.swp *.swo +/tmp packages/react-devtools-core/dist packages/react-devtools-extensions/chrome/build diff --git a/.prettierrc.js b/.prettierrc.js index 37cf9c9d3a89b..aa54cbae1f9f8 100644 --- a/.prettierrc.js +++ b/.prettierrc.js @@ -3,13 +3,12 @@ const {esNextPaths} = require('./scripts/shared/pathsByLanguageVersion'); module.exports = { - plugins: ['prettier-plugin-hermes-parser'], bracketSpacing: false, singleQuote: true, bracketSameLine: true, trailingComma: 'es5', printWidth: 80, - parser: 'hermes', + parser: 'flow', arrowParens: 'avoid', overrides: [ { diff --git a/CHANGELOG.md b/CHANGELOG.md index d5551df26c7de..21704e3e29f64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,81 @@ +## 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/developer-tooling/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.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 @@ -19,11 +97,11 @@ An Owner Stack is a string representing the components that are directly respons * Updated `useId` to use valid CSS selectors, changing format from `:r123:` to `«r123»`. [#32001](https://github.com/facebook/react/pull/32001) * Added a dev-only warning for null/undefined created in useEffect, useInsertionEffect, and useLayoutEffect. [#32355](https://github.com/facebook/react/pull/32355) * Fixed a bug where dev-only methods were exported in production builds. React.act is no longer available in production builds. [#32200](https://github.com/facebook/react/pull/32200) -* Improved consistency across prod and dev to improve compatibility with Google Closure Complier and bindings [#31808](https://github.com/facebook/react/pull/31808) +* Improved consistency across prod and dev to improve compatibility with Google Closure Compiler and bindings [#31808](https://github.com/facebook/react/pull/31808) * Improve passive effect scheduling for consistent task yielding. [#31785](https://github.com/facebook/react/pull/31785) * Fixed asserts in React Native when passChildrenWhenCloningPersistedNodes is enabled for OffscreenComponent rendering. [#32528](https://github.com/facebook/react/pull/32528) * Fixed component name resolution for Portal [#32640](https://github.com/facebook/react/pull/32640) -* Added support for beforetoggle and toggle events on the dialog element. #32479 [#32479](https://github.com/facebook/react/pull/32479) +* Added support for beforetoggle and toggle events on the dialog element. [#32479](https://github.com/facebook/react/pull/32479) ### React DOM * Fixed double warning when the `href` attribute is an empty string [#31783](https://github.com/facebook/react/pull/31783) diff --git a/MAINTAINERS b/MAINTAINERS index 5ad514035dd53..e48736bc1ca41 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1,5 +1,6 @@ acdlite eps1lon +EugeneChoi4 gaearon gnoff unstubbable diff --git a/README.md b/README.md index 88f8e827b0255..8b137891791fe 100644 --- a/README.md +++ b/README.md @@ -1,78 +1 @@ -# [React](https://react.dev/) · [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/facebook/react/blob/main/LICENSE) [![npm version](https://img.shields.io/npm/v/react.svg?style=flat)](https://www.npmjs.com/package/react) [![(Runtime) Build and Test](https://github.com/facebook/react/actions/workflows/runtime_build_and_test.yml/badge.svg)](https://github.com/facebook/react/actions/workflows/runtime_build_and_test.yml) [![(Compiler) TypeScript](https://github.com/facebook/react/actions/workflows/compiler_typescript.yml/badge.svg?branch=main)](https://github.com/facebook/react/actions/workflows/compiler_typescript.yml) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://legacy.reactjs.org/docs/how-to-contribute.html#your-first-pull-request) -React is a JavaScript library for building user interfaces. - -* **Declarative:** React makes it painless to create interactive UIs. Design simple views for each state in your application, and React will efficiently update and render just the right components when your data changes. Declarative views make your code more predictable, simpler to understand, and easier to debug. -* **Component-Based:** Build encapsulated components that manage their own state, then compose them to make complex UIs. Since component logic is written in JavaScript instead of templates, you can easily pass rich data through your app and keep the state out of the DOM. -* **Learn Once, Write Anywhere:** We don't make assumptions about the rest of your technology stack, so you can develop new features in React without rewriting existing code. React can also render on the server using [Node](https://nodejs.org/en) and power mobile apps using [React Native](https://reactnative.dev/). - -[Learn how to use React in your project](https://react.dev/learn). - -## Installation - -React has been designed for gradual adoption from the start, and **you can use as little or as much React as you need**: - -* Use [Quick Start](https://react.dev/learn) to get a taste of React. -* [Add React to an Existing Project](https://react.dev/learn/add-react-to-an-existing-project) to use as little or as much React as you need. -* [Create a New React App](https://react.dev/learn/start-a-new-react-project) if you're looking for a powerful JavaScript toolchain. - -## Documentation - -You can find the React documentation [on the website](https://react.dev/). - -Check out the [Getting Started](https://react.dev/learn) page for a quick overview. - -The documentation is divided into several sections: - -* [Quick Start](https://react.dev/learn) -* [Tutorial](https://react.dev/learn/tutorial-tic-tac-toe) -* [Thinking in React](https://react.dev/learn/thinking-in-react) -* [Installation](https://react.dev/learn/installation) -* [Describing the UI](https://react.dev/learn/describing-the-ui) -* [Adding Interactivity](https://react.dev/learn/adding-interactivity) -* [Managing State](https://react.dev/learn/managing-state) -* [Advanced Guides](https://react.dev/learn/escape-hatches) -* [API Reference](https://react.dev/reference/react) -* [Where to Get Support](https://react.dev/community) -* [Contributing Guide](https://legacy.reactjs.org/docs/how-to-contribute.html) - -You can improve it by sending pull requests to [this repository](https://github.com/reactjs/react.dev). - -## Examples - -We have several examples [on the website](https://react.dev/). Here is the first one to get you started: - -```jsx -import { createRoot } from 'react-dom/client'; - -function HelloMessage({ name }) { - return
Hello {name}
; -} - -const root = createRoot(document.getElementById('container')); -root.render(); -``` - -This example will render "Hello Taylor" into a container on the page. - -You'll notice that we used an HTML-like syntax; [we call it JSX](https://react.dev/learn#writing-markup-with-jsx). JSX is not required to use React, but it makes code more readable, and writing it feels like writing HTML. - -## Contributing - -The main purpose of this repository is to continue evolving React core, making it faster and easier to use. Development of React happens in the open on GitHub, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React. - -### [Code of Conduct](https://code.fb.com/codeofconduct) - -Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read [the full text](https://code.fb.com/codeofconduct) so that you can understand what actions will and will not be tolerated. - -### [Contributing Guide](https://legacy.reactjs.org/docs/how-to-contribute.html) - -Read our [contributing guide](https://legacy.reactjs.org/docs/how-to-contribute.html) to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React. - -### [Good First Issues](https://github.com/facebook/react/labels/good%20first%20issue) - -To help you get your feet wet and get you familiar with our contribution process, we have a list of [good first issues](https://github.com/facebook/react/labels/good%20first%20issue) that contain bugs that have a relatively limited scope. This is a great place to get started. - -### License - -React is [MIT licensed](./LICENSE). diff --git a/ReactVersions.js b/ReactVersions.js index 79e23e1d4b109..c657857cbbc82 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 // -