diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index b7d1d535158..9a0e68f0920 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -183,13 +183,10 @@ jobs: build_task: build-native-release os: mac: + host: "['macos-15']" vendor: apple sys: darwin - arch: - x86_64: - host: "['macos-15-intel']" - aarch64: - host: "['macos-15']" + arch: [x86_64, aarch64] windows: host: "['windows-latest-8-core-oss']" vendor: pc @@ -226,7 +223,7 @@ jobs: name: stable - ${{ matrix.target }} - node@20 runs-on: ${{ fromJSON(matrix.host) }} - timeout-minutes: ${{ matrix.os == 'mac' && 90 || 45 }} + timeout-minutes: 45 env: # Disable all build caches for production/staging/force-preview deploys NEXT_SKIP_BUILD_CACHE: ${{ contains(fromJSON('["production","staging","force-preview"]'), needs.deploy-target.outputs.value) && '1' || '' }} diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index ef7a99dcbf1..2d9047e437d 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -238,6 +238,7 @@ jobs: needsRust: 'yes' needsNextest: 'yes' skipNativeBuild: 'yes' + skipInstallBuild: 'yes' afterBuild: pnpm dlx turbo@${TURBO_VERSION} run test-cargo-unit ${TURBO_ARGS} stepName: 'test-cargo-unit' secrets: inherit diff --git a/.github/workflows/build_reusable.yml b/.github/workflows/build_reusable.yml index bbd669af0d1..082150a3268 100644 --- a/.github/workflows/build_reusable.yml +++ b/.github/workflows/build_reusable.yml @@ -309,7 +309,7 @@ jobs: if: ${{ inputs.skipInstallBuild != 'yes' }} - run: pnpm install - if: ${{ inputs.skipInstallBuild != 'yes' }} + if: ${{ inputs.skipInstallBuild != 'yes' || inputs.needsNextest == 'yes' }} - name: Install node-file-trace test dependencies if: ${{ inputs.needsNextest == 'yes' }} diff --git a/Cargo.lock b/Cargo.lock index d125d53dbd5..47f06d42eaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2007,19 +2007,20 @@ dependencies = [ [[package]] name = "ctor" -version = "0.8.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" +checksum = "83cf0d42651b16c6dfe68685716d18480d18a9c39c62d76e8cf3eb6ed5d8bcbf" dependencies = [ "ctor-proc-macro", "dtor", + "link-section", ] [[package]] name = "ctor-proc-macro" -version = "0.0.7" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1" +checksum = "7a949c44fcacbbbb7ada007dc7acb34603dd97cd47de5d054f2b6493ecebb483" [[package]] name = "ctrlc" @@ -2398,18 +2399,18 @@ dependencies = [ [[package]] name = "dtor" -version = "0.3.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4" +checksum = "edf234dd1594d6dd434a8fb8cada51ddbbc593e40e4a01556a0b31c62da2775b" dependencies = [ "dtor-proc-macro", ] [[package]] name = "dtor-proc-macro" -version = "0.0.6" +version = "0.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5" +checksum = "2647271c92754afcb174e758003cfd1cbf1e43e5a7853d7b1813e63e19e39a73" [[package]] name = "dunce" @@ -3347,7 +3348,7 @@ dependencies = [ "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.2", + "socket2 0.5.10", "tokio", "tower-service", "tracing", @@ -3781,17 +3782,6 @@ version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06432fb54d3be7964ecd3649233cddf80db2832f47fec34c01f65b3d9d774983" -[[package]] -name = "io-uring" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] - [[package]] name = "ipnet" version = "2.10.1" @@ -4102,9 +4092,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.174" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libfuzzer-sys" @@ -4218,6 +4208,12 @@ dependencies = [ "smallvec", ] +[[package]] +name = "link-section" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b685d66585d646efe09fec763d796c291049c8b6bf84e04954bffc8748341f0d" + [[package]] name = "linked-hash-map" version = "0.5.6" @@ -4569,14 +4565,14 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.3" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5078,7 +5074,7 @@ dependencies = [ "kqueue", "libc", "log", - "mio 1.0.3", + "mio 1.2.0", "notify-types", "walkdir", "windows-sys 0.60.2", @@ -6089,7 +6085,7 @@ dependencies = [ "quinn-udp", "rustc-hash 2.1.1", "rustls", - "socket2 0.6.2", + "socket2 0.5.10", "thiserror 2.0.12", "tokio", "tracing", @@ -6127,7 +6123,7 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.2", + "socket2 0.5.10", "tracing", "windows-sys 0.60.2", ] @@ -7417,12 +7413,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -9304,30 +9300,27 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.3" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89b5fb34fc88de6a0c0e32dcee5f4890c67b8afbbc4ba35afc0671c6eacda60" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", - "mio 1.0.3", + "mio 1.2.0", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.2", + "socket2 0.6.3", "tokio-macros", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", @@ -9380,15 +9373,14 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.13" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7fcaa8d55a2bdd6b83ace262b016eca0d79ee02818c5c1bcdf0305114081078" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", "futures-sink", "futures-util", - "hashbrown 0.14.5", "pin-project-lite", "tokio", ] @@ -9898,6 +9890,7 @@ dependencies = [ "bincode 2.0.1", "codspeed-criterion-compat", "concurrent-queue", + "ctor 0.10.1", "dashmap 6.1.0", "either", "erased-serde", @@ -10120,7 +10113,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode 2.0.1", - "ctor 0.8.0", + "ctor 0.10.1", "serde", "tokio", "trybuild", @@ -10809,6 +10802,7 @@ dependencies = [ "rustc-hash 2.1.1", "serde", "serde_json", + "smallvec", "tungstenite 0.21.0", "turbo-rcstr", "turbo-tasks-malloc", diff --git a/Cargo.toml b/Cargo.toml index c9879b8909b..e4c649c01e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -258,7 +258,7 @@ console-subscriber = "0.4.1" const_format = "0.2.30" crc32fast = "1.5.0" criterion = { package = "codspeed-criterion-compat", version = "4.3.0" } -ctor = "0.8" +ctor = "0.10" crossbeam-channel = "0.5.8" crossbeam-utils = "0.8" dashmap = "6.1.0" @@ -348,8 +348,8 @@ tempfile = "3.20.0" terminal_size = "0.3.0" thiserror = "1.0.48" thread_local = "1.1.8" -tokio = "~1.47.3" -tokio-util = { version = "0.7.13", features = ["io", "rt"] } +tokio = "1.52.1" +tokio-util = { version = "0.7.18", features = ["io", "rt"] } tracing = "0.1.44" tracing-subscriber = "0.3.16" triomphe = { git = "https://github.com/sokra/triomphe", branch = "sokra/unstable" } diff --git a/crates/next-api/src/client_references.rs b/crates/next-api/src/client_references.rs index bd2f137c3eb..5f77173b386 100644 --- a/crates/next-api/src/client_references.rs +++ b/crates/next-api/src/client_references.rs @@ -31,9 +31,9 @@ pub struct ClientReferenceData(FxHashMap>, ClientMani pub async fn map_client_references( graph: ResolvedVc, ) -> Result> { - let graph = graph.await?; let manifest = graph - .iter_nodes() + .await? + .iter_reachable_modules()? .map(|module| async move { if let Some(client_reference_module) = ResolvedVc::try_downcast_type::(module) diff --git a/crates/next-api/src/dynamic_imports.rs b/crates/next-api/src/dynamic_imports.rs index 8a09e081622..3c0e4f92b85 100644 --- a/crates/next-api/src/dynamic_imports.rs +++ b/crates/next-api/src/dynamic_imports.rs @@ -123,7 +123,7 @@ pub async fn map_next_dynamic( let actions = graph .await? - .iter_nodes() + .iter_reachable_modules()? .map(|module| async move { if let Some(dynamic_entry_module) = ResolvedVc::try_downcast_type::(module) diff --git a/crates/next-api/src/project.rs b/crates/next-api/src/project.rs index 63da4038135..611251d188c 100644 --- a/crates/next-api/src/project.rs +++ b/crates/next-api/src/project.rs @@ -2482,7 +2482,7 @@ async fn scale_down_node_pool(project: ResolvedVc) -> Result<()> { async fn whole_app_module_graph_operation( project: ResolvedVc, ) -> Result> { - let span = tracing::info_span!("whole app module graph", modules = Empty); + let span = tracing::info_span!("whole app module graph", modules = Empty, edges = Empty); let span_clone = span.clone(); async move { let next_mode = project.next_mode(); @@ -2529,15 +2529,24 @@ async fn whole_app_module_graph_operation( .connect() .module_count() .untracked() - .owned() .await?; let additional_module_count = additional_module_graph .connect() .module_count() .untracked() - .owned() .await?; - span.record("modules", base_module_count + additional_module_count); + span.record("modules", *base_module_count + *additional_module_count); + let base_edge_count = base_single_module_graph + .connect() + .edge_count() + .untracked() + .await?; + let additional_edge_count = additional_module_graph + .connect() + .edge_count() + .untracked() + .await?; + span.record("edges", *base_edge_count + *additional_edge_count); } let graphs = vec![base_single_module_graph, additional_module_graph]; diff --git a/crates/next-api/src/server_actions.rs b/crates/next-api/src/server_actions.rs index d2cb359bdf1..5d85211344b 100644 --- a/crates/next-api/src/server_actions.rs +++ b/crates/next-api/src/server_actions.rs @@ -527,7 +527,7 @@ pub async fn map_server_actions( ) -> Result> { let actions = graph .await? - .iter_nodes() + .iter_reachable_modules()? .map(async |module| { // TODO: compare module contexts instead? let layer = match module.ident().await?.layer.as_ref() { diff --git a/lerna.json b/lerna.json index f79f4e9a5a5..5fca0c04212 100644 --- a/lerna.json +++ b/lerna.json @@ -15,5 +15,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "16.3.0-canary.4" -} + "version": "16.3.0-canary.5" +} \ No newline at end of file diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 056fbf21319..6cd531a9e91 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index a0edb5d2f6e..8ef8aa77e03 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "ESLint configuration used by Next.js.", "license": "MIT", "repository": { @@ -12,7 +12,7 @@ "dist" ], "dependencies": { - "@next/eslint-plugin-next": "16.3.0-canary.4", + "@next/eslint-plugin-next": "16.3.0-canary.5", "eslint-import-resolver-node": "^0.3.6", "eslint-import-resolver-typescript": "^3.5.2", "eslint-plugin-import": "^2.32.0", diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index b7d5fa0093d..ab86c488edb 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,7 +1,7 @@ { "name": "@next/eslint-plugin-internal", "private": true, - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "ESLint plugin for working on Next.js.", "exports": { ".": "./src/eslint-plugin-internal.js" diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 261f15f2755..2bbe9c40314 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/packages/font/package.json b/packages/font/package.json index f11bd9ea7f2..15350993877 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,7 +1,7 @@ { "name": "@next/font", "private": true, - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 8032b770340..9e5a4acac92 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 6f1bfbf0ff9..ac64619da63 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 01a5a3b768b..dfdde13d08f 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index bb027703f21..0fcc6ef2a61 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-playwright/package.json b/packages/next-playwright/package.json index a9888468903..2c60c2b450b 100644 --- a/packages/next-playwright/package.json +++ b/packages/next-playwright/package.json @@ -1,6 +1,6 @@ { "name": "@next/playwright", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-playwright" diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 19df21707a2..a22812457ec 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index c2962c4a815..ba7173ff216 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 03987548d1d..7eb0847b8eb 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-routing/package.json b/packages/next-routing/package.json index 591cb0cace6..b7393b55130 100644 --- a/packages/next-routing/package.json +++ b/packages/next-routing/package.json @@ -1,6 +1,6 @@ { "name": "@next/routing", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "keywords": [ "react", "next", diff --git a/packages/next-rspack/package.json b/packages/next-rspack/package.json index a6a3b3128b8..c7d38f9e2e5 100644 --- a/packages/next-rspack/package.json +++ b/packages/next-rspack/package.json @@ -1,6 +1,6 @@ { "name": "next-rspack", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "repository": { "url": "vercel/next.js", "directory": "packages/next-rspack" diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 5e1e60726a2..f185866668f 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "private": true, "files": [ "native/" diff --git a/packages/next-swc/turbo.jsonc b/packages/next-swc/turbo.jsonc index 297ba751252..b20c048642b 100644 --- a/packages/next-swc/turbo.jsonc +++ b/packages/next-swc/turbo.jsonc @@ -84,7 +84,12 @@ }, "test-cargo-unit": { "dependsOn": ["rust-fingerprint"], - "inputs": ["../../target/.rust-fingerprint"], + "inputs": [ + "../../target/.rust-fingerprint", + "../../crates/*/tests/**", + "../../turbopack/crates/*/tests/**", + "!../../turbopack/crates/turbopack-tests/tests/execution/**/output/*", + ], }, }, } diff --git a/packages/next/package.json b/packages/next/package.json index 7601c6fedc0..4eb3eb890d2 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "16.3.0-canary.4", + "version": "16.3.0-canary.5", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -101,7 +101,7 @@ ] }, "dependencies": { - "@next/env": "16.3.0-canary.4", + "@next/env": "16.3.0-canary.5", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -165,11 +165,11 @@ "@modelcontextprotocol/sdk": "1.18.1", "@mswjs/interceptors": "0.23.0", "@napi-rs/triples": "1.2.0", - "@next/font": "16.3.0-canary.4", - "@next/polyfill-module": "16.3.0-canary.4", - "@next/polyfill-nomodule": "16.3.0-canary.4", - "@next/react-refresh-utils": "16.3.0-canary.4", - "@next/swc": "16.3.0-canary.4", + "@next/font": "16.3.0-canary.5", + "@next/polyfill-module": "16.3.0-canary.5", + "@next/polyfill-nomodule": "16.3.0-canary.5", + "@next/react-refresh-utils": "16.3.0-canary.5", + "@next/swc": "16.3.0-canary.5", "@opentelemetry/api": "1.6.0", "@playwright/test": "1.58.2", "@rspack/core": "1.6.7", diff --git a/packages/next/src/next-devtools/dev-overlay/components/devtools-indicator/next-logo.tsx b/packages/next/src/next-devtools/dev-overlay/components/devtools-indicator/next-logo.tsx index d12da9fb58e..11a9c1a55df 100644 --- a/packages/next/src/next-devtools/dev-overlay/components/devtools-indicator/next-logo.tsx +++ b/packages/next/src/next-devtools/dev-overlay/components/devtools-indicator/next-logo.tsx @@ -7,6 +7,7 @@ import { css } from '../../utils/css' import { useDevOverlayContext } from '../../../dev-overlay.browser' import { useRenderErrorContext } from '../../dev-overlay' import { useDelayedRender } from '../../hooks/use-delayed-render' +import { useDebouncedValue } from '../../hooks/use-debounced-value' import { ACTION_ERROR_OVERLAY_CLOSE, ACTION_ERROR_OVERLAY_OPEN, @@ -17,6 +18,12 @@ import { StatusIndicator, Status, getCurrentStatus } from './status-indicator' const SHORT_DURATION_MS = 150 +// Smooth out rapid status transitions driven by bursty HMR events (e.g. +// Compiling→None→Compiling when consecutive compile episodes are <300ms apart, +// or Compiling→Rendering→Compiling oscillation). The debounce bridges burst +// gaps and active↔active flicker. +const STATUS_DEBOUNCE_MS = 300 + export function NextLogo({ onTriggerClick, ...buttonProps @@ -42,12 +49,30 @@ export function NextLogo({ ) // Cache indicator state management - const isCacheFilling = state.cacheIndicator === 'filling' const isCacheBypassing = state.cacheIndicator === 'bypass' + // Get the current status from the state. Debounce active↔active transitions + // (e.g. Compiling→Rendering) so bursts of HMR events don't flicker the + // badge. Transitions to None are committed immediately so fast single builds + // cancel the enter timer before the pill becomes visible. + const currentStatus = useDebouncedValue( + getCurrentStatus( + state.buildingIndicator, + state.renderingIndicator, + state.cacheIndicator + ), + STATUS_DEBOUNCE_MS, + { + // Only None→active is immediate (no debounce on top of enterDelay). + // active→None is debounced so short inter-burst gaps don't prematurely + // collapse the pill. Fast single builds (completing in