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

visaljs

v0.0.8

Published

Ahead-of-time JavaScript to C compiler: the command line

Readme

visaljs

An ahead-of-time JavaScript to C compiler: visaljs build turns a JavaScript program (ES modules, CommonJS, node_modules) into a native binary.

npm install -g visaljs
visaljs build app.js -o app
./app

In a project, visaljs build with no file finds the entry in package.json, and names the binary after the project:

cd my-api                # package.json: "name": "my-api", "scripts": { "start": "node server.js" }
visaljs build            # 📄 Entry: server.js (package.json "scripts.start") → ./my-api

It takes, in order, the first of these whose file exists: the one command in "bin" (with several, it asks which), the file "scripts.start" runs with node, "main", and index.js. Arguments in the start script aren't built into the binary: give them when you run it.

A Next.js app is detected instead (next in its dependencies). visaljs build runs next build (as a standalone build: next.config stays as it is), then compiles Next's own production server, the one next start runs, with the app's routes built in. The binary serves .next/ and public/ from the working directory, as next start does:

cd my-next-app
visaljs build            # next build, then the server → ./my-next-app
PORT=3000 ./my-next-app  # to deploy: copy my-next-app, .next/ (without .next/cache) and public/

It compiles Turbopack builds (next build's default): tested with the App Router's static and dynamic pages, client components and route handlers (tests/apps/nextjs). Not tested yet: the Pages Router, middleware and next/image. Not supported: a webpack build (next build --webpack); a static export (output: "export") has no server to compile. A vinext app (Next.js on Vite) is built with its own vite build first.

Needs Node 22 or later and a C compiler (cc, gcc or clang). Linux and macOS; on Windows, a clang-family compiler: Zig (winget install zig.zig) or LLVM-MinGW (MSVC isn't supported yet). The C runtime is built on first use and cached in ~/.cache/visaljs. The third-party C libraries (BoringSSL, libuv, zlib, Brotli, zstd) come prebuilt in the package for Linux (x64, arm64; glibc and musl), macOS and Windows x64; on another platform, the first build compiles them too, which takes a minute. VISALJS_PREBUILT=0 builds them anyway.

visaljs build reports each step as it goes:

 ✓ 🔍 Detected GCC 13.3.0  10ms
 ✓ 📦 Rolled 6 modules into a single file (63.7 kB)  37ms
 ✓ 🌳 Parsed 1,988 lines of JavaScript  60ms
 ✓ 🧩 Compiled 1 regular expression  6ms
 ✓ 🔧 Converted 272 functions to IR and optimized them  46ms
 ✓ 📝 Emitted 21,951 lines of C code (1.2 MB)  39ms
 ✓ 📚 Runtime libraries ready (cached ⚡)  39ms
 ✓ 🔨 Compiled the binary (-O2, stripped)  6.57s

 🎉 Built srv in 6.85s: 1.2 MB, fits on a floppy disk 💾
usage: visaljs build [entry.js | project directory] [options]
       visaljs licenses   print the licenses to ship with a binary you distribute

A project (the current directory when none is given) builds its framework's production server: a
vinext app is built with its own `vite build` first, then its server is compiled. Any other
project builds the file its package.json starts: its one "bin" command, the file "scripts.start"
runs with node, or "main"; else index.js. The binary is named after the command or the project.

options:
  -o <file>          output binary
  --emit-c <dir>     stop after C emission
  --dump-ast         print the syntax tree and stop
  --dump-ir          print the IR and stop
  --debug            build without optimization (-O0), keeping symbols and debug info
  --symbols          keep symbols and debug info in the optimized build (for profilers such as perf)
  --no-optimize      skip the IR optimizer (to compare, or to rule it out)
  -j, --jobs <n>     compile at most n C files at once (default: one per processor, memory permitting)
  --embed-source     embed the source text: Function.prototype.toString returns it
  --all-builtins     install every built-in, not only those the program names
  --all-features     link every optional part of the Node modules (node:stream's pipeline,
                     FormData, Brotli…), not only those the program's code names
  --node-env <name>  the value of process.env.NODE_ENV, fixed at build time (default: production);
                     empty: read from the environment at run time
  --no-bundle        skip the bundler: the input is one ES module (a bundle)
  --no-framework-build  a project: compile its existing build output, without building it first
  --script           compile as a classic script (sloppy mode, no bundler)
  -q, --quiet        don't report each step of the build
  --verbose          list each place a warning is about
  --version          print the version
  --help             print this help

Licenses

visaljs is MIT licensed. A binary it builds contains its runtime and third-party code (BoringSSL, libuv, zlib, code ported from Node.js and others), each under its own license, and those licenses require their notices to go with copies of the code. If you distribute a binary, ship what visaljs licenses prints with it, in its documentation or a file beside it:

visaljs licenses > THIRD_PARTY_LICENSES

The package carries the same text as THIRD_PARTY_LICENSES.