Skip to content
CAI
Software that uses CAICheck a score

preactjs/preact

51.8

Adequate · 25 September 2026

7.3k

lines of production code

JavaScript

primary language

4

measurements over time

CAI band scale
CAI trend line
CAI lens gauges

What this system is

This system is the Preact core library, a lightweight UI framework designed to render component-based user interfaces using a virtual DOM. It provides a React-compatible API layer through its compatibility package, enabling existing React applications and libraries to run on Preact with minimal changes. The system also includes dedicated utilities for debugging, development tools integration, and testing, ensuring a robust ecosystem for building and maintaining frontend applications.

How it got here

2015–2018 — Preact 11 modernization and tooling

8 changes.

This period focused on modernizing the Preact codebase for version 11, introducing a modular architecture with sub-packages and migrating the build and test infrastructure to Vitest, pnpm, and Vite. The work included refactoring the core diffing engine for better maintainability, expanding the demo application with new examples, and establishing comprehensive TypeScript type testing to ensure type safety.

2019 — Hooks API and React compatibility layer

10 changes.

This period focused on introducing the Preact Hooks API with full TypeScript definitions and restructuring debug utilities into a standalone package. A new preact/compat module was added to provide a comprehensive React API compatibility layer, including support for modern React patterns and concurrent features. Extensive test coverage was implemented across core APIs, the compatibility layer, and TypeScript types to ensure stability and ecosystem alignment.

2020–2026 — Build modernization and test expansion

12 changes.

The project modernized its build pipeline by adopting Rollup and Babel for ES module output and introduced a dedicated jsx-runtime sub-package with precompiled JSX support. Significant effort was devoted to expanding test coverage across core rendering, hooks, lifecycles, and devtools integration to ensure robustness and correct behavior.

Features

Demo app migrated to Vite with new and updated examples

The demo application has been rebuilt using Vite, replacing the previous build setup. This migration introduces several new interactive examples, including a contenteditable component, a MobX integration using mobx-react, a Zustand store example, and a Redux Toolkit counter. The existing People Browser demo has been integrated and updated to use TypeScript and MobX State Tree for state management, while the Suspense and lazy-loading demos have been expanded to demonstrate nested lazy components and error boundaries. Additionally, the Context and Devtools demos have been added to showcase React/Preact context usage and profiling capabilities.

demo · high confidence

Initial release of the Preact core library

This change introduces the foundational source files for the Preact library, establishing the core rendering engine and component model. It defines the \Component\ base class with \setState\ and \forceUpdate\ methods, the \VNode\ structure for the virtual DOM, and the \createElement\ and \cloneElement\ APIs for building UI trees. The implementation includes the diffing algorithm, context management via \createContext\, and support for portals through \createPortal\. Additionally, it provides comprehensive TypeScript type definitions (\index.d.ts\, \dom.d.ts\) to ensure type safety for consumers.

src · high confidence

Introduce Preact 11 devtools integration and custom hook naming

The devtools module now initializes the Preact 11.0.0-rc.2 devtools bridge, using globalThis with a window fallback to register the library. It also exposes an addHookName function that allows developers to customize the display name of useState, useReducer, or useRef hooks in the devtools panel.

devtools/src · high confidence

Introduce Preact Hooks API with TypeScript definitions

This change adds the core implementation and TypeScript definitions for the Preact Hooks API. It introduces support for state and side-effect management through hooks such as useState, useReducer, useEffect, useLayoutEffect, useRef, useContext, useMemo, useCallback, useImperativeHandle, useDebugValue, useErrorBoundary, and useId. The implementation hooks into Preact's lifecycle (diff, render, commit, unmount) to manage hook state, effect ordering, and cleanup, providing a React-compatible API for functional components.

hooks/src · high confidence

Introduce dedicated jsx-runtime sub-package

The JSX runtime is now available as a standalone sub-package (\jsx-runtime\) with its own implementation and TypeScript definitions. This provides a dedicated, optimized entry point for Babel's automatic JSX runtime API (\jsx\, \jsxs\, \jsxDEV\) and adds support for precompiled JSX transforms via new helper functions (\jsxTemplate\, \jsxAttr\, \jsxEscape\).

jsx-runtime/src · high confidence

Introduce dedicated preact/debug package with component stack and prop validation

The debug utilities have been restructured into a standalone \preact/debug\ package, introducing a new \component-stack.js\ module that tracks component ownership and renders detailed stack traces (including file/line info via \@babel/plugin-transform-react-jsx-source\) for errors and warnings. A new \check-props.js\ module provides a simplified, dependency-free implementation of \prop-types\ validation that logs failures once per message. The package exports helper functions like \captureOwnerStack\, \getDisplayName\, and \resetPropWarnings\ to support debugging and devtools integration, while \initDebug()\ hooks into Preact's lifecycle options to enforce these checks during rendering.

debug/src · high confidence

Introduce preact/compat module for React API compatibility

A new \preact/compat\ module has been added to provide a React-compatible API layer, allowing libraries and applications built for React to run on Preact. This module exports React-standard components and hooks such as \Component\, \PureComponent\, \memo\, \forwardRef\, \Suspense\, and \lazy\, alongside React-specific hooks like \useTransition\, \useDeferredValue\, and \useSyncExternalStore\. It also includes utility functions like \Children.map\, \createPortal\, and \flushSync\, and implements necessary behaviors such as \className\ normalization, \UNSAFE\\\ lifecycle aliases, and event propagation shims to ensure compatibility with existing React ecosystems.

compat/src · high confidence

New compat entry points for client, server, scheduler, and JSX runtimes

The compat package now exposes dedicated entry points for \client\, \server\, \scheduler\, and \jsx-runtime\ (including \jsx-dev-runtime\), along with \test-utils\. The \client\ entry provides \createRoot\ and \hydrateRoot\ wrappers to align with React's concurrent API, while the \server\ entry re-exports \renderToString\, \renderToPipeableStream\, and \renderToReadableStream\ from \preact-render-to-string\ with improved error messaging if the dependency is missing. The \scheduler\ entry shims React's unstable priority APIs, and the JSX runtime entries ensure the correct Preact runtime is used when an alias is present. These changes support modern React patterns and tooling compatibility.

compat · high confidence

Architecture

Refactor core diffing engine into modular files

The core diffing logic has been reorganized from a single monolithic file into four distinct modules: \index.js\ (main diff loop), \children.js\ (child reconciliation), \props.js\ (property and event handling), and \catch-error.js\ (error boundary propagation). This structural change improves code maintainability and tree-shakeability without altering the external API or runtime behavior.

src/diff · high confidence

Behavioural changes

Add WeakKey type definitions

A new \types/weak-key.d.ts\ file has been added to define the \WeakKey\ type and the \WeakKeyTypes\ interface, enabling proper type checking for weak keys in the application.

types · medium confidence

Adopts modern Rollup and Babel build pipeline

The build system has been replaced with a modern setup using Rollup and Babel, removing previous UMD and CommonJS output formats in favor of ES modules. This change introduces a custom Babel plugin to optimize rest parameter handling and integrates Terser for minification, resulting in a streamlined build process that targets specific browser versions.

scripts · high confidence

Build fails if compatibility files are missing from package.json

A new configuration script (config/compat-entries.js) now validates that all JavaScript files in the compat directory are listed in the package.json files entry. If any file is missing, the build process will fail with an error, ensuring that compatibility assets are correctly included in the published package.

config · high confidence

Extracted test utilities for act, setupRerender, and teardown

The test utilities previously embedded in the main library have been extracted into a dedicated \test-utils\ package. This change introduces explicit exports for \act\, \setupRerender\, and \teardown\, providing users with a cleaner separation between production code and testing infrastructure. The \act\ function now supports nested calls and asynchronous callbacks, ensuring that effects and rerenders are properly flushed and cleaned up, while \setupRerender\ allows manual draining of the pending render queue and \teardown\ resets Preact's internal test state.

test-utils/src · high confidence

Migrate to pnpm workspaces and Vitest with oxlint/oxfmt tooling

The repository has switched its package manager from npm to pnpm, organizing the codebase into a pnpm workspace that includes the root library and the demo application. The test runner has been migrated from Mocha to Vitest, and the build/test configuration now uses oxlint and oxfmt for linting and formatting, replacing the previous ESLint and Prettier setup. This change also introduces a new \mangle.json\ configuration to control property mangling for minified builds and updates the development environment to require Node.js 22.

(repo-wide) · high confidence

Updated pre-commit hook to use nano-staged

The pre-commit hook in the .husky directory has been updated to execute \pnpm exec nano-staged\ instead of the previous command. This change aligns with the migration to Husky v9 and the replacement of npm-run-all and lint-staged, ensuring that staged files are processed correctly using the new nano-staged tooling within the pnpm workspace.

.husky · high confidence

Test coverage

Added Preact fixture for testing; Added TypeScript type tests for Preact compat; Added TypeScript type tests for Preact components, VNodes, and custom elements; Added browser tests for Preact hooks; Added comprehensive test coverage for Preact debug mode; Added test coverage for component lifecycle methods; Added test coverage for core Preact APIs; Added test for build artifact exports; Added test utility for scheduling effect assertions; Added tests for JSX runtime functions and precompiled JSX support; Added tests for devtools hook naming and test-utils act/rerender behavior; Expanded browser test coverage for core rendering and hydration behaviors; Expanded test coverage for preact/compat browser APIs; New test utility modules for DOM validation and lifecycle spying.

Dependencies

Preact 11.0.0-rc.2: Sub-package exports and modernized build tooling

This release introduces a comprehensive package structure for Preact 11, defining individual sub-packages for compat, debug, devtools, hooks, jsx-runtime, and test-utils, each with its own package.json and peer dependency on preact ^10.0.0. The main package.json is updated to version 11.0.0-rc.2 and implements a detailed Node.js 'exports' map to expose these sub-packages (including compat/client, compat/server, and compat/scheduler) alongside the core library. The build tooling has been modernized by replacing Babel, UglifyJS, and JSHint with Rollup, esbuild, oxlint, and oxfmt, and the test suite has migrated from Mocha to Vitest with Playwright for browser testing. The demo application has been updated to use Vite and includes examples for Redux, MobX, Zustand, and other state management libraries.

(dependencies) · high confidence

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

How this codebase got here

This is the PUBLIC form of this artifact. Findings are listed in full, but the details of SECURITY findings — which rule fired, in which file, on which line, and how to fix it — are deliberately withheld, and any secret-scanner results are excluded entirely. Where detail is absent here it was REMOVED FOR PUBLICATION; it is not missing from the analysis. The complete artifact is available from the repository owner.

Score

  • CAI 40 → 52 (+11.9)
  • Rubric changed (rubric-2026.08.15 → rubric-2026.09.15) — scores are not directly comparable.

Lenses

  • Code Health 51 → 52 (+0.5)
  • Architecture 56 (new)
  • Maturity 58 → 58 (-0.0)
  • Readiness 27 → 47 (+20.2)
  • Security 53 → 80 (+27.2)

Resolved (94)

  • Change coupling: check-props.js ↔ debug.js (debug/src/check-props.js)
  • Change coupling: children.js ↔ index.js (src/diff/children.js)
  • Change coupling: client.js ↔ client.mjs (compat/client.js)
  • Change coupling: debug.js ↔ index.js (debug/src/debug.js)
  • Change coupling: index.d.ts ↔ index.js (test-utils/src/index.d.ts)
  • Change coupling: index.js ↔ index.js (src/diff/index.js)
  • Change coupling: index.js ↔ render.js (src/diff/index.js)
  • Critical CVE: [GHSA redacted] (package-lock.json)
  • Critical CVE: [GHSA redacted] (demo/package-lock.json)
  • Critical CVE: [GHSA redacted] (package-lock.json)
  • Critical CVE: [GHSA redacted] (package-lock.json)
  • Critical CVE: [GHSA redacted] (package-lock.json)
  • Dimension evaluation failed
  • FileTooLong: diff/children.js (src/diff/children.js)
  • FileTooLong: diff/index.js (src/diff/index.js)
  • FileTooLong: src/debug.js (debug/src/debug.js)
  • FileTooLong: src/index.js (hooks/src/index.js)
  • High CVE: [GHSA redacted] (package-lock.json)
  • High CVE: [GHSA redacted] (demo/package-lock.json)
  • High CVE: [GHSA redacted] (package-lock.json)
  • …and 74 more

New (89)

  • Base-context workflow trigger runs with an unscoped token
  • Coverage not measured — JavaScript/TypeScript suite
  • Documentation: no installation or build instructions (README.md)
  • FunctionTooLong: children.constructNewChildrenArray (src/diff/children.js)
  • FunctionTooLong: debug.initDebug (debug/src/debug.js)
  • FunctionTooLong: index.diff (src/diff/index.js)
  • FunctionTooLong: index.diffElementNodes (src/diff/index.js)
  • High CVE: [GHSA redacted] (pnpm-lock.yaml)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • High: security finding (details withheld)
  • Hotspot: jsx-runtime/src/index.js (jsx-runtime/src/index.js)
  • No assertions: should handle a promise thrown from a layout effect (compat/test/browser/suspense.test.jsx)
  • No assertions: should not crash when effect throws and component is unmounted by render(null) during flush (hooks/test/browser/useEffect.test.jsx)
  • No checksums published for release artifacts
  • No dependency advisory monitoring
  • Off-boarding risk: anonymized user #1
  • Outdated (npm): @material-ui/core
  • …and 69 more

Changes since last survey

  • 111 commits — 91 feature/other, 20 fixes

By area

  • (repo) — 56 commits
  • (root) — 15 commits
  • compat/src — 8 commits
  • src/diff — 8 commits
  • .github/workflows — 6 commits
  • compat/test — 4 commits
  • hooks/src — 3 commits
  • src/dom.d.ts — 3 commits
  • debug/src — 2 commits
  • jsx-runtime/src — 2 commits
  • demo/package-lock.json — 1 commit
  • src/constants.js — 1 commit
  • src/create-portal.js — 1 commit
  • src/jsx.d.ts — 1 commit

Notable commits

  • fix: FIx parameter description in getHookState function
  • fix: Fix compat element tag validation
  • fix: Fix compressed size comparison with pnpm
  • fix: Fix hook state loss when Suspense re-suspends
  • fix: Fix perf regression from the attribute/unmount loop golfing
  • fix: Merge branch 'main' into JoviDeCroock/fix-catch-error-dirty-ancestor
  • fix: Merge branch 'main' into JoviDeCroock/fix-error-boundary-retry-loop
  • fix: Merge branch 'main' into JoviDeCroock/fix-mathml-token-elements
  • fix: Merge pull request #5206 from upupming/fix/demo-declare-sass
  • fix: Merge pull request #5226 from preactjs/JoviDeCroock/fix-catch-error-dirty-ancestor
  • fix: Merge pull request #5227 from preactjs/JoviDeCroock/fix-error-boundary-retry-loop
  • fix: Merge pull request #5228 from preactjs/JoviDeCroock/fix-mathml-token-elements
  • fix: Merge pull request #5239 from preactjs/fix/suspense-preserve-mounted-hooks
  • fix: Merge pull request #5254 from preactjs/JoviDeCroock/fix-compressed-size-build
  • fix: Revert "Golf encodeEntities down to chained replaces"
  • fix: fix(demo): declare the sass dependency vite's scss compilation needs
  • fix: fix: anchor the MathML token element regex
  • fix: fix: keep the pending error flag until the boundary's retry render
  • fix: fix: only treat components with error handlers as error boundaries
  • fix: fix: resolve preact dist build in minified tests
  • …and 91 more

Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.

Survey your own repository

preactjs/preact was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.

About this page

  • The score is its most recent published measurement, taken on 25 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
  • Measured at commit 8101ff821690817c7786739c317af215c62a0cff — the exact code this score is about.
  • Scored under rubric-2026.09.15 — the same rubric and the same method as every other entry in this index.
  • Measured by watchdog.canine.dev using codehealth-analyzer preprod-dd72cc24c749.