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

@bunnybox/cli

v0.11.1

Published

Command line tool for scaffolding, building, and deploying BunnyBox micro-frontends.

Readme

@bunnybox/cli

The bunnybox command line tool: scaffold a micro-frontend, run it locally, and ship it to the control plane.

Install

npm install --save-dev @bunnybox/cli

Or run it without installing:

npx @bunnybox/cli init my-mfe

Requires Node 20.19 or newer.

Getting started

bunnybox init my-mfe && cd my-mfe                    # scaffold a project
npm install
bunnybox dev                                         # run it in a browser

bunnybox login --url https://control-plane.example   # save the connection
bunnybox deploy --version 1.0.0                      # build and register an immutable version
bunnybox promote 1.0.0                               # make it the active one

The first three commands need no account. login points the CLI at a BunnyBox control plane — the service that stores your registered versions and serves the manifest your app fetches — and only the commands that ship something need one.

init generates a working micro-frontend — bunnybox.json, package.json, a tsconfig.json already wired for JSX, and a src/index.tsx you can deploy as-is. It pins @bunnybox/core to the version matching this CLI, since the two release together. Pass --minimal for a bare stub instead of the guided example.

init --app generates an app instead: several micro-frontends laid out into the regions of one page, a shared/ package they can all import, and one lint config covering the tree.

bunnybox init console --app && cd console      # an app, with its first micro-frontend in it
npm install
bunnybox dev

bunnybox init mfes/orders                      # add another; inside an app it wires itself in

Add --skip-mfe to scaffold the app on its own, for one assembled from micro-frontends that already exist.

Shipping it

page writes the page that starts your app in production, and the app commands move every micro-frontend of an app at one version:

bunnybox page --manifest-url https://control-plane.example/v1/acme/apps/console/manifest
bunnybox app deploy --version 1.4.0     # build and register all of them
bunnybox app promote 1.4.0              # make that version live, everywhere

The repository's docs/shipping-an-app.md covers the page's contents, channels in production, and what a release does when it stops half-way.

Commands

| Command | What it does | | ----------------------- | ---------------------------------------------------------------- | | init [dir] | Scaffold a new micro-frontend, or an app with --app | | dev | Build, serve, and rebuild on change, locally | | build | Bundle once to check that it builds | | page | Write the production host page | | deploy --version <v> | Build and register a version. Registered versions are immutable | | promote <version> | Set the active version | | rollback <version> | Repoint the active version | | versions | List registered versions | | app apply <file> | Create or update an App from its spec file | | app validate | Check that the micro-frontends an app composes fit together | | app deploy | Build and register every micro-frontend of an app at one version | | app promote <version> | Set that version live on every one of them | | app rollback <ver> | Put every one of them back | | login | Save control-plane credentials | | config | Inspect and manage saved CLI config |

bunnybox <command> --help prints the flags for any of them.

Running it locally

bunnybox dev builds your micro-frontend, generates the host page and manifest it needs in order to mount, and serves them along with the import map that points @bunnybox/core at the runtime bundle:

bunnybox dev              # starts on 8010, or the next free port
bunnybox dev --port 4000  # honoured exactly; fails if that port is taken

Editing a source file rebuilds and swaps the new code into the running page without a reload. Run it from a directory holding an app.json instead and it composes several micro-frontends — each one read from mfes/<name>/ — into a single page. An optional bunnybox.dev.json supplies canned channels responses and extra context, so a micro-frontend that calls host.request(...) gets an answer locally rather than an error. Its channelsModule key names a module that answers with code instead, for the values JSON can't hold — an AudioContext, a socket, anything with a lifetime.

build is a different thing and worth not confusing with it: it bundles once and reports the size without writing a file, answering only "does this compile and bundle". deploy is what uploads a bundle anywhere.

Checking that a composed app fits together

Each micro-frontend compiles on its own against the channels and events it imports the handles for — there is no map, just files that declare a handle and files that import it. That leaves one question nobody was asking: does the set actually composed work? A part listening for an event no part emits is silent, and silence is the hardest symptom to trace.

bunnybox app validate builds every micro-frontend the app spec names and compares what they publish against what they listen for:

✔ 6 MicroFrontends, 8 seams, every listener has a speaker

app deploy runs the same check between building and uploading — the last moment at which stopping costs nothing — and uploads nothing if it finds a fault. --skip-validation releases anyway.

Channels are listed rather than judged unless the grants are actually known:

★ asks the page for hutch:analyser, hutch:clock, hutch:share, hutch:voice-bus — check the page grants each

A page that builds its channels in code — from an AudioContext, a socket, anything with a lifetime — is not something this command can see, and bunnybox.dev.json is not a stand-in: its channels are canned answers for local development, so a channel nobody bothered to stub would read as a channel nobody grants. The list is the half that can be acted on without inventing the other.

It reads built bundles as text, which is what lets it see the set as deployed rather than as written, and it is a heuristic: it recognises a seam name by its namespace:name shape, so a name assembled at runtime is invisible to it, and a project that names its events without a colon is not checked. A finding is evidence that something is wrong; a clean result is not proof that everything is right. An event nobody listens for is reported as a note rather than a fault, because that is what a broadcast looks like before its listener is deployed.

It finds a use by first binding a local name to a seam name and a kind — reading the channel() or event() call that declared it — and then reading uses through that binding. A handle declared in a file this command builds into the bundle is bound and its uses are seen. A handle declared inside @bunnybox/core itself, which every bundle keeps external, is not: nothing binds its local name, so a use of it is not reported at all, not even as a note. A use whose declaration is external to the bundle is not reported, and widening it would mean parsing what the bundler already left external.

Deploy and promote are separate

deploy registers a version but does not serve it to anyone; promote repoints which version is active. Splitting them is what makes a release reversible: rollback moves the pointer back, and because the shell keys its mounts on the resolved entry URL, only the affected region remounts. Sibling micro-frontends are untouched and the page is never reloaded.

Styles in a file of their own

A micro-frontend is delivered as one ES module, so its styles travel inside that module or they do not arrive. That constrains the artifact, not the source: build and dev load a stylesheet as text, so a component can keep its appearance beside it and still ship as one file.

import css from './styles.css';

export default mfe('orders', () => () => (
  <section class="orders">
    <style>{css}</style>…
  </section>
));

init writes src/env.d.ts declaring *.css for the compiler, since this is something the bundler does that TypeScript cannot see. An existing project needs that file added by hand, once.

Project file

bunnybox.json is the source of truth for the resource, written by init and read by dev, build, and deploy. bunnybox.yaml and bunnybox.yml are read the same way, for a project that would rather keep a comment beside a setting than not explain it — as are app.yaml and app.yml for an app spec:

{
  "tenant": "acme",
  "name": "orders",
  "displayName": "Orders",
  "contractVersion": "^1.0.0",
  "element": "orders",
  "entry": "src/index.tsx",
  "isolation": "inline"
}

License

Apache-2.0. See LICENSE.

The Apache License grants no trademark rights. "BunnyBox" and the BunnyBox logo — which this package embeds and prints as its version banner — are trademarks of Wolfware LLC, and the licence to use the code is not permission to use the name or the mark.