From 76432fed054cc72c0d69ab81c9622701858c7707 Mon Sep 17 00:00:00 2001 From: Christopher Burns Date: Mon, 16 Feb 2026 12:43:14 +0000 Subject: [PATCH 1/5] chore: add benchmark projects for 'c15t-nextjs', 'c15t-react', and 'cookie-control'; update configurations and dependencies. Includes new METHODOLOGY.md for benchmarking guidelines and adjustments to .gitignore and package.json scripts. --- .cursor/rules/ultracite.mdc | 227 ++ .gitignore | 3 +- METHODOLOGY.md | 289 ++ README.md | 13 +- benchmarks/baseline/next-env.d.ts | 1 + benchmarks/baseline/package.json | 19 +- benchmarks/c15t-nextjs/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/c15t-nextjs/app/layout.tsx | 41 + benchmarks/c15t-nextjs/app/page.tsx | 7 + benchmarks/c15t-nextjs/config.json | 48 + benchmarks/c15t-nextjs/next-env.d.ts | 6 + benchmarks/c15t-nextjs/next.config.ts | 7 + benchmarks/c15t-nextjs/package.json | 29 + benchmarks/c15t-nextjs/tsconfig.json | 11 + benchmarks/c15t-react/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/c15t-react/app/layout.tsx | 41 + benchmarks/c15t-react/app/page.tsx | 7 + benchmarks/c15t-react/config.json | 48 + benchmarks/c15t-react/next-env.d.ts | 6 + benchmarks/c15t-react/next.config.ts | 7 + benchmarks/c15t-react/package.json | 28 + benchmarks/c15t-react/tsconfig.json | 11 + benchmarks/cookie-control/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/cookie-control/app/layout.tsx | 58 + benchmarks/cookie-control/app/page.tsx | 7 + benchmarks/cookie-control/config.json | 40 + benchmarks/cookie-control/next-env.d.ts | 6 + benchmarks/cookie-control/next.config.ts | 7 + benchmarks/cookie-control/package.json | 27 + benchmarks/cookie-control/tsconfig.json | 11 + benchmarks/cookie-yes/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/cookie-yes/app/layout.tsx | 26 + benchmarks/cookie-yes/app/page.tsx | 7 + benchmarks/cookie-yes/config.json | 44 + benchmarks/cookie-yes/next-env.d.ts | 6 + benchmarks/cookie-yes/next.config.ts | 7 + benchmarks/cookie-yes/package.json | 27 + benchmarks/cookie-yes/tsconfig.json | 11 + benchmarks/didomi/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/didomi/app/layout.tsx | 69 + benchmarks/didomi/app/page.tsx | 7 + benchmarks/didomi/config.json | 49 + benchmarks/didomi/next-env.d.ts | 6 + benchmarks/didomi/next.config.ts | 7 + benchmarks/didomi/package.json | 28 + benchmarks/didomi/tsconfig.json | 11 + benchmarks/enzuzo/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/enzuzo/app/layout.tsx | 56 + benchmarks/enzuzo/app/page.tsx | 7 + benchmarks/enzuzo/config.json | 40 + benchmarks/enzuzo/next-env.d.ts | 6 + benchmarks/enzuzo/next.config.ts | 7 + benchmarks/enzuzo/package.json | 27 + benchmarks/enzuzo/tsconfig.json | 11 + benchmarks/iubenda/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/iubenda/app/layout.tsx | 90 + benchmarks/iubenda/app/page.tsx | 7 + benchmarks/iubenda/config.json | 45 + benchmarks/iubenda/next-env.d.ts | 6 + benchmarks/iubenda/next.config.ts | 7 + benchmarks/iubenda/package.json | 27 + benchmarks/iubenda/tsconfig.json | 11 + benchmarks/ketch/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/ketch/app/layout.tsx | 26 + benchmarks/ketch/app/page.tsx | 7 + benchmarks/ketch/config.json | 39 + benchmarks/ketch/next-env.d.ts | 6 + benchmarks/ketch/next.config.ts | 7 + benchmarks/ketch/package.json | 27 + benchmarks/ketch/tsconfig.json | 11 + benchmarks/onetrust/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/onetrust/app/layout.tsx | 30 + benchmarks/onetrust/app/page.tsx | 7 + benchmarks/onetrust/config.json | 46 + benchmarks/onetrust/next-env.d.ts | 6 + benchmarks/onetrust/next.config.ts | 7 + benchmarks/onetrust/package.json | 27 + benchmarks/onetrust/tsconfig.json | 11 + benchmarks/osano/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/osano/app/layout.tsx | 21 + benchmarks/osano/app/page.tsx | 7 + benchmarks/osano/config.json | 40 + benchmarks/osano/next-env.d.ts | 6 + benchmarks/osano/next.config.ts | 7 + benchmarks/osano/package.json | 27 + benchmarks/osano/tsconfig.json | 11 + benchmarks/usercentrics/app/favicon.ico | Bin 0 -> 25931 bytes benchmarks/usercentrics/app/layout.tsx | 25 + benchmarks/usercentrics/app/page.tsx | 7 + benchmarks/usercentrics/config.json | 40 + benchmarks/usercentrics/next-env.d.ts | 6 + benchmarks/usercentrics/next.config.ts | 7 + benchmarks/usercentrics/package.json | 27 + benchmarks/usercentrics/tsconfig.json | 11 + package.json | 60 +- packages/benchmark-schema/schema.json | 53 +- packages/benchmark/README.md | 113 + packages/benchmark/package.json | 34 + packages/benchmark/rslib.config.ts | 14 + packages/benchmark/src/bundle-strategy.ts | 25 + packages/benchmark/src/constants.ts | 81 + .../benchmark/src/cookie-banner-collector.ts | 388 +++ packages/benchmark/src/index.ts | 26 + packages/benchmark/src/network-monitor.ts | 135 + packages/benchmark/src/perfume-collector.ts | 261 ++ .../src/resource-timing-collector.ts | 188 ++ packages/benchmark/src/types.ts | 280 ++ packages/benchmark/tsconfig.json | 15 + packages/cookiebench-cli/README.md | 395 +++ packages/cookiebench-cli/base.json | 19 + packages/cookiebench-cli/package.json | 39 + packages/cookiebench-cli/rslib.config.ts | 24 + .../cookiebench-cli/src/commands/benchmark.ts | 584 ++++ packages/cookiebench-cli/src/commands/db.ts | 270 ++ .../cookiebench-cli/src/commands/results.ts | 1120 ++++++++ packages/cookiebench-cli/src/commands/save.ts | 587 ++++ .../cookiebench-cli/src/commands/scores.ts | 355 +++ .../cookiebench-cli/src/components/intro.ts | 93 + packages/cookiebench-cli/src/index.ts | 135 + packages/cookiebench-cli/src/types/index.ts | 38 + packages/cookiebench-cli/src/utils/auth.ts | 11 + .../cookiebench-cli/src/utils/constants.ts | 31 + packages/cookiebench-cli/src/utils/index.ts | 23 + packages/cookiebench-cli/src/utils/logger.ts | 162 ++ packages/cookiebench-cli/src/utils/scoring.ts | 1422 +++++++++ packages/cookiebench-cli/tsconfig.json | 14 + packages/runner/README.md | 150 + packages/runner/package.json | 34 + packages/runner/rslib.config.ts | 14 + packages/runner/src/benchmark-runner.ts | 474 +++ packages/runner/src/index.ts | 31 + packages/runner/src/performance-aggregator.ts | 463 +++ packages/runner/src/server.ts | 77 + packages/runner/src/statistics.ts | 138 + packages/runner/src/types.ts | 294 ++ packages/runner/src/utils.ts | 57 + packages/runner/tsconfig.json | 15 + packages/shared/README.md | 98 + packages/shared/package.json | 29 + packages/shared/rslib.config.ts | 19 + packages/shared/src/constants.ts | 14 + packages/shared/src/index.ts | 22 + packages/shared/src/utils/config.ts | 26 + packages/shared/src/utils/conversion.ts | 43 + packages/shared/src/utils/package-manager.ts | 37 + packages/shared/src/utils/time.ts | 20 + packages/shared/tsconfig.json | 14 + pnpm-lock.yaml | 2551 +++++++++-------- tsconfig.json | 20 +- turbo.json | 63 +- 150 files changed, 12464 insertions(+), 1390 deletions(-) create mode 100644 .cursor/rules/ultracite.mdc create mode 100644 METHODOLOGY.md create mode 100644 benchmarks/c15t-nextjs/app/favicon.ico create mode 100644 benchmarks/c15t-nextjs/app/layout.tsx create mode 100644 benchmarks/c15t-nextjs/app/page.tsx create mode 100644 benchmarks/c15t-nextjs/config.json create mode 100644 benchmarks/c15t-nextjs/next-env.d.ts create mode 100644 benchmarks/c15t-nextjs/next.config.ts create mode 100644 benchmarks/c15t-nextjs/package.json create mode 100644 benchmarks/c15t-nextjs/tsconfig.json create mode 100644 benchmarks/c15t-react/app/favicon.ico create mode 100644 benchmarks/c15t-react/app/layout.tsx create mode 100644 benchmarks/c15t-react/app/page.tsx create mode 100644 benchmarks/c15t-react/config.json create mode 100644 benchmarks/c15t-react/next-env.d.ts create mode 100644 benchmarks/c15t-react/next.config.ts create mode 100644 benchmarks/c15t-react/package.json create mode 100644 benchmarks/c15t-react/tsconfig.json create mode 100644 benchmarks/cookie-control/app/favicon.ico create mode 100644 benchmarks/cookie-control/app/layout.tsx create mode 100644 benchmarks/cookie-control/app/page.tsx create mode 100644 benchmarks/cookie-control/config.json create mode 100644 benchmarks/cookie-control/next-env.d.ts create mode 100644 benchmarks/cookie-control/next.config.ts create mode 100644 benchmarks/cookie-control/package.json create mode 100644 benchmarks/cookie-control/tsconfig.json create mode 100644 benchmarks/cookie-yes/app/favicon.ico create mode 100644 benchmarks/cookie-yes/app/layout.tsx create mode 100644 benchmarks/cookie-yes/app/page.tsx create mode 100644 benchmarks/cookie-yes/config.json create mode 100644 benchmarks/cookie-yes/next-env.d.ts create mode 100644 benchmarks/cookie-yes/next.config.ts create mode 100644 benchmarks/cookie-yes/package.json create mode 100644 benchmarks/cookie-yes/tsconfig.json create mode 100644 benchmarks/didomi/app/favicon.ico create mode 100644 benchmarks/didomi/app/layout.tsx create mode 100644 benchmarks/didomi/app/page.tsx create mode 100644 benchmarks/didomi/config.json create mode 100644 benchmarks/didomi/next-env.d.ts create mode 100644 benchmarks/didomi/next.config.ts create mode 100644 benchmarks/didomi/package.json create mode 100644 benchmarks/didomi/tsconfig.json create mode 100644 benchmarks/enzuzo/app/favicon.ico create mode 100644 benchmarks/enzuzo/app/layout.tsx create mode 100644 benchmarks/enzuzo/app/page.tsx create mode 100644 benchmarks/enzuzo/config.json create mode 100644 benchmarks/enzuzo/next-env.d.ts create mode 100644 benchmarks/enzuzo/next.config.ts create mode 100644 benchmarks/enzuzo/package.json create mode 100644 benchmarks/enzuzo/tsconfig.json create mode 100644 benchmarks/iubenda/app/favicon.ico create mode 100644 benchmarks/iubenda/app/layout.tsx create mode 100644 benchmarks/iubenda/app/page.tsx create mode 100644 benchmarks/iubenda/config.json create mode 100644 benchmarks/iubenda/next-env.d.ts create mode 100644 benchmarks/iubenda/next.config.ts create mode 100644 benchmarks/iubenda/package.json create mode 100644 benchmarks/iubenda/tsconfig.json create mode 100644 benchmarks/ketch/app/favicon.ico create mode 100644 benchmarks/ketch/app/layout.tsx create mode 100644 benchmarks/ketch/app/page.tsx create mode 100644 benchmarks/ketch/config.json create mode 100644 benchmarks/ketch/next-env.d.ts create mode 100644 benchmarks/ketch/next.config.ts create mode 100644 benchmarks/ketch/package.json create mode 100644 benchmarks/ketch/tsconfig.json create mode 100644 benchmarks/onetrust/app/favicon.ico create mode 100644 benchmarks/onetrust/app/layout.tsx create mode 100644 benchmarks/onetrust/app/page.tsx create mode 100644 benchmarks/onetrust/config.json create mode 100644 benchmarks/onetrust/next-env.d.ts create mode 100644 benchmarks/onetrust/next.config.ts create mode 100644 benchmarks/onetrust/package.json create mode 100644 benchmarks/onetrust/tsconfig.json create mode 100644 benchmarks/osano/app/favicon.ico create mode 100644 benchmarks/osano/app/layout.tsx create mode 100644 benchmarks/osano/app/page.tsx create mode 100644 benchmarks/osano/config.json create mode 100644 benchmarks/osano/next-env.d.ts create mode 100644 benchmarks/osano/next.config.ts create mode 100644 benchmarks/osano/package.json create mode 100644 benchmarks/osano/tsconfig.json create mode 100644 benchmarks/usercentrics/app/favicon.ico create mode 100644 benchmarks/usercentrics/app/layout.tsx create mode 100644 benchmarks/usercentrics/app/page.tsx create mode 100644 benchmarks/usercentrics/config.json create mode 100644 benchmarks/usercentrics/next-env.d.ts create mode 100644 benchmarks/usercentrics/next.config.ts create mode 100644 benchmarks/usercentrics/package.json create mode 100644 benchmarks/usercentrics/tsconfig.json create mode 100644 packages/benchmark/README.md create mode 100644 packages/benchmark/package.json create mode 100644 packages/benchmark/rslib.config.ts create mode 100644 packages/benchmark/src/bundle-strategy.ts create mode 100644 packages/benchmark/src/constants.ts create mode 100644 packages/benchmark/src/cookie-banner-collector.ts create mode 100644 packages/benchmark/src/index.ts create mode 100644 packages/benchmark/src/network-monitor.ts create mode 100644 packages/benchmark/src/perfume-collector.ts create mode 100644 packages/benchmark/src/resource-timing-collector.ts create mode 100644 packages/benchmark/src/types.ts create mode 100644 packages/benchmark/tsconfig.json create mode 100644 packages/cookiebench-cli/README.md create mode 100644 packages/cookiebench-cli/base.json create mode 100644 packages/cookiebench-cli/package.json create mode 100644 packages/cookiebench-cli/rslib.config.ts create mode 100644 packages/cookiebench-cli/src/commands/benchmark.ts create mode 100644 packages/cookiebench-cli/src/commands/db.ts create mode 100644 packages/cookiebench-cli/src/commands/results.ts create mode 100644 packages/cookiebench-cli/src/commands/save.ts create mode 100644 packages/cookiebench-cli/src/commands/scores.ts create mode 100644 packages/cookiebench-cli/src/components/intro.ts create mode 100644 packages/cookiebench-cli/src/index.ts create mode 100644 packages/cookiebench-cli/src/types/index.ts create mode 100644 packages/cookiebench-cli/src/utils/auth.ts create mode 100644 packages/cookiebench-cli/src/utils/constants.ts create mode 100644 packages/cookiebench-cli/src/utils/index.ts create mode 100644 packages/cookiebench-cli/src/utils/logger.ts create mode 100644 packages/cookiebench-cli/src/utils/scoring.ts create mode 100644 packages/cookiebench-cli/tsconfig.json create mode 100644 packages/runner/README.md create mode 100644 packages/runner/package.json create mode 100644 packages/runner/rslib.config.ts create mode 100644 packages/runner/src/benchmark-runner.ts create mode 100644 packages/runner/src/index.ts create mode 100644 packages/runner/src/performance-aggregator.ts create mode 100644 packages/runner/src/server.ts create mode 100644 packages/runner/src/statistics.ts create mode 100644 packages/runner/src/types.ts create mode 100644 packages/runner/src/utils.ts create mode 100644 packages/runner/tsconfig.json create mode 100644 packages/shared/README.md create mode 100644 packages/shared/package.json create mode 100644 packages/shared/rslib.config.ts create mode 100644 packages/shared/src/constants.ts create mode 100644 packages/shared/src/index.ts create mode 100644 packages/shared/src/utils/config.ts create mode 100644 packages/shared/src/utils/conversion.ts create mode 100644 packages/shared/src/utils/package-manager.ts create mode 100644 packages/shared/src/utils/time.ts create mode 100644 packages/shared/tsconfig.json diff --git a/.cursor/rules/ultracite.mdc b/.cursor/rules/ultracite.mdc new file mode 100644 index 0000000..0b3bf93 --- /dev/null +++ b/.cursor/rules/ultracite.mdc @@ -0,0 +1,227 @@ +--- +description: Ultracite Rules - AI-Ready Formatter and Linter +globs: "**/*.{ts,tsx,js,jsx,json,jsonc,html,vue,svelte,astro,css,yaml,yml,graphql,gql,md,mdx,grit}" +alwaysApply: false +--- + +Avoid `accessKey` attr and distracting els +No `aria-hidden="true"` on focusable els +No ARIA roles, states, props on unsupported els +Use `scope` prop only on `` els +No non-interactive ARIA roles on interactive els +Label els need text and associated input +No event handlers on non-interactive els +No interactive ARIA roles on non-interactive els +No `tabIndex` on non-interactive els +No positive integers on `tabIndex` prop +No `image`, `picture`, or `photo` in img alt props +No explicit role matching implicit role +Valid role attrs on static, visible els w/ click handlers +Use `title` el for `svg` els +Provide meaningful alt text for all els requiring it +Anchors need accessible content +Assign `tabIndex` to non-interactive els w/ `aria-activedescendant` +Include all required ARIA attrs for els w/ ARIA roles +Use valid ARIA props for the el's role +Use `type` attr on `button` els +Make els w/ interactive roles and handlers focusable +Heading els need accessible content +Add `lang` attr to `html` el +Use `title` attr on `iframe` els +Pair `onClick` w/ `onKeyUp`, `onKeyDown`, or `onKeyPress` +Pair `onMouseOver`/`onMouseOut` w/ `onFocus`/`onBlur` +Add caption tracks to audio and video els +Use semantic els vs role attrs +All anchors must be valid and navigable +Use valid, non-abstract ARIA props, roles, states, and values +Use valid values for `autocomplete` attr +Use correct ISO language codes in `lang` attr +Include generic font family in font families +No consecutive spaces in regex literals +Avoid `arguments`, comma op, and primitive type aliases +No empty type params in type aliases and interfaces +Keep fns under Cognitive Complexity limit +Limit nesting depth of `describe()` in tests +No unnecessary boolean casts or callbacks on `flatMap` +Use `for...of` vs `Array.forEach` +No classes w/ only static members +No `this` and `super` in static contexts +No unnecessary catch clauses, ctors, `continue`, escape sequences in regex literals, fragments, labels, or nested blocks +No empty exports +No renaming imports, exports, or destructured assignments to same name +No unnecessary string/template literal concatenation or useless cases in switch stmts, `this` aliasing, or `String.raw` without escape sequences +Use simpler alternatives to ternary ops if possible +No `any` or `unknown` as type constraints or initializing vars to `undefined` +Avoid `void` op +Use arrow fns vs function exprs +Use `Date.now()` for milliseconds since Unix Epoch +Use `.flatMap()` vs `map().flat()` +Use `indexOf`/`lastIndexOf` vs `findIndex`/`findLastIndex` for simple lookups +Use literal property access vs computed property access +Use binary, octal, or hex literals vs `parseInt()` +Use concise optional chains vs chained logical exprs +Use regex literals vs `RegExp` ctor +Use base 10 or underscore separators for number literal object member names +Remove redundant terms from logical exprs +Use `while` loops vs `for` loops if initializer and update aren't needed +No reassigning `const` vars or constant exprs in conditions +No `Math.min`/`Math.max` to clamp values where result is constant +No return values from ctors or setters +No empty character classes in regex literals or destructuring patterns +No `__dirname` and `__filename` in global scope +No calling global object props as fns or declaring fns and `var` accessible outside their block +Instantiate builtins correctly +Use `super()` correctly in classes +Use standard direction values for linear gradient fns +Use valid named grid areas in CSS Grid Layouts +Use `@import` at-rules in valid positions +No vars and params before their decl +Include `var` fn for CSS vars +No `\8` and `\9` escape sequences in strings +No literal numbers that lose precision, configured els, or assigning where both sides are same +Compare string case modifications w/ compliant values +No lexical decls in switch clauses or undeclared vars +No unknown CSS value fns, media feature names, props, pseudo-class/pseudo-element selectors, type selectors, or units +No unmatchable An+B selectors or unreachable code +Call `super()` exactly once before accessing `this` in ctors +No control flow stmts in `finally` blocks +No optional chaining where `undefined` is not allowed +No unused fn params, imports, labels, private class members, or vars +No return values from fns w/ return type `void` +Specify all dependencies correctly in React hooks and names for GraphQL operations +Call React hooks from top level of component fns +Use `isNaN()` when checking for NaN +Use `{ type: "json" }` for JSON module imports +Use radix arg w/ `parseInt()` +Start JSDoc comment lines w/ single asterisk +Move `for` loop counters in right direction +Compare `typeof` exprs to valid values +Include `yield` in generator fns +No importing deprecated exports, duplicate dependencies, or Promises where they're likely a mistake +No non-null assertions after optional chaining or shadowing vars from outer scope +No expr stmts that aren't fn calls or assignments or useless `undefined` +Add `href` attr to `` els and `width`/`height` attrs to `` els +Use consistent arrow fn bodies and either `interface` or `type` consistently +Specify deletion date w/ `@deprecated` directive +Make switch-case stmts exhaustive and limit number of fn params +Sort CSS utility classes +No spread syntax on accumulators, barrel files, `delete` op, dynamic namespace import access, namespace imports, or duplicate polyfills from Polyfill.io +Use `preconnect` attr w/ Google Fonts +Declare regex literals at top level +Add `rel="noopener"` when using `target="_blank"` +No dangerous JSX props +No both `children` and `dangerouslySetInnerHTML` props +No global `eval()` +No callbacks in async tests and hooks, TS enums, exporting imported vars, type annotations for vars initialized w/ literals, magic numbers without named constants, or TS namespaces +No negating `if` conditions when there's an `else` clause, nested ternary exprs, non-null assertions (`!`), reassigning fn params, parameter props in class ctors, specified global var names, importing specified modules, or specified user-defined types +No constants where value is upper-case version of name, template literals without interpolation or special chars, `else` blocks when `if` block breaks early, yoda exprs, or `Array` ctors +Use `String.slice()` vs `String.substr()` and `String.substring()` +Use `as const` vs literal type annotations and `at()` vs integer index access +Follow curly brace conventions +Use `else if` vs nested `if` in `else` clauses and single `if` vs nested `if` clauses +Use `T[]` vs `Array` +Use `new` for all builtins except `String`, `Number`, and `Boolean` +Use consistent accessibility modifiers on class props and methods +Declare object literals consistently +Use `const` for vars only assigned once +Put default and optional fn params last +Include `default` clause in switch stmts +Specify reason arg w/ `@deprecated` directive +Explicitly initialize each enum member value +Use `**` op vs `Math.pow` +Use `export type` and `import type` for types +Use kebab-case, ASCII filenames +Use `for...of` vs `for` loops w/ array index access +Use `<>...` vs `...` +Capitalize all enum values +Place getters and setters for same prop adjacent +Use literal values for all enum members +Use `node:assert/strict` vs `node:assert` +Use `node:` protocol for Node.js builtin modules +Use `Number` props vs global ones +Use numeric separators in numeric literals +Use object spread vs `Object.assign()` for new objects +Mark members `readonly` if never modified outside ctor +No extra closing tags for comps without children +Use assignment op shorthand +Use fn types vs object types w/ call signatures +Add description param to `Symbol()` +Use template literals vs string concatenation +Use `new` when throwing an error +No throwing non-`Error` values +Use `String.trimStart()`/`String.trimEnd()` vs `String.trimLeft()`/`String.trimRight()` +No overload signatures that can be unified +No lower specificity selectors after higher specificity selectors +No `@value` rule in CSS modules +No `alert`, `confirm`, and `prompt` +Use standard constants vs approximated literals +No assigning in exprs +No async fns as Promise executors +No `!` pattern in first position of `files.includes` +No bitwise ops +No reassigning exceptions in catch clauses +No reassigning class members +No inserting comments as text nodes +No comparing against `-0` +No labeled stmts that aren't loops +No `void` type outside generic or return types +No `console` +No TS const enums +No exprs where op doesn't affect value +No control chars in regex literals +No `debugger` +No assigning directly to `document.cookie` +Use `===` and `!==` +No duplicate `@import` rules, case labels, class members, custom props, conditions in if-else-if chains, GraphQL fields, font family names, object keys, fn param names, decl block props, keyframe selectors, or describe hooks +No empty CSS blocks, block stmts, static blocks, or interfaces +No letting vars evolve into `any` type through reassignments +No `any` type +No `export` or `module.exports` in test files +No misusing non-null assertion op (`!`) +No fallthrough in switch clauses +No focused or disabled tests +No reassigning fn decls +No assigning to native objects and read-only global vars +Use `Number.isFinite` and `Number.isNaN` vs global `isFinite` and `isNaN` +No implicit `any` type on var decls +No assigning to imported bindings +No `!important` within keyframe decls +No irregular whitespace chars +No labels that share name w/ var +No chars made w/ multiple code points in char classes +Use `new` and `constructor` properly +Place assertion fns inside `it()` fn calls +No shorthand assign when var appears on both sides +No octal escape sequences in strings +No `Object.prototype` builtins directly +No `quickfix.biome` in editor settings +No redeclaring vars, fns, classes, and types in same scope +No redundant `use strict` +No comparing where both sides are same +No shadowing restricted names +No shorthand props that override related longhand props +No sparse arrays +No template literal placeholder syntax in regular strings +No `then` prop +No `@ts-ignore` directive +No `let` or `var` vars that are read but never assigned +No unknown at-rules +No merging interface and class decls unsafely +No unsafe negation (`!`) +No unnecessary escapes in strings or useless backreferences in regex literals +No `var` +No `with` stmts +No separating overload signatures +Use `await` in async fns +Use correct syntax for ignoring folders in config +Put default clauses in switch stmts last +Pass message value when creating built-in errors +Return value from get methods +Use recommended display strategy w/ Google Fonts +Include `if` stmt in for-in loops +Use `Array.isArray()` vs `instanceof Array` +Return consistent values in iterable callbacks +Use `namespace` keyword vs `module` keyword +Use digits arg w/ `Number#toFixed()` +Use static `Response` methods vs `new Response()` +Use `use strict` directive in script files \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3a70dd7..4460cdc 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ node_modules # Results results.json +benchmarks/**/traces # Testing coverage @@ -42,4 +43,4 @@ yarn-error.log* test-results -playwright-report \ No newline at end of file +.pnpm-store diff --git a/METHODOLOGY.md b/METHODOLOGY.md new file mode 100644 index 0000000..c67f0c8 --- /dev/null +++ b/METHODOLOGY.md @@ -0,0 +1,289 @@ +# Benchmark Methodology + +This document explains how CookieBench measures and evaluates cookie banner performance. Our methodology prioritizes transparency, reproducibility, and real-world user experience. + +## Introduction + +CookieBench measures the performance impact of cookie consent solutions on web applications. We focus on metrics that directly impact user experience, following industry standards like Core Web Vitals and Lighthouse. + +## Measurement Approach + +### Banner Render Time vs Visibility Time + +We track two distinct metrics for banner appearance: + +**Banner Render Time** (Technical Metric): + +- Measures when the banner element first appears in the DOM +- Recorded when the element has dimensions (`width > 0`, `height > 0`) and is not hidden +- Represents technical implementation performance +- This metric is tracked for reference but not used in primary scoring + +**Banner Visibility Time** (User-Perceived Metric): + +- Measures when the banner becomes visible to users +- Uses opacity threshold of **0.5** to account for CSS animations and transitions +- Represents actual user experience - when users can see and interact with the banner +- This metric is used for scoring and primary comparisons + +**Why This Distinction Matters**: + +- A banner that renders instantly but fades in slowly should score differently than one that renders slower but is immediately visible +- CSS animations can delay user-perceived visibility even after technical rendering +- Measuring visibility aligns with Core Web Vitals' focus on user experience + +### Opacity Threshold + +We use an opacity threshold of **0.5** (50% opacity) to determine visibility: + +- An element with opacity ≤ 0.5 is considered not visible to users +- An element with opacity > 0.5 is considered visible +- This accounts for CSS fade-in animations that gradually reveal the banner +- This threshold balances technical accuracy with user perception + +### Measurement Baseline + +All timing measurements start from `navigationStart`: + +- Includes Time to First Byte (TTFB) +- Includes server response time +- Includes network latency +- Aligns with Core Web Vitals measurement standards +- Represents total time from page load initiation to metric completion + +This means results reflect the complete user experience, including server-side performance and network conditions. + +## Network Conditions + +### Current Implementation + +Currently, benchmarks run on **localhost** with **no network throttling**: + +- Ideal network conditions (~9-35ms TTFB) +- No bandwidth limitations +- No latency simulation +- Results reflect optimal performance + +**Impact on Results**: + +- Results represent best-case performance +- Real-world performance will vary based on network conditions +- Differences between implementations are isolated from network variability +- Fair comparison when all implementations tested under same conditions + +### Future Considerations + +We are evaluating network throttling options: + +- **Cable Profile** (5 Mbps, 28ms latency): Minimal impact, maintains speed +- **Fast 3G** (1.6 Mbps, 562ms latency): More realistic, significantly impacts TTFB +- **Slow 4G**: Balanced approach for modern connections + +Any future changes to network conditions will be clearly documented and versioned. + +## Metrics Tracked + +### Primary Metrics (Used for Scoring) + +**Banner Visibility Time**: + +- Time from `navigationStart` until banner opacity > 0.5 +- Primary metric for UX scoring +- Accounts for CSS animations +- Measured in milliseconds + +**Banner Interactive Time**: + +- Time from `navigationStart` until banner buttons become clickable +- Measures when users can actually interact with the banner +- Uses `offsetParent` check to verify clickability + +**Layout Shift Impact**: + +- Cumulative Layout Shift (CLS) caused by banner appearance +- Measures visual stability impact +- Lower is better (0 = no layout shift) + +**Viewport Coverage**: + +- Percentage of viewport covered by banner +- Calculated as: `(visibleArea / viewportArea) * 100` +- Accounts for partial visibility (banners extending beyond viewport) + +**Network Impact**: + +- Total size of banner-related network requests +- Number of network requests +- Download time for banner resources + +### Secondary Metrics (Tracked for Reference) + +**Banner Render Time**: + +- Technical render time (when element appears in DOM) +- Not used for scoring +- Available for technical analysis + +**Banner Hydration Time**: + +- Time from render to interactive: `interactiveTime - renderTime` +- Measures JavaScript execution and event binding time +- Useful for understanding banner implementation performance + +## Scoring Methodology + +### How Scores Are Calculated + +Our scoring system evaluates multiple categories: + +**Performance Score** (40% weight): + +- First Contentful Paint (FCP) +- Largest Contentful Paint (LCP) +- Cumulative Layout Shift (CLS) +- Time to Interactive (TTI) +- Total Blocking Time (TBT) +- Time to First Byte (TTFB) + +**Bundle Strategy Score** (25% weight): + +- Bundle type (Bundled vs IIFE) +- Third-party dependencies +- Bundler type +- TypeScript usage + +**Network Impact Score** (20% weight): + +- Total bundle size +- Third-party size +- Network requests count +- Script load time + +**Transparency Score** (10% weight): + +- Open-source status +- Company information +- Tech stack transparency + +**User Experience Score** (5% weight): + +- Layout stability (CLS) +- Banner render time (uses visibility time) +- Viewport coverage + +### Banner Visibility Time Scoring + +Banner visibility time is scored within the User Experience category: + +- **≤ 25ms**: Excellent (35 points) +- **≤ 50ms**: Very Good (25 points) +- **≤ 100ms**: Good (15 points) +- **≤ 200ms**: Fair (10 points) +- **> 200ms**: Poor (5 points) + +**Note**: Scoring uses `bannerVisibilityTime` (opacity-based), not `bannerRenderTime` (technical). This ensures scores reflect actual user experience. + +## Reproducibility + +### Configuration Requirements + +Each benchmark requires a `config.json` file with: + +- Cookie banner selectors (CSS selectors to detect the banner) +- Service hosts (domains used by the cookie service) +- Tech stack information +- Iteration count + +### Running Benchmarks + +```bash +# Run benchmarks +pnpm benchmark + +# View results +pnpm results +``` + +### What Affects Results + +**Consistent Factors**: + +- Browser engine (Chromium) +- Viewport size (1280x720) +- Detection selectors +- Measurement methodology + +**Variable Factors**: + +- Server performance (if testing SSR) +- System load +- Network conditions (currently localhost) + +**Best Practices**: + +- Run multiple iterations (default: 20) +- Ensure consistent server state +- Clear browser cache between runs +- Use same environment for all comparisons + +## Limitations + +### Current Limitations + +1. **Network Conditions**: + - No throttling means results reflect optimal conditions + - Real-world performance will vary + - Future: Network throttling support + +2. **Measurement Window**: + - Some metrics collected over 1-second window + - CLS may need longer observation periods + - Future: Configurable observation windows + +3. **Banner Detection**: + - Requires accurate CSS selectors + - May miss dynamically loaded banners + - Detection timeout: 10 seconds + +4. **Animation Timing**: + - Opacity threshold may not account for all animation types + - Transform-based animations not measured + - Future: Enhanced animation detection + +### Future Improvements + +- Network throttling support +- More granular animation detection +- Configurable observation windows +- Enhanced banner detection algorithms +- Real-world performance simulation + +## Transparency Statement + +We believe in transparent benchmarking: + +- **Open Methodology**: This document explains exactly how we measure +- **Open Source**: Benchmark code is available for review +- **Reproducible**: Anyone can run the same benchmarks +- **Honest Metrics**: We measure user-perceived visibility, not just technical render time +- **Clear Limitations**: We document what we measure and what we don't + +## Industry Standards Alignment + +Our methodology aligns with: + +- **Core Web Vitals**: User-centric performance metrics +- **Lighthouse**: Measurement approaches and thresholds +- **WebPageTest**: Performance testing practices +- **W3C Performance Timeline**: Standard timing APIs + +We measure what matters to users, not just what's technically possible. + +## Questions or Feedback + +If you have questions about our methodology or suggestions for improvement, please open an issue on our GitHub repository. + +--- + +**Last Updated**: 2025-10-31 +**Version**: 2.0 diff --git a/README.md b/README.md index a4e888f..f203c51 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ A benchmarking tool for measuring the performance impact of cookie consent solut This tool measures various performance metrics when loading web applications with different cookie consent solutions. It helps developers understand the performance implications of their cookie consent implementation choices. +For detailed information about how benchmarks are measured, see [METHODOLOGY.md](./METHODOLOGY.md). + ## Metrics Measured ### Core Web Vitals @@ -17,7 +19,11 @@ This tool measures various performance metrics when loading web applications wit ### Additional Metrics - **Total Time**: Complete page load time - **Script Load Time**: Time taken to load and execute JavaScript -- **Banner Render Time**: Time taken to render the cookie consent banner +- **Banner Render Time**: Technical render time (when element appears in DOM) +- **Banner Visibility Time**: User-perceived visibility time (when opacity > 0.5, accounts for CSS animations) +- **Banner Interactive Time**: Time until banner buttons become clickable + +See [METHODOLOGY.md](./METHODOLOGY.md) for detailed explanation of render time vs visibility time. ### Resource Size Metrics - **Total Size**: Combined size of all resources @@ -41,7 +47,8 @@ This tool measures various performance metrics when loading web applications wit 2. **Performance Metrics**: - Metrics are collected over a 1-second window after page load - Some metrics (like CLS) may need longer observation periods - - Network conditions are not simulated + - Network conditions are not simulated (benchmarks run on localhost) + - See [METHODOLOGY.md](./METHODOLOGY.md) for detailed limitations and measurement approach ## Usage @@ -93,7 +100,7 @@ Each benchmark implementation requires a `config.json` file with the following s - `frameworks`: Array of frameworks used - `bundler`: Build tool used (e.g., webpack, vite) - `packageManager`: Package manager used (e.g., npm, pnpm) - - `bundleType`: Output format (esm, iffe, cjs) + - `bundleType`: Output format (esm, iife, cjs) - `typescript`: Whether TypeScript is used - **source**: Project source information diff --git a/benchmarks/baseline/next-env.d.ts b/benchmarks/baseline/next-env.d.ts index 1b3be08..9edff1c 100644 --- a/benchmarks/baseline/next-env.d.ts +++ b/benchmarks/baseline/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +import "./.next/types/routes.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/benchmarks/baseline/package.json b/benchmarks/baseline/package.json index 973edfd..5eeebf8 100644 --- a/benchmarks/baseline/package.json +++ b/benchmarks/baseline/package.json @@ -3,25 +3,26 @@ "version": "0.1.0", "private": true, "scripts": { - "benchmark": "pnpm exec benchmark-cli benchmark", - "build": "next build ", + "build": "next build", "dev": "next dev --port 3000", "fmt": "biome format . --write", "lint": "biome lint .", "start": "next start" }, "dependencies": { - "next": "16.0.7", - "react": "^19.2.1", - "react-dom": "^19.2.1" + "next": "16.0.1", + "react": "^19.2.0", + "react-dom": "^19.2.0" }, "devDependencies": { "@cookiebench/benchmark-schema": "workspace:*", - "@cookiebench/cli": "workspace:*", "@cookiebench/ts-config": "workspace:*", - "@types/node": "^24.10.1", - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", + "@types/node": "^24.9.2", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", "typescript": "^5.9.3" + }, + "engines": { + "node": ">=20.9.0" } } diff --git a/benchmarks/c15t-nextjs/app/favicon.ico b/benchmarks/c15t-nextjs/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/benchmarks/c15t-nextjs/app/layout.tsx b/benchmarks/c15t-nextjs/app/layout.tsx new file mode 100644 index 0000000..03438c4 --- /dev/null +++ b/benchmarks/c15t-nextjs/app/layout.tsx @@ -0,0 +1,41 @@ +import type { Metadata } from "next"; + +/* + * If you're using Next.js, we recommend installing the @c15t/nextjs package. + * The Next.js package is a wrapper around the React package that provides + * additional features for Next.js. + */ + +import { + ConsentManagerDialog, + ConsentManagerProvider, + CookieBanner, +} from "@c15t/nextjs"; +import type { ReactNode } from "react"; + +export const metadata: Metadata = { + title: "benchmark", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: ReactNode; +}>) { + return ( + + + + + + {children} + + + + ); +} diff --git a/benchmarks/c15t-nextjs/app/page.tsx b/benchmarks/c15t-nextjs/app/page.tsx new file mode 100644 index 0000000..cb954f2 --- /dev/null +++ b/benchmarks/c15t-nextjs/app/page.tsx @@ -0,0 +1,7 @@ +export default function Home() { + return ( +
+

Benchmark

+
+ ); +} diff --git a/benchmarks/c15t-nextjs/config.json b/benchmarks/c15t-nextjs/config.json new file mode 100644 index 0000000..2735964 --- /dev/null +++ b/benchmarks/c15t-nextjs/config.json @@ -0,0 +1,48 @@ +{ + "$schema": "./node_modules/@cookiebench/benchmark-schema/schema.json", + "name": "c15t-nextjs", + "iterations": 20, + "cookieBanner": { + "selectors": [ + "[data-testid=\"cookie-banner-root\"]", + ".c15t-banner", + "[data-c15t-banner]", + ".consent-banner", + "[data-consent-banner]" + ], + "serviceHosts": ["c15t.com", "consent.io"], + "waitForVisibility": true, + "measureViewportCoverage": true, + "expectedLayoutShift": false, + "serviceName": "C15T Next.js" + }, + "techStack": { + "bundler": "rslib", + "bundleType": ["esm", "cjs"], + "frameworks": ["react", "nextjs"], + "languages": ["typescript", "javascript"], + "packageManager": "pnpm", + "typescript": true + }, + "internationalization": { + "detection": "browser", + "stringLoading": "server" + }, + "source": { + "github": "github.com/c15t/c15t", + "isOpenSource": true, + "license": "GPL-3.0-only", + "npm": "@c15t/nextjs", + "website": "https://www.c15t.com" + }, + "includes": { + "backend": ["nodejs", "typescript"], + "components": ["react", "javascript"] + }, + "company": { + "name": "c15t", + "website": "https://c15t.com", + "avatar": "https://zxlypdluowixfd7j.public.blob.vercel-storage.com/c15t-icon-z6gQxO0ogxWgY51dluWPhNfAoPyELT.png" + }, + "tags": ["c15t"] +} diff --git a/benchmarks/c15t-nextjs/next-env.d.ts b/benchmarks/c15t-nextjs/next-env.d.ts new file mode 100644 index 0000000..9edff1c --- /dev/null +++ b/benchmarks/c15t-nextjs/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/benchmarks/c15t-nextjs/next.config.ts b/benchmarks/c15t-nextjs/next.config.ts new file mode 100644 index 0000000..7921f35 --- /dev/null +++ b/benchmarks/c15t-nextjs/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/benchmarks/c15t-nextjs/package.json b/benchmarks/c15t-nextjs/package.json new file mode 100644 index 0000000..95baf82 --- /dev/null +++ b/benchmarks/c15t-nextjs/package.json @@ -0,0 +1,29 @@ +{ + "name": "c15t-nextjs", + "version": "0.1.0", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev --port 3001", + "fmt": "biome format . --write", + "lint": "biome lint .", + "start": "next start" + }, + "dependencies": { + "@c15t/nextjs": "1.7.1", + "next": "16.0.1", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@cookiebench/benchmark-schema": "workspace:*", + "@cookiebench/ts-config": "workspace:*", + "@types/node": "^24.9.2", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=20.9.0" + } +} diff --git a/benchmarks/c15t-nextjs/tsconfig.json b/benchmarks/c15t-nextjs/tsconfig.json new file mode 100644 index 0000000..787e3f6 --- /dev/null +++ b/benchmarks/c15t-nextjs/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@cookiebench/ts-config/nextjs.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/benchmarks/c15t-react/app/favicon.ico b/benchmarks/c15t-react/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/benchmarks/c15t-react/app/layout.tsx b/benchmarks/c15t-react/app/layout.tsx new file mode 100644 index 0000000..0d80c78 --- /dev/null +++ b/benchmarks/c15t-react/app/layout.tsx @@ -0,0 +1,41 @@ +import type { Metadata } from "next"; + +/* + * If you're using Next.js, we recommend installing the @c15t/nextjs package. + * The Next.js package is a wrapper around the React package that provides + * additional features for Next.js. + */ + +import { + ConsentManagerDialog, + ConsentManagerProvider, + CookieBanner, +} from "@c15t/react"; +import type { ReactNode } from "react"; + +export const metadata: Metadata = { + title: "benchmark", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: ReactNode; +}>) { + return ( + + + + + + {children} + + + + ); +} diff --git a/benchmarks/c15t-react/app/page.tsx b/benchmarks/c15t-react/app/page.tsx new file mode 100644 index 0000000..cb954f2 --- /dev/null +++ b/benchmarks/c15t-react/app/page.tsx @@ -0,0 +1,7 @@ +export default function Home() { + return ( +
+

Benchmark

+
+ ); +} diff --git a/benchmarks/c15t-react/config.json b/benchmarks/c15t-react/config.json new file mode 100644 index 0000000..bf1b98c --- /dev/null +++ b/benchmarks/c15t-react/config.json @@ -0,0 +1,48 @@ +{ + "$schema": "./node_modules/@cookiebench/benchmark-schema/schema.json", + "name": "c15t-react", + "iterations": 20, + "cookieBanner": { + "selectors": [ + "[data-testid=\"cookie-banner-root\"]", + ".c15t-banner", + "[data-c15t-banner]", + ".consent-banner", + "[data-consent-banner]" + ], + "serviceHosts": ["c15t.com", "consent.io"], + "waitForVisibility": true, + "measureViewportCoverage": true, + "expectedLayoutShift": false, + "serviceName": "C15T React" + }, + "techStack": { + "bundler": "rslib", + "bundleType": ["esm", "cjs"], + "frameworks": ["react"], + "languages": ["typescript", "javascript"], + "packageManager": "pnpm", + "typescript": true + }, + "source": { + "github": "github.com/c15t/c15t", + "isOpenSource": true, + "license": "GPL-3.0-only", + "npm": "@c15t/nextjs", + "website": "https://www.c15t.com" + }, + "includes": { + "backend": ["nodejs", "typescript"], + "components": ["react", "javascript"] + }, + "internationalization": { + "detection": "browser", + "stringLoading": "server" + }, + "company": { + "name": "c15t", + "website": "https://c15t.com", + "avatar": "https://zxlypdluowixfd7j.public.blob.vercel-storage.com/c15t-icon-z6gQxO0ogxWgY51dluWPhNfAoPyELT.png" + }, + "tags": ["c15t"] +} diff --git a/benchmarks/c15t-react/next-env.d.ts b/benchmarks/c15t-react/next-env.d.ts new file mode 100644 index 0000000..9edff1c --- /dev/null +++ b/benchmarks/c15t-react/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/benchmarks/c15t-react/next.config.ts b/benchmarks/c15t-react/next.config.ts new file mode 100644 index 0000000..7921f35 --- /dev/null +++ b/benchmarks/c15t-react/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/benchmarks/c15t-react/package.json b/benchmarks/c15t-react/package.json new file mode 100644 index 0000000..079c95b --- /dev/null +++ b/benchmarks/c15t-react/package.json @@ -0,0 +1,28 @@ +{ + "name": "c15t-react", + "private": true, + "scripts": { + "build": "next build", + "dev": "next dev --port 3003", + "fmt": "biome format . --write", + "lint": "biome lint .", + "start": "next start --port 3003" + }, + "dependencies": { + "@c15t/react": "1.7.1", + "next": "16.0.1", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@cookiebench/benchmark-schema": "workspace:*", + "@cookiebench/ts-config": "workspace:*", + "@types/node": "^24.9.2", + "@types/react": "^19.2.2", + "@types/react-dom": "^19.2.2", + "typescript": "^5.9.3" + }, + "engines": { + "node": ">=20.9.0" + } +} diff --git a/benchmarks/c15t-react/tsconfig.json b/benchmarks/c15t-react/tsconfig.json new file mode 100644 index 0000000..787e3f6 --- /dev/null +++ b/benchmarks/c15t-react/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "@cookiebench/ts-config/nextjs.json", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "@/*": ["./*"] + } + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/benchmarks/cookie-control/app/favicon.ico b/benchmarks/cookie-control/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/benchmarks/cookie-control/app/layout.tsx b/benchmarks/cookie-control/app/layout.tsx new file mode 100644 index 0000000..beb311a --- /dev/null +++ b/benchmarks/cookie-control/app/layout.tsx @@ -0,0 +1,58 @@ +import type { Metadata } from "next"; +import type { ReactNode } from "react"; + +export const metadata: Metadata = { + title: "benchmark", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: ReactNode; +}>) { + return ( + + + {/* Cookie Control Script */} +