From d6eb3e9827a751861f7ed41e31f2b13f1a7d2e30 Mon Sep 17 00:00:00 2001 From: Ryan Carniato Date: Sun, 27 Sep 2026 03:00:58 -0700 Subject: [PATCH] feat: performance tracks on by default under vite dev (performanceTracks option) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New `performanceTracks` option (`boolean | PerformanceTracksOptions`, default `true`): under `vite dev` the plugin injects `virtual:solid-performance-tracks` — a module that calls `@solidjs/web/performance-tracks`' enablePerformanceTracks() with the serialized options — ahead of the app's entry: a head-prepended module script for index.html apps (transformIndexHtml), the first import of the generated or authored client entry in start mode. Hydration and the first interaction land on the Chrome Performance panel's Solid tracks without the app enabling them itself. Never on vite build (dev: true and observe builds included), preview, or test mode; skipped with a warning if the installed @solidjs/web lacks the ./performance-tracks subpath. The dev server already writes its Server-Timing metrics, so nothing changes server-side. Tests (examples/start-ssr): dev asserts the import order in the generated entry, the served module, the pre-bundled adapter import, and a browser-level check that the first click paints measure entries with detail.devtools.track; entries asserts the authored-entry transform; prod/observe assert no injection in build output; a new perf-tracks mode covers false, the options form, test mode, an index.html app, and a dev: true build. Co-authored-by: Cursor --- .changeset/performance-tracks-dev-default.md | 5 + README.md | 41 +- examples/start-ssr/test/run.mjs | 375 ++++++++++++++++++- examples/start-ssr/vite.config.ts | 12 + package.json | 1 + pnpm-lock.yaml | 6 +- src/index.ts | 42 +++ src/performance-tracks/index.ts | 181 +++++++++ src/ssr/index.ts | 43 ++- 9 files changed, 699 insertions(+), 7 deletions(-) create mode 100644 .changeset/performance-tracks-dev-default.md create mode 100644 src/performance-tracks/index.ts diff --git a/.changeset/performance-tracks-dev-default.md b/.changeset/performance-tracks-dev-default.md new file mode 100644 index 0000000..c39f6f8 --- /dev/null +++ b/.changeset/performance-tracks-dev-default.md @@ -0,0 +1,5 @@ +--- +'@solidjs/vite-plugin': patch +--- + +Chrome Performance panel tracks on by default under `vite dev`. New `performanceTracks` option (`boolean | PerformanceTracksOptions`, default `true`): the plugin injects a client module that calls `@solidjs/web/performance-tracks`' `enablePerformanceTracks()` ahead of the app's entry — a `` module script for `index.html` apps, the first import of the (generated or authored) client entry in start mode — so hydration and the first interaction land on the timeline without the app enabling the tracks itself. An object passes the adapter's options through (`minMs`, `rich`, `attribution`, serialized into the module); `false` opts out. Dev serve only: never on `vite build` (`dev: true` and `observe` builds included), preview, or in test mode. The dev server already writes its `Server-Timing` metrics, which the tracks read back. Skipped with a startup warning if the installed `@solidjs/web` lacks the `./performance-tracks` subpath. diff --git a/README.md b/README.md index fc11153..902b4df 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,43 @@ and turns on the compiler's source names (see `options.solid.sourceNames`), so g (``, `span.textContent`, `count`) survive minification. Under `vite dev` the dev build still wins. +#### options.performanceTracks + +- Type: `boolean | PerformanceTracksOptions` (from `@solidjs/web/performance-tracks`) +- Default: true + +Dev-serve only: paint Solid's records — effect and memo re-runs, interactions, holds, async +flights, navigations, server-function calls — as custom tracks in the Chrome Performance +panel, without the app calling `enablePerformanceTracks()` itself. Record a trace with the +Performance panel while the dev server serves the page; the `Solid` group appears beside +Chrome's main-thread and network tracks (`Interactions`, `Propagation`, `Effects`, `Memos`, +`Async`, `Holds`, `Navigations`, `Server`), every span labelled by *why* it ran, findings as +markers on the Timings track. See [Chrome Performance panel](https://github.com/solidjs/solid/blob/next/documentation/solid-2.0/08-dev-diagnostics.md#chrome-performance-panel-solidjswebperformance-tracks) +in the Solid 2.0 diagnostics guide for how to read them. + +The plugin injects a small client module that enables the tracks *ahead of the app's entry* +— a `', + '', + ].join('\n'); + try { + rmSync(plainRoot, { recursive: true, force: true }); + mkdirSync(path.join(plainRoot, 'src'), { recursive: true }); + writeFileSync(path.join(plainRoot, 'index.html'), plainHtml); + writeFileSync( + path.join(plainRoot, 'src/main.tsx'), + [ + `import { render } from '@solidjs/web';`, + `render(() =>

plain

, document.getElementById('app'));`, + ``, + ].join('\n'), + ); + const { default: solidPlugin } = await import('@solidjs/vite-plugin'); + const plainServer = async (options) => + createServer({ + root: plainRoot, + configFile: false, + plugins: [solidPlugin(options)], + server: { middlewareMode: true }, + }); + + server = await plainServer({}); + const html = await server.transformIndexHtml('/index.html', plainHtml); + const scriptAt = html.indexOf(`/@id/${PERF_TRACKS_ID}`); + const headEnd = html.indexOf(''); + const appAt = html.indexOf('/src/main.tsx'); + record( + mode, + 'plain', + 'index.html app gets the performance-tracks module script in , ahead of its entry', + scriptAt !== -1 && scriptAt < headEnd && scriptAt < appAt, + `script@${scriptAt} @${headEnd} entry@${appAt}`, + ); + record( + mode, + 'plain', + 'the injected script is a module script (deferred, document order)', + html.includes(`