npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@retreejs/babel-plugin-compiler

v0.11.1

Published

Babel plugin that compiles ReactiveNode classes into proxy-free managed classes.

Readme

@retreejs/babel-plugin-compiler

Babel plugin that compiles ReactiveNode subclasses into managed classes so their instances skip the Proxy path. Every member Retree tracks becomes a literal accessor on a per-class prototype, which keeps V8 inline caches monomorphic. Nodes keep the same identity contract: a stable base identity plus a fresh view identity per change.

Install

npm install --save-dev @retreejs/babel-plugin-compiler

Running npm create @retreejs@latest offers the compiler as an opt-in (--compiler) and can add it to a JSON Babel config for you.

Setup

Add the plugin before the decorators plugin so it sees @memo, @ignore, and @link before they are lowered:

{
    "presets": ["next/babel"],
    "plugins": [
        "@retreejs/babel-plugin-compiler",
        ["@babel/plugin-proposal-decorators", { "version": "2023-11" }]
    ]
}

The emitted code imports from @retreejs/core/compiler-runtime, so the installed @retreejs/core must match the compiler's peer range.

Runtime boundary

Only compiler-generated imports load @retreejs/core/compiler-runtime. It registers handler subclasses with core through a small registry that has no runtime imports. Core never imports the compiler runtime. Ordinary handlers carry no compiler fields; compiled handlers share proxy mutation methods, function binding, and dependency tracking.

React integration tests live in samples/04.convex-react-nextjs/app/page.spec.tsx. The tests compile the real sample models with its .babelrc and stub only the Convex transport.

What compiles

A class compiles when it extends ReactiveNode imported from a core module, extends a class in the same file that does, extends a class listed in bases, or applies any Retree decorator. For each compiled class the plugin emits a managed class with:

  • reactive fields, @ignore fields, and @link fields as accessors that call the same runtime paths the Proxy traps use;
  • methods bound to the managed node, and prototype getters that run under the same dependency tracking;
  • memo getters served by the existing runtime decorators, preserving key tracking, other getter decorators, and live prototype replacements.

Classes with #private members, accessor fields, or computed keys stay on the Proxy path. The first instance of a compiled class completes its schema at runtime: fields of an uncompiled base class (one from another package) and properties assigned in a constructor get accessors too. Later instances with symbol-keyed own properties, or whose decorator keys or own keys differ from that first instance, fall back to the Proxy path with a dev warning.

Options

[
    "@retreejs/babel-plugin-compiler",
    {
        "coreModules": ["@retreejs/core"],
        "bases": ["BaseViewModel"],
        "runtimeModule": "@retreejs/core/compiler-runtime"
    }
]
  • coreModules lists the module specifiers that export ReactiveNode and the decorators. Add your own re-export module here.
  • bases names base classes from other files whose subclasses should compile even when they use no decorator.
  • runtimeModule overrides where the emitted helpers are imported from.

Limitations

Fields of a compiled node live on the raw object behind prototype accessors, so Object.keys, spread, for...in, and Object.hasOwn on a managed node do not see them. Use Retree.raw(node) for those. JSON.stringify works: compiled classes get a default toJSON that snapshots every declared field unless the class defines its own. delete node.field and Object.defineProperty on a managed node are not supported.

Assigning a key the class does not declare (node.extra = 1, Reflect.set(node, ...)) lands on the managed object instead of the raw node, so views and serialization never see it; declare the field or assign on Retree.raw(node). Dev builds warn when a view is created for such a node, and Retree.move throws when its destination is a compiled node with no such field.

Test spies work on methods and on arrow-function fields (vi.spyOn(node, "handler")). Getters and methods replaced on a live prototype after the class was defined are picked up for compiled classes; getters inherited from an uncompiled base are captured when the class is defined.