chore(dev): add opt-in render cause diagnostics

This commit is contained in:
Tunglies
2026-11-03 19:29:43 +08:00
parent d2c6eafc9e
commit e69c8aeccf
7 changed files with 67 additions and 4 deletions
+2 -1
View File
@@ -7,7 +7,8 @@
"scripts/react/profiler.ts!",
"scripts/react/boundaries.tsx!",
"scripts/react/material.tsx!",
"scripts/react/yaml.ts!"
"scripts/react/yaml.ts!",
"scripts/react/wdyr.ts!"
],
"project": ["src/**/*.{js,jsx,ts,tsx,sass,scss}!", "scripts/**/*.{js,mjs}!"],
"include": [
+4 -2
View File
@@ -42,7 +42,8 @@
"perf:compare": "node scripts/perf/compare.mjs",
"perf:test": "node --test scripts/perf/report.test.mjs",
"dev:profile": "cross-env CVR_REACT_DIAGNOSTICS=profiler node scripts/dev.mjs dev",
"react:ab": "node scripts/react/ab.mjs"
"react:ab": "node scripts/react/ab.mjs",
"dev:wdyr": "cross-env CVR_REACT_DIAGNOSTICS=wdyr node scripts/dev.mjs dev"
},
"dependencies": {
"@dnd-kit/collision": "^0.5.0",
@@ -137,7 +138,8 @@
"vitest": "^5.0.1",
"webdriverio": "10.1.0",
"ws": "8.22.1",
"playwright": "1.64.1"
"playwright": "1.64.1",
"@welldone-software/why-did-you-render": "10.0.1"
},
"lint-staged": {
"*.{ts,tsx,js,mjs}": [
+13
View File
@@ -341,6 +341,9 @@ importers:
'@wdio/tauri-service':
specifier: 1.5.0
version: 1.5.0(expect-webdriverio@6.1.0)(supports-color@7.2.0)(webdriverio@10.1.0(supports-color@7.2.0)(yauzl@2.10.0))
'@welldone-software/why-did-you-render':
specifier: 10.0.1
version: 10.0.1(react@19.3.1)
adm-zip:
specifier: ^0.6.1
version: 0.6.1
@@ -2681,6 +2684,11 @@ packages:
resolution: {integrity: sha512-BABJY+L4JidOD2bfQe3icuRZ0jQeUimTwUEe66I4BHVGWwaa5QBeVU+JZmdNQLjMA9q+Nk385aL96Mb1/PbKYw==}
engines: {node: '>=22.19.0'}
'@welldone-software/why-did-you-render@10.0.1':
resolution: {integrity: sha512-tMgGkt30iVYeLMUKExNmtm019QgyjLtA7lwB0QAizYNEuihlCG2eoAWBBaz/bDeI7LeqAJ9msC6hY3vX+JB97g==}
peerDependencies:
react: ^19
'@zip.js/zip.js@2.24.0':
resolution: {integrity: sha512-WlaVKzdqBK+RF3bdiXZWbdCnvGB6PdO4IHC1mn/2Yfl3bASgqUNegnU3+PNg61iecwoPfUi5BgLUPqBukXpyWw==}
engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=18.0.0'}
@@ -7389,6 +7397,11 @@ snapshots:
- supports-color
- yauzl
'@welldone-software/why-did-you-render@10.0.1(react@19.3.1)':
dependencies:
lodash: 4.18.1
react: 19.3.1
'@zip.js/zip.js@2.24.0': {}
abort-controller@3.0.0:
+7
View File
@@ -6,6 +6,13 @@ copies of the latest 1,000 standard Profiler callback records; `.clear()` drops
them. Records contain timing and commit metadata, never business props. Normal
development and production builds do not load the collector.
`pnpm dev:wdyr` instead initializes why-did-you-render before loading the app
and uses its development JSX runtime. It reports avoidable renders for
`ProxyItem`, `ProxyItemMini` and `ProxyTunCard` in the console. The modes are
mutually exclusive; `CVR_REACT_DIAGNOSTICS` accepts only `profiler` or `wdyr` on
the development server. Each mode uses its own Vite cache. Production builds
ignore this variable and include neither diagnostic entry nor runtime.
Install the browser explicitly with `pnpm exec playwright install chromium`.
Then run `pnpm react:ab --base <ref> --head <ref>`. Both Git trees run against
one installed dependency set and the same fixed DNS, delay-hook and proxy-tab
+30 -1
View File
@@ -10,10 +10,39 @@ export function reactDiagnostics(mode: string | undefined): Plugin[] {
enforce: 'pre',
apply: 'serve',
config() {
if (mode !== 'profiler')
if (mode !== 'profiler' && mode !== 'wdyr')
throw new Error(`Unknown CVR_REACT_DIAGNOSTICS mode: ${mode}`)
return {
cacheDir: path.resolve('node_modules/.vite', mode),
...(mode === 'wdyr'
? {
oxc: {
jsx: {
importSource: '@welldone-software/why-did-you-render',
},
},
optimizeDeps: {
include: [
'@welldone-software/why-did-you-render',
'@welldone-software/why-did-you-render/jsx-dev-runtime',
],
},
}
: {}),
}
},
transformIndexHtml(html) {
if (mode !== 'wdyr') return html
const entry = 'src="./main.tsx"'
if (!html.includes(entry))
throw new Error('WDYR entry no longer matches index.html')
return html.replace(
entry,
`src="/@fs/${normalizePath(path.resolve('scripts/react/wdyr.ts'))}"`,
)
},
transform(code, id) {
if (mode !== 'profiler') return
if (id !== normalizePath(path.resolve('src/main.tsx'))) return
const open = '<React.StrictMode>'
const close = '</React.StrictMode>'
+10
View File
@@ -0,0 +1,10 @@
import whyDidYouRender from '@welldone-software/why-did-you-render'
import React from 'react'
whyDidYouRender(React, {
include: [/^(ProxyItem|ProxyItemMini|ProxyTunCard)$/],
trackAllPureComponents: false,
trackHooks: true,
})
await import('../../src/main')
+1
View File
@@ -9,6 +9,7 @@ import { reactDiagnostics } from './scripts/react/vite.mts'
export default defineConfig({
root: 'src',
cacheDir: path.resolve('node_modules/.vite/default'),
server: { port: 3000 },
plugins: [
svgr(),