fixtures/flight-ssr-bench/bench.js JAVASCRIPT 793 lines View on github.com → Search inside
1'use strict';23require('@babel/register')({4  presets: [['@babel/preset-react', {runtime: 'automatic'}]],5  plugins: ['@babel/plugin-transform-modules-commonjs'],6  only: [/\/src\//],7});89const path = require('path');10const fs = require('fs');11const webpack = require('webpack');12const inspector = require('node:inspector');1314const {clientManifest, ssrManifest} = require('./webpack-mock');1516const PROFILE_MODE = process.argv.includes('--profile');17const CONCURRENT_MODE = process.argv.includes('--concurrent');18const INJECT = !process.argv.includes('--no-injection');19const JSON_OUT = (function () {20  const arg = process.argv.find(function (a) {21    return a.startsWith('--json-out=');22  });23  return arg ? arg.slice('--json-out='.length) : null;24})();25const jsonResults = [];26function writeJsonOut(mode) {27  if (!JSON_OUT) return;28  fs.writeFileSync(JSON_OUT, JSON.stringify({mode, results: jsonResults}));29}3031// ---------------------------------------------------------------------------32// Build33// ---------------------------------------------------------------------------3435function build() {36  const config = require('./webpack.config');37  return new Promise(function (resolve, reject) {38    webpack(config, function (err, stats) {39      if (err) {40        reject(err);41        return;42      }43      if (stats.hasErrors()) {44        reject(new Error(stats.toString({errors: true})));45        return;46      }47      console.log(48        stats.toString({colors: true, modules: false, entrypoints: false})49      );50      resolve();51    });52  });53}5455// ---------------------------------------------------------------------------56// Render helpers57// ---------------------------------------------------------------------------5859const {60  renderFizzNode: renderFizzNodeStream,61  renderFizzEdge: renderFizzEdgeStream,62  renderFlightFizzNode: renderFlightFizzNodeStream,63  renderFlightFizzEdge: renderFlightFizzEdgeStream,64  nodeStreamToString,65  webStreamToString,66} = require('./render-helpers');67const {printGrid} = require('./print-helpers');6869function renderFizzNode(AppComponent, itemCount) {70  return nodeStreamToString(renderFizzNodeStream(AppComponent, itemCount));71}7273function renderFizzEdge(AppComponent, itemCount) {74  return renderFizzEdgeStream(AppComponent, itemCount).then(webStreamToString);75}7677function renderFlightFizzNode(renderRSCNode, AppComponent, itemCount) {78  return nodeStreamToString(79    renderFlightFizzNodeStream(80      renderRSCNode,81      AppComponent,82      itemCount,83      clientManifest,84      ssrManifest,85      {inject: INJECT}86    )87  );88}8990function renderFlightFizzEdge(renderRSCEdge, AppComponent, itemCount) {91  return renderFlightFizzEdgeStream(92    renderRSCEdge,93    AppComponent,94    itemCount,95    clientManifest,96    ssrManifest,97    {inject: INJECT}98  ).then(webStreamToString);99}100101// ---------------------------------------------------------------------------102// Benchmarking103// ---------------------------------------------------------------------------104105const canGC = typeof globalThis.gc === 'function';106107// Yield to the event loop's check phase between renders. React schedules a108// setImmediate per request, but a fully in-process render completes entirely109// in microtasks/nextTicks, so a tight benchmark loop never lets those110// immediates run. They then pile up in Node's immediate queue, each one111// retaining its (otherwise finished) request graph, which inflates any memory112// measurement. A real server yields to the event loop on every request, so113// draining between iterations is both correct and more representative.114function tick() {115  return new Promise(resolve => setImmediate(resolve));116}117118async function settledHeapUsed() {119  await tick();120  if (canGC) globalThis.gc();121  return process.memoryUsage().heapUsed;122}123124async function runBenchmark(name, fn, iterations, warmup) {125  if (canGC) globalThis.gc();126  const heapBefore = await settledHeapUsed();127128  // Warmup129  for (let i = 0; i < warmup; i++) {130    await fn();131    await tick();132  }133134  // Collect GC pauses during timed iterations.135  let gcCount = 0;136  let gcTotalMs = 0;137  const gcObs = new PerformanceObserver(list => {138    for (const entry of list.getEntries()) {139      gcCount++;140      gcTotalMs += entry.duration;141    }142  });143  gcObs.observe({entryTypes: ['gc']});144145  // Timed iterations. The tick between iterations is excluded from the146  // timed window.147  const times = [];148  for (let i = 0; i < iterations; i++) {149    const start = performance.now();150    await fn();151    times.push(performance.now() - start);152    await tick();153  }154  gcObs.disconnect();155  const heapAfter = await settledHeapUsed();156157  // Trim top/bottom 5% to remove outliers158  const sorted = [...times].sort((a, b) => a - b);159  const trimCount = Math.floor(sorted.length * 0.05);160  const trimmed = sorted.slice(trimCount, sorted.length - trimCount);161162  const mean = trimmed.reduce((s, t) => s + t, 0) / trimmed.length;163  const median = sorted[Math.floor(sorted.length / 2)];164  const stddev = Math.sqrt(165    trimmed.reduce((s, t) => s + (t - mean) ** 2, 0) / trimmed.length166  );167  const p95 = sorted[Math.floor(sorted.length * 0.95)];168  const min = sorted[0];169  const max = sorted[sorted.length - 1];170171  return {172    name,173    mean,174    median,175    stddev,176    p95,177    min,178    max,179    iterations,180    gcCount,181    gcTotalMs,182    heapBefore,183    heapAfter,184  };185}186187function printResult(result) {188  jsonResults.push(result);189  console.log('  %s:', result.name);190  console.log('    Mean:   %s ms', result.mean.toFixed(2));191  console.log('    Median: %s ms', result.median.toFixed(2));192  console.log('    Stddev: %s ms', result.stddev.toFixed(2));193  console.log('    P95:    %s ms', result.p95.toFixed(2));194  console.log('    Min:    %s ms', result.min.toFixed(2));195  console.log('    Max:    %s ms', result.max.toFixed(2));196  console.log(197    '    GC:     %d pauses, %s ms total (%s ms/iter)',198    result.gcCount,199    result.gcTotalMs.toFixed(1),200    (result.gcTotalMs / result.iterations).toFixed(2)201  );202  printHeap(result);203}204205function printHeap(result) {206  if (!canGC) return;207  const mb = b => (b / 1048576).toFixed(1);208  const delta = result.heapAfter - result.heapBefore;209  console.log(210    '    Heap:   %s MB retained after run (%s%s MB vs before)',211    mb(result.heapAfter),212    delta >= 0 ? '+' : '',213    mb(delta)214  );215}216217async function runConcurrent(name, fn, total, concurrency, warmup) {218  if (canGC) globalThis.gc();219  const heapBefore = await settledHeapUsed();220221  for (let i = 0; i < warmup; i++) {222    await fn();223    await tick();224  }225226  let gcCount = 0;227  let gcTotalMs = 0;228  const gcObs = new PerformanceObserver(list => {229    for (const entry of list.getEntries()) {230      gcCount++;231      gcTotalMs += entry.duration;232    }233  });234  gcObs.observe({entryTypes: ['gc']});235236  const latencies = new Array(total);237  let completed = 0;238  let launched = 0;239240  const start = performance.now();241  await new Promise(resolve => {242    function launch() {243      while (launched < total && launched - completed < concurrency) {244        const idx = launched++;245        const t0 = performance.now();246        fn()247          .then(() => {248            latencies[idx] = performance.now() - t0;249            // Drain immediates before freeing the slot (see tick()).250            return tick();251          })252          .then(() => {253            completed++;254            if (completed === total) {255              resolve();256            } else {257              launch();258            }259          });260      }261    }262    launch();263  });264  const elapsed = performance.now() - start;265  gcObs.disconnect();266  const heapAfter = await settledHeapUsed();267268  const sorted = [...latencies].sort((a, b) => a - b);269  const mean = sorted.reduce((s, t) => s + t, 0) / sorted.length;270  const p95 = sorted[Math.floor(sorted.length * 0.95)];271272  return {273    name,274    reqPerSec: (total / elapsed) * 1000,275    mean,276    p95,277    total,278    concurrency,279    gcCount,280    gcTotalMs,281    heapBefore,282    heapAfter,283  };284}285286function printConcurrentResult(result) {287  jsonResults.push(result);288  console.log('  %s:', result.name);289  console.log('    Req/s:  %s', result.reqPerSec.toFixed(1));290  console.log('    Mean:   %s ms', result.mean.toFixed(2));291  console.log('    P95:    %s ms', result.p95.toFixed(2));292  console.log(293    '    GC:     %d pauses, %s ms total (%s ms/req)',294    result.gcCount,295    result.gcTotalMs.toFixed(1),296    (result.gcTotalMs / result.total).toFixed(2)297  );298  printHeap(result);299}300301// ---------------------------------------------------------------------------302// CPU Profiling303// ---------------------------------------------------------------------------304305function startProfiler() {306  const session = new inspector.Session();307  session.connect();308  return new Promise(function (resolve, reject) {309    session.post('Profiler.enable', function (err) {310      if (err) {311        reject(err);312        return;313      }314      session.post('Profiler.start', function (err2) {315        if (err2) {316          reject(err2);317          return;318        }319        resolve(session);320      });321    });322  });323}324325function stopProfiler(session, outputPath) {326  return new Promise(function (resolve, reject) {327    session.post('Profiler.stop', function (err, {profile}) {328      if (err) {329        reject(err);330        return;331      }332      fs.mkdirSync(path.dirname(outputPath), {recursive: true});333      fs.writeFileSync(outputPath, JSON.stringify(profile));334      session.post('Profiler.disable');335      session.disconnect();336      resolve(profile);337    });338  });339}340341function printTopFunctions(profile, topN) {342  // Aggregate self-time per function from the profile nodes.343  const selfTimes = new Map();344  for (const node of profile.nodes) {345    const name = node.callFrame.functionName || '(anonymous)';346    const loc = node.callFrame.url347      ? node.callFrame.url.replace(/.*\//, '') + ':' + node.callFrame.lineNumber348      : '(native)';349    const key = name + ' @ ' + loc;350    const hitCount = node.hitCount || 0;351    selfTimes.set(key, (selfTimes.get(key) || 0) + hitCount);352  }353354  const sorted = [...selfTimes.entries()]355    .sort((a, b) => b[1] - a[1])356    .slice(0, topN);357358  const totalSamples = profile.nodes.reduce((s, n) => s + (n.hitCount || 0), 0);359360  console.log('    Top %d functions by self-time:', topN);361  for (const [key, hits] of sorted) {362    const pct = ((hits / totalSamples) * 100).toFixed(1);363    console.log('      %s%% - %s', pct, key);364  }365}366367async function profileRun(name, fn, warmup, iterations, outputPath) {368  // Warmup (unprofiled)369  for (let i = 0; i < warmup; i++) {370    await fn();371    await tick();372  }373374  // Collect GC pauses during the profiled run.375  let gcCount = 0;376  let gcTotalMs = 0;377  const gcObs = new PerformanceObserver(list => {378    for (const entry of list.getEntries()) {379      gcCount++;380      gcTotalMs += entry.duration;381    }382  });383  gcObs.observe({entryTypes: ['gc']});384385  // Profiled run386  const session = await startProfiler();387  for (let i = 0; i < iterations; i++) {388    await fn();389    await tick();390  }391  const profile = await stopProfiler(session, outputPath);392  gcObs.disconnect();393394  console.log('  %s → %s', name, outputPath);395  printTopFunctions(profile, 10);396  console.log(397    '    GC: %d pauses, %s ms total (%s ms/iter)',398    gcCount,399    gcTotalMs.toFixed(1),400    (gcTotalMs / iterations).toFixed(2)401  );402}403404// ---------------------------------------------------------------------------405// Main406// ---------------------------------------------------------------------------407408async function main() {409  console.log('Building RSC bundle...\n');410  await build();411412  const {413    renderRSCNode,414    renderRSCEdge,415    App: RSCApp,416    AppAsync: RSCAppAsync,417  } = require('./build/rsc-bundle.js');418  const App = require('./src/App.js').default;419  const AppAsync = require('./src/AppAsync.js').default;420421  const ITEM_COUNT = 200;422423  const WARMUP = 50;424  const ITERATIONS = 1000;425  const PROFILE_WARMUP = 50;426  const PROFILE_ITERATIONS = 500;427428  // --- Verify renders ---429  console.log('\n--- Verifying renders ---\n');430431  const fizzNodeHtml = await renderFizzNode(App, ITEM_COUNT);432  console.log('Fizz (Node, sync):          %d bytes', fizzNodeHtml.length);433434  const flightFizzNodeHtml = await renderFlightFizzNode(435    renderRSCNode,436    RSCApp,437    ITEM_COUNT438  );439  console.log(440    'Flight + Fizz (Node, sync): %d bytes',441    flightFizzNodeHtml.length442  );443444  const fizzNodeAsyncHtml = await renderFizzNode(AppAsync, ITEM_COUNT);445  console.log('Fizz (Node, async):         %d bytes', fizzNodeAsyncHtml.length);446447  const flightFizzNodeAsyncHtml = await renderFlightFizzNode(448    renderRSCNode,449    RSCAppAsync,450    ITEM_COUNT451  );452  console.log(453    'Flight + Fizz (Node, async):%d bytes',454    flightFizzNodeAsyncHtml.length455  );456457  const fizzEdgeHtml = await renderFizzEdge(App, ITEM_COUNT);458  console.log('Fizz (Edge, sync):          %d bytes', fizzEdgeHtml.length);459460  const fizzEdgeAsyncHtml = await renderFizzEdge(AppAsync, ITEM_COUNT);461  console.log('Fizz (Edge, async):         %d bytes', fizzEdgeAsyncHtml.length);462463  const flightFizzEdgeHtml = await renderFlightFizzEdge(464    renderRSCEdge,465    RSCApp,466    ITEM_COUNT467  );468  console.log(469    'Flight + Fizz (Edge, sync): %d bytes',470    flightFizzEdgeHtml.length471  );472473  const flightFizzEdgeAsyncHtml = await renderFlightFizzEdge(474    renderRSCEdge,475    RSCAppAsync,476    ITEM_COUNT477  );478  console.log(479    'Flight + Fizz (Edge, async):%d bytes',480    flightFizzEdgeAsyncHtml.length481  );482483  // --- CPU Profiling ---484  if (PROFILE_MODE) {485    console.log(486      '\n--- CPU Profiling (%d warmup, %d iterations) ---\n',487      PROFILE_WARMUP,488      PROFILE_ITERATIONS489    );490491    const profileDir = path.resolve(__dirname, 'build/profiles');492493    await profileRun(494      'Fizz (Node, sync)',495      () => renderFizzNode(App, ITEM_COUNT),496      PROFILE_WARMUP,497      PROFILE_ITERATIONS,498      path.join(profileDir, 'fizz-node-sync.cpuprofile')499    );500501    await profileRun(502      'Flight + Fizz (Node, sync)',503      () => renderFlightFizzNode(renderRSCNode, RSCApp, ITEM_COUNT),504      PROFILE_WARMUP,505      PROFILE_ITERATIONS,506      path.join(profileDir, 'flight-fizz-node-sync.cpuprofile')507    );508509    await profileRun(510      'Fizz (Node, async)',511      () => renderFizzNode(AppAsync, ITEM_COUNT),512      PROFILE_WARMUP,513      PROFILE_ITERATIONS,514      path.join(profileDir, 'fizz-node-async.cpuprofile')515    );516517    await profileRun(518      'Flight + Fizz (Node, async)',519      () => renderFlightFizzNode(renderRSCNode, RSCAppAsync, ITEM_COUNT),520      PROFILE_WARMUP,521      PROFILE_ITERATIONS,522      path.join(profileDir, 'flight-fizz-node-async.cpuprofile')523    );524525    await profileRun(526      'Fizz (Edge, sync)',527      () => renderFizzEdge(App, ITEM_COUNT),528      PROFILE_WARMUP,529      PROFILE_ITERATIONS,530      path.join(profileDir, 'fizz-edge-sync.cpuprofile')531    );532533    await profileRun(534      'Flight + Fizz (Edge, sync)',535      () => renderFlightFizzEdge(renderRSCEdge, RSCApp, ITEM_COUNT),536      PROFILE_WARMUP,537      PROFILE_ITERATIONS,538      path.join(profileDir, 'flight-fizz-edge-sync.cpuprofile')539    );540541    await profileRun(542      'Fizz (Edge, async)',543      () => renderFizzEdge(AppAsync, ITEM_COUNT),544      PROFILE_WARMUP,545      PROFILE_ITERATIONS,546      path.join(profileDir, 'fizz-edge-async.cpuprofile')547    );548549    await profileRun(550      'Flight + Fizz (Edge, async)',551      () => renderFlightFizzEdge(renderRSCEdge, RSCAppAsync, ITEM_COUNT),552      PROFILE_WARMUP,553      PROFILE_ITERATIONS,554      path.join(profileDir, 'flight-fizz-edge-async.cpuprofile')555    );556557    console.log(558      '\nProfiles saved to build/profiles/. Open in Chrome DevTools or speedscope.app.'559    );560561    return;562  }563564  // --- Concurrent Benchmark ---565  if (CONCURRENT_MODE) {566    const CONCURRENCY = 50;567    const TOTAL = 1000;568    const CONC_WARMUP = 20;569570    console.log(571      '\n--- Concurrent Benchmark (%d warmup, %d concurrency, %d requests, %d items) ---\n',572      CONC_WARMUP,573      CONCURRENCY,574      TOTAL,575      ITEM_COUNT576    );577578    const fizzNodeSync = await runConcurrent(579      'Fizz (Node, sync)',580      () => renderFizzNode(App, ITEM_COUNT),581      TOTAL,582      CONCURRENCY,583      CONC_WARMUP584    );585    printConcurrentResult(fizzNodeSync);586587    const flightFizzNodeSync = await runConcurrent(588      'Flight + Fizz (Node, sync)',589      () => renderFlightFizzNode(renderRSCNode, RSCApp, ITEM_COUNT),590      TOTAL,591      CONCURRENCY,592      CONC_WARMUP593    );594    printConcurrentResult(flightFizzNodeSync);595596    const fizzNodeAsync = await runConcurrent(597      'Fizz (Node, async)',598      () => renderFizzNode(AppAsync, ITEM_COUNT),599      TOTAL,600      CONCURRENCY,601      CONC_WARMUP602    );603    printConcurrentResult(fizzNodeAsync);604605    const flightFizzNodeAsync = await runConcurrent(606      'Flight + Fizz (Node, async)',607      () => renderFlightFizzNode(renderRSCNode, RSCAppAsync, ITEM_COUNT),608      TOTAL,609      CONCURRENCY,610      CONC_WARMUP611    );612    printConcurrentResult(flightFizzNodeAsync);613614    const fizzEdgeSync = await runConcurrent(615      'Fizz (Edge, sync)',616      () => renderFizzEdge(App, ITEM_COUNT),617      TOTAL,618      CONCURRENCY,619      CONC_WARMUP620    );621    printConcurrentResult(fizzEdgeSync);622623    const flightFizzEdgeSync = await runConcurrent(624      'Flight + Fizz (Edge, sync)',625      () => renderFlightFizzEdge(renderRSCEdge, RSCApp, ITEM_COUNT),626      TOTAL,627      CONCURRENCY,628      CONC_WARMUP629    );630    printConcurrentResult(flightFizzEdgeSync);631632    const fizzEdgeAsync = await runConcurrent(633      'Fizz (Edge, async)',634      () => renderFizzEdge(AppAsync, ITEM_COUNT),635      TOTAL,636      CONCURRENCY,637      CONC_WARMUP638    );639    printConcurrentResult(fizzEdgeAsync);640641    const flightFizzEdgeAsync = await runConcurrent(642      'Flight + Fizz (Edge, async)',643      () => renderFlightFizzEdge(renderRSCEdge, RSCAppAsync, ITEM_COUNT),644      TOTAL,645      CONCURRENCY,646      CONC_WARMUP647    );648    printConcurrentResult(flightFizzEdgeAsync);649650    const rps = r => r.reqPerSec;651652    console.log('\n--- Flight overhead ---\n');653    printGrid(654      ['Fizz', 'Flight+Fizz'],655      [656        ['Node sync', fizzNodeSync, flightFizzNodeSync],657        ['Node async', fizzNodeAsync, flightFizzNodeAsync],658        ['Edge sync', fizzEdgeSync, flightFizzEdgeSync],659        ['Edge async', fizzEdgeAsync, flightFizzEdgeAsync],660      ],661      rps,662      'req/s',663      'higher is better'664    );665666    console.log('\n--- Edge vs Node ---\n');667    printGrid(668      ['Node', 'Edge'],669      [670        ['Fizz sync', fizzNodeSync, fizzEdgeSync],671        ['Fizz async', fizzNodeAsync, fizzEdgeAsync],672        ['Flight+Fizz sync', flightFizzNodeSync, flightFizzEdgeSync],673        ['Flight+Fizz async', flightFizzNodeAsync, flightFizzEdgeAsync],674      ],675      rps,676      'req/s',677      'higher is better'678    );679680    writeJsonOut('concurrent');681    return;682  }683684  // --- Benchmark ---685  console.log(686    '\n--- Benchmark (%d warmup, %d iterations, %d items) ---\n',687    WARMUP,688    ITERATIONS,689    ITEM_COUNT690  );691692  const fizzNodeSync = await runBenchmark(693    'Fizz (Node, sync)',694    () => renderFizzNode(App, ITEM_COUNT),695    ITERATIONS,696    WARMUP697  );698  printResult(fizzNodeSync);699700  const flightFizzNodeSync = await runBenchmark(701    'Flight + Fizz (Node, sync)',702    () => renderFlightFizzNode(renderRSCNode, RSCApp, ITEM_COUNT),703    ITERATIONS,704    WARMUP705  );706  printResult(flightFizzNodeSync);707708  const fizzNodeAsync = await runBenchmark(709    'Fizz (Node, async)',710    () => renderFizzNode(AppAsync, ITEM_COUNT),711    ITERATIONS,712    WARMUP713  );714  printResult(fizzNodeAsync);715716  const flightFizzNodeAsync = await runBenchmark(717    'Flight + Fizz (Node, async)',718    () => renderFlightFizzNode(renderRSCNode, RSCAppAsync, ITEM_COUNT),719    ITERATIONS,720    WARMUP721  );722  printResult(flightFizzNodeAsync);723724  const fizzEdgeSync = await runBenchmark(725    'Fizz (Edge, sync)',726    () => renderFizzEdge(App, ITEM_COUNT),727    ITERATIONS,728    WARMUP729  );730  printResult(fizzEdgeSync);731732  const flightFizzEdgeSync = await runBenchmark(733    'Flight + Fizz (Edge, sync)',734    () => renderFlightFizzEdge(renderRSCEdge, RSCApp, ITEM_COUNT),735    ITERATIONS,736    WARMUP737  );738  printResult(flightFizzEdgeSync);739740  const fizzEdgeAsync = await runBenchmark(741    'Fizz (Edge, async)',742    () => renderFizzEdge(AppAsync, ITEM_COUNT),743    ITERATIONS,744    WARMUP745  );746  printResult(fizzEdgeAsync);747748  const flightFizzEdgeAsync = await runBenchmark(749    'Flight + Fizz (Edge, async)',750    () => renderFlightFizzEdge(renderRSCEdge, RSCAppAsync, ITEM_COUNT),751    ITERATIONS,752    WARMUP753  );754  printResult(flightFizzEdgeAsync);755756  const median = r => r.median;757758  console.log('\n--- Flight overhead ---\n');759  printGrid(760    ['Fizz', 'Flight+Fizz'],761    [762      ['Node sync', fizzNodeSync, flightFizzNodeSync],763      ['Node async', fizzNodeAsync, flightFizzNodeAsync],764      ['Edge sync', fizzEdgeSync, flightFizzEdgeSync],765      ['Edge async', fizzEdgeAsync, flightFizzEdgeAsync],766    ],767    median,768    'ms',769    'median, lower is better'770  );771772  console.log('\n--- Edge vs Node ---\n');773  printGrid(774    ['Node', 'Edge'],775    [776      ['Fizz sync', fizzNodeSync, fizzEdgeSync],777      ['Fizz async', fizzNodeAsync, fizzEdgeAsync],778      ['Flight+Fizz sync', flightFizzNodeSync, flightFizzEdgeSync],779      ['Flight+Fizz async', flightFizzNodeAsync, flightFizzEdgeAsync],780    ],781    median,782    'ms',783    'median, lower is better'784  );785786  writeJsonOut(INJECT ? 'inject' : 'bare');787}788789main().catch(function (err) {790  console.error(err);791  process.exit(1);792});

Code quality findings 49

Remove debugging statements or use a logging library
info correctness console-log
console.log(
Chain Promises properly to avoid callback hell
info correctness unresolved-promise
return renderFizzEdgeStream(AppComponent, itemCount).then(webStreamToString);
Chain Promises properly to avoid callback hell
info correctness unresolved-promise
).then(webStreamToString);
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
const canGC = typeof globalThis.gc === 'function';
Be cautious with typeof; it has limitations (e.g., typeof null === 'object')
info correctness typeof-pitfall
const canGC = typeof globalThis.gc === 'function';
Ensure all async functions handle errors properly
info correctness async-without-catch
async function settledHeapUsed() {
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runBenchmark(name, fn, iterations, warmup) {
Remove debugging statements or use a logging library
info correctness console-log
console.log(' %s:', result.name);
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Mean: %s ms', result.mean.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Median: %s ms', result.median.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Stddev: %s ms', result.stddev.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' P95: %s ms', result.p95.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Min: %s ms', result.min.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Max: %s ms', result.max.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Ensure all async functions handle errors properly
info correctness async-without-catch
async function runConcurrent(name, fn, total, concurrency, warmup) {
Chain Promises properly to avoid callback hell
info correctness unresolved-promise
.then(() => {
Chain Promises properly to avoid callback hell
info correctness unresolved-promise
.then(() => {
Use strict equality (===) to prevent type coercion bugs
info correctness loose-equality
if (completed === total) {
Remove debugging statements or use a logging library
info correctness console-log
console.log(' %s:', result.name);
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Req/s: %s', result.reqPerSec.toFixed(1));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Mean: %s ms', result.mean.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(' P95: %s ms', result.p95.toFixed(2));
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(' Top %d functions by self-time:', topN);
Remove debugging statements or use a logging library
info correctness console-log
console.log(' %s%% - %s', pct, key);
Ensure all async functions handle errors properly
info correctness async-without-catch
async function profileRun(name, fn, warmup, iterations, outputPath) {
Remove debugging statements or use a logging library
info correctness console-log
console.log(' %s → %s', name, outputPath);
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Ensure all async functions handle errors properly
info correctness async-without-catch
async function main() {
Remove debugging statements or use a logging library
info correctness console-log
console.log('Building RSC bundle...\n');
Remove debugging statements or use a logging library
info correctness console-log
console.log('\n--- Verifying renders ---\n');
Remove debugging statements or use a logging library
info correctness console-log
console.log('Fizz (Node, sync): %d bytes', fizzNodeHtml.length);
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log('Fizz (Node, async): %d bytes', fizzNodeAsyncHtml.length);
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log('Fizz (Edge, sync): %d bytes', fizzEdgeHtml.length);
Remove debugging statements or use a logging library
info correctness console-log
console.log('Fizz (Edge, async): %d bytes', fizzEdgeAsyncHtml.length);
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log('\n--- Flight overhead ---\n');
Remove debugging statements or use a logging library
info correctness console-log
console.log('\n--- Edge vs Node ---\n');
Remove debugging statements or use a logging library
info correctness console-log
console.log(
Remove debugging statements or use a logging library
info correctness console-log
console.log('\n--- Flight overhead ---\n');
Remove debugging statements or use a logging library
info correctness console-log
console.log('\n--- Edge vs Node ---\n');

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.