Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

rolldown-plugin-run

Runs your bundled server during rolldown --watch, with zero-downtime restarts: each rebuild boots on a fresh port behind a tiny TCP proxy, and traffic only switches over once the new process actually accepts connections. The old process keeps serving until then — a rebuild never drops in-flight requests or leaves a dead window.

An alternative to rollup-plugin-run, built for Rolldown.

The contract

Your entry must be a server that listens on process.env.PORT.

The plugin decides a build is "ready" by probing that port for a TCP listener. Anything speaking TCP works — HTTP, WebSockets, gRPC — but a script that never listens (a CLI, a one-shot job) will never be considered ready and will not be switched to. For arbitrary scripts, use a plain restart-style runner instead.

Install

pnpm add -D @joylunow/rolldown-plugin-run

Requires Node >= 20.6.

Usage

// rolldown.config.ts
import { defineConfig } from "rolldown";
import run from "@joylunow/rolldown-plugin-run";

export default defineConfig({
  input: "src/server.ts",
  platform: "node",
  output: { dir: "dist" },
  plugins: [run()],
});
// src/server.ts
import { createServer } from "node:http";

createServer((req, res) => res.end("hello")).listen(process.env.PORT);
rolldown --watch
# → serving on http://127.0.0.1:3000

The plugin does nothing outside watch mode, so the same config is safe for production builds.

How it works

  1. On the first writeBundle in watch mode, a raw TCP proxy binds the public port ($PORT or 3000). This is the only address you and your tools ever talk to.
  2. Each build is forked from the entry chunk with PORT set to a random free port.
  3. The plugin probes that port until the child accepts a connection, then atomically points the proxy at it and SIGTERMs the previous process (SIGKILL after 5s if it lingers).
  4. Rebuilds that produce byte-identical output are detected by hashing the chunks and skipped entirely — no pointless restart.
  5. A build that crashes (or never listens) is never switched to; the last good build keeps serving.
  6. Children are forked over an IPC channel and exit themselves if the watcher dies, so no orphan processes survive a killed terminal.

Because the proxy pipes raw TCP, WebSockets and streaming responses pass through untouched.

If the public port is already held by another live process (say, a second watch session), the plugin falls back to a random port and logs the address it actually bound.

Options

run({
  // extra flags for the forked child, e.g. ["--inspect"]
  execArgv: ["--inspect"],
});

The public port is taken from process.env.PORT (default 3000).

Constraints

  • Exactly one entry chunk per build (the plugin errors otherwise).
  • The child inherits the watcher's environment plus its own PORT.
  • The proxy holds early connections for up to 10s while the first build boots, then drops them.

License

MIT

About

rolldown plugin for running nodejs apps

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages