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

@entryscape/blocks-bundler

v0.4.0

Published

Convention-based Rollup plugin + CLI that bundles an EntryScape Blocks source tree into a single window.__entryscape_config script.

Readme

@entryscape/blocks-bundler

Convention-based Rollup plugin + CLI that bundles an EntryScape Blocks source tree into a single IIFE script which assigns to window.__entryscape_config.

Quickstart

From an empty directory on a fresh machine — no install needed, npx fetches the package on demand:

mkdir my-blocks && cd my-blocks
npx @entryscape/blocks-bundler create

(Equivalent on pnpm: pnpm dlx @entryscape/blocks-bundler create.)

If the package is already a devDependency in the project, use the locally installed binary instead:

pnpm add -D @entryscape/blocks-bundler
pnpm exec blocks-bundler create

This bootstraps a full project: the source layout (src/config.js, src/collections.js, src/style.css, src/nls.js, src/blocks/example.js, plus a src/README.md orientation note), a top-level README.md and .gitignore, a package.json with dev / build / serve scripts, and a minimal demo/index.html that loads the built bundle alongside the EntryScape Blocks CDN runtime. Existing files are never overwritten. Pass --name <pkg> to set the package.json name (defaults to the cwd basename). Pass --src <dir> to put the whole source tree under a directory other than src/; per-file flags (--config, --collections, --style, --nls, --blocks-dir) further override individual paths.

After scaffolding:

pnpm install
pnpm start  # runs dev + serve together; demo at http://localhost:5173/demo/

(pnpm dev and pnpm serve are also available individually.)

Or lay out your source like this by hand (all roots are optional):

src/
  config.js          export default { namespaces, bundles, ... }
  collections.js     export default [ ...collections ]
  style.css          (read as a string and attached as `style:`)
  nls.js             export default { en: { ... }, sv: { ... } }
  blocks/
    myBlock.js       export default { extends: "template", template: ... }
    other/
      another.js     export default { ... }
    scripts.js       (helper module; not registered as a block)

In each block file omit the block: property — the bundler injects it from the filename. extends: can be a built-in name ("template", "searchList", ...) or an imported block module:

import myBlock from '../myBlock.js';
export default { extends: myBlock, template: `...` };

The build resolves the imported reference to a string at compile time, so the final bundle has extends: "myBlock" directly — no runtime helpers.

Building

Both paths produce the same three files (pick by use case):

  • dist/blocks.js — readable IIFE, templates as strings.
  • dist/blocks.precompiled.js — readable IIFE with handlebar templates precompiled (see below).
  • dist/blocks.min.js — terser-minified, with precompiled templates.

One-off build with npx (no install)

If all you have is a source tree and you just want to (re)build it, npx works without any package.json or node_modules:

npx @entryscape/blocks-bundler                 # bundle src/ into dist/
npx @entryscape/blocks-bundler --watch         # rebuild on changes
npx @entryscape/[email protected]           # pin a specific version

Equivalent on pnpm: pnpm dlx @entryscape/blocks-bundler.

Day-to-day development with a devDependency

For inner-loop dev (frequent builds, watch mode, parallel serve) prefer a local install — faster startup, lockfile-pinned transitives, and works with editor/IDE script pickers:

pnpm add -D @entryscape/blocks-bundler

Then in package.json:

{
  "scripts": {
    "build":       "blocks-bundler",
    "build:watch": "blocks-bundler --watch"
  }
}

(The create subcommand scaffolds this layout for you, along with dev / serve / start scripts and the matching devDeps.)

When to use which

| Use case | Recommended path | |---------------------------------------------------|-------------------------------------------------| | First-time bootstrap of a project | npx … create | | Recovering source from a built bundle | npx … disassemble | | One-off rebuild without committing to a devDep | npx @entryscape/blocks-bundler | | CI sanity check / version-pinned reproducible run | npx @entryscape/blocks-bundler@<version> | | Day-to-day dev (watch, hot-reload, concurrent serve) | devDep + pnpm dev / pnpm start | | CI build in the project's own repo | devDep (lockfile-pinned) + pnpm build | | Editor / IDE-driven build | devDep (resolved via node_modules/.bin/) |

Load dist/blocks.js from your HTML alongside the EntryScape Blocks runtime — see demo/index.html (scaffolded by create) for the minimal pattern.

CLI options

blocks-bundler [command] [options]

Commands:
  (default)              Bundle the source tree.
  create                 Scaffold the default source structure.
  disassemble [path]     Inverse of bundle: turn a built blocks.js back into
                         editable source (default path: dist/blocks.js).

Options:
  -w, --watch            Rebuild on source changes.
      --no-minify        Skip the minified bundle.
      --no-precompile    Skip handlebars template precompilation. Drops the
                         precompiled bundle and makes the minified bundle a
                         plain (runtime-compiled) one.
      --outfile <path>   Readable bundle output (default: dist/blocks.js).
      --min-outfile <p>  Minified bundle output (default: <outfile>.min.js).
                         Built with precompiled templates unless
                         --no-precompile.
      --precompiled-outfile <p>
                         Readable bundle with precompiled handlebar templates
                         (default: <outfile>.precompiled.js).
      --banner <text>    Banner comment for all bundles (default: empty).
      --src <dir>        Source root (default: src). Sets the parent for
                         config/collections/style/nls/blocks unless those
                         are overridden by their per-file flags below.
      --blocks-dir <d>   Blocks source directory (default: <src>/blocks).
      --config <file>    Config file (default: <src>/config.js).
      --collections <f>  Collections file (default: <src>/collections.js).
      --style <file>     Style file (default: <src>/style.css).
      --nls <file>       NLS (i18n strings) file (default: <src>/nls.js).
  -h, --help             Show this help.

Conventions

| Path | Role | |-------------------------------------|-----------------------------------------------------| | src/config.js | export default { ... } spread into the bundle | | src/collections.js | export default [ ... ] attached as collections: | | src/style.css | Read as a string, attached as style: | | src/nls.js | export default { ... } attached as nls: (i18n) | | src/blocks/<name>.js | One block; name = filename without .js | | src/blocks/<group>/<name>.js | Subdirectories are organization only, no namespacing | | src/blocks/scripts.js | Shared helpers; not registered as a block | | src/blocks/**/scripts/*.js | Entire scripts directories are skipped |

Plugin API

If you need a custom rollup.config.js, import the plugin directly:

import blocksBundler from '@entryscape/blocks-bundler';

export default {
  input: 'virtual:blocks-bundler-entry',
  plugins: [blocksBundler({ /* override defaults if needed */ })],
  output: { file: 'dist/blocks.js', format: 'iife' },
};

Pass precompile: true to emit precompiled handlebar templates (see "Template precompilation"); templateProps: [...] overrides the list of property names treated as templates.

Output shape

window.__entryscape_config = [].concat(window.__entryscape_config)
  .filter(Boolean)
  .concat([{ ...config, style: "...", collections, nls, blocks: [...] }]);

Blocks are toposorted so each block's extends target appears before it. Cyclic extends chains fail the build with a clear error.

Template precompilation

Blocks normally compiles handlebar templates at render time with handlebars.compile(), which creates functions dynamically — blocked under a CSP without unsafe-eval. The precompiled bundles avoid this: at build time, every known template property in a block definition (template, htemplate, rowhead, rowexpand, listhead, listbody, listempty, listplaceholder, expandhead, expandbody, and the templateFilter family — also inside a nested templates: {} object) whose value is a plain string/template literal is replaced with a tagged envelope:

rowhead: {
  type: "handlebars",
  spec: { compiler: [8, ">= 4.3.0"], main: function (...) { ... }, useData: true },
}

spec is untouched handlebars.precompile() output; a Blocks version that supports precompiled templates detects the non-string value and renders it with handlebars.template(spec) — no compiler, no eval. The type tag exists so future template languages can be added alongside handlebars.

Notes:

  • Helper resolution in handlebars happens at render time, so precompiling works even though blocks-as-helpers (and prop, ifprop, ...) are only registered once Blocks is running.
  • The spec is tied to handlebars compiler revision 8 (handlebars

    = 4.3); Blocks ships a compatible 4.7.x runtime.

  • Template values that are not plain literals (e.g. a template literal with ${} interpolation, or a computed expression) are left as strings with a build warning — Blocks compiles those at runtime as before.
  • Older Blocks versions that expect strings should be served the regular dist/blocks.js.

Disassembling a built bundle

blocks-bundler disassemble [path] is the inverse of the build: it evaluates an existing bundle (default dist/blocks.js) in a Node vm sandbox, captures the resulting window.__entryscape_config, and writes the pieces back out as src/config.js, src/collections.js, src/style.css, src/nls.js, and one src/blocks/<name>.js per block. When a block's extends: value matches another local block in the same bundle, an import statement is reconstructed so the rebuild preserves the topological order.

Precompiled bundles (dist/blocks.precompiled.js, and dist/blocks.min.js unless built with --no-precompile) cannot be disassembled — the template sources are gone from them. Disassemble the regular dist/blocks.js; a minified bundle works only if it was built without precompilation.

blocks-bundler disassemble                 # default: dist/blocks.js
blocks-bundler disassemble path/to/bundle.js
blocks-bundler disassemble bundle.js --force     # overwrite existing

Skips existing files by default (use --force to overwrite). Honours the same --src plus per-file flags (--config/--collections/--style/--nls/--blocks-dir) as create, so disassemble --src sources puts every recovered file under sources/ instead of src/. The output is "flat string-extends" form for any extends: values that don't match another local block (e.g. built-in names like "template").

disassemble writes only the source tree (src/*); it does not scaffold package.json, the demo page, or other project-shell files. That keeps each subcommand single-purpose. To bootstrap a fresh project from just a bundle, combine the two — both subcommands are idempotent and compose cleanly:

# Order A: shell first, then real data
mkdir my-project && cd my-project
npx @entryscape/blocks-bundler create
npx @entryscape/blocks-bundler disassemble path/to/bundle.js --force

# Order B: real data first, then shell
mkdir my-project && cd my-project
npx @entryscape/blocks-bundler disassemble path/to/bundle.js
npx @entryscape/blocks-bundler create

In Order A, --force lets the real bundle data overwrite the example src/config.js / src/collections.js / src/style.css that create scaffolded. In Order B, create skips the already-populated source files and only fills in the project shell (plus src/blocks/example.js, which sits harmlessly alongside the real blocks — delete it if it's noise).