Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .eslintrc.js

This file was deleted.

9 changes: 7 additions & 2 deletions .release-it.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
{
"hooks": {
"before:init": ["npm run lint", "npm run test"],
"before:init": [
"npm run check:types",
"npm run lint",
"npm run test",
"npm run build-binary"
],
"after:bump": "npm run prerelease",
"after:git:release": "echo After git push, before github release"
}
}
}
221 changes: 158 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,63 +1,158 @@
## General introduction
> A command line tool to serve local directory with http protocol

## Installation

```text
# Install globally:
npm i instantly_http -g
```

## Options

```bash
instant_http --help
Usage: instant_http [global options]

Options:
-V, --version output the version number
-p --port [port] To point which port to use as the server address. (default: "9090")
-d --dir [dir] Dir to serve (default: "/home/frank/code/InstantHttp")
-pt --proxyTarget [proxyTarget] Where the delegated communication targets to
-pp --proxyPattern [proxyPattern] URL matcher to be used to identify which url to proxy
-m --mode [mode] Which mode to use (default: "NORMAL")
-i --indexFile [indexFile] Index File location(relative to --dir) (default: "index.html")
-q --quiet [quiet] Set it to false to see more debug outputs (default: false)
-h, --help display help for command
```

## Usages

### MJS/TS
```javascript
import {run} from 'instantly_http';
```

### CJS
```javascript
const {run} = require('instantly_http');
```

### As a binary
```bash
./instantHttp --port=8080 --proxyTarget=http://google.com --proxyPattern=/proxy
```

## Build for portable binary
After checkout then install this repository, you can then try below commands to get an executable binary.

```
npm run build-binary
```

> [pkg](https://www.npmjs.com/package/pkg) is used as the package utility, please check pkg's document in order to build runnable binaries as you want.


## Test

```bash
npm run test
```

## Breaking Changes
- **vNext**: Removed `--open` option and chrome launcher functionality. Server URL is now displayed prominently in terminal for easy clicking.
# InstantHttp

> Static file server & reverse proxy with optional HTTPS — zero config, single binary.

[![npm version](https://img.shields.io/npm/v/instantly_http)](https://www.npmjs.com/package/instantly_http)
[![license](https://img.shields.io/npm/l/instantly_http)](https://github.com/pillsilly/InstantHttp/blob/master/LICENSE)

Serves a local directory over HTTP, proxies requests to a backend, or does both in static-first hybrid mode. Ships as an npm package, a CLI, or a standalone binary.

## Why

Frontend development means serving built artifacts against a backend you don't control — a staging API, a production backend, or a colleague's dev server. Writing a throwaway Express script each time, wiring up CORS, compression, and a proxy middleware is boilerplate that adds nothing to your actual work.

InstantHttp collapses that into a single command. No config files. No scaffolding. Point it at a directory, optionally give it a backend to proxy to, and you're done.

Two scenarios where this matters:

**Frontend-to-backend pairing.** You have a React, Vue, or Svelte build output and need to test it against a specific backend. `--proxyStaticFileWise` serves your static files first and proxies API calls to the backend. Switch backends by changing one flag — no code changes, no restart dance.

**Static apps that need HTTP.** Some HTML+CSS+JS prototypes, spec pages, or tool UIs only work over HTTP (service workers, `fetch` to local resources, ES modules that need a real origin). `instant_http --dir ./demo` is zero-code — faster than pulling a full dependency tree.

The binary build goes a step further: a single self-contained executable you can drop onto a CI runner or share with a teammate who doesn't have Node.

## Installation

```bash
npm i -g instantly_http
```

Or run without installing:

```bash
npx instantly_http --port 8080
```

## Quick start

```bash
# Serve current directory
instant_http

# Serve another directory on a different port
instant_http --dir ./public --port 3000

# SPA mode — all unmatched routes fall back to index.html
instant_http --mode SPA --dir ./dist

# Static files first, proxy everything else to backend
instant_http --proxyStaticFileWise --proxyTarget http://localhost:3001

# HTTPS with default bundled cert/key
instant_http --https
```

## CLI reference

| Option | Default | Description |
|---|---|---|
| `-p, --port` | `9090` | Server port |
| `-d, --dir` | `cwd` | Directory to serve |
| `-m, --mode` | `NORMAL` | Server mode: `NORMAL`, `SPA`, or `PROXY_STATIC_FILE_WISE` |
| `-i, --indexFile` | `index.html` | Index file (relative to `--dir`) for SPA fallback |
| `-t, --proxyTarget` | — | Backend URL to proxy requests to |
| `-P, --proxyPattern` | — | URL pattern to match for proxying (supports `*` wildcard) |
| `--proxyStaticFileWise` | `false` | Serve static files first, proxy everything else |
| `--https` | `false` | Enable HTTPS |
| `--httpsKey` | — | Path to HTTPS private key (defaults to bundled `server.key`) |
| `--httpsCert` | — | Path to HTTPS certificate (defaults to bundled `server.cert`) |
| `-q, --quiet` | `true` | Suppress request logs (`false` for debug output) |
| `-V, --version` | — | Print version |
| `-h, --help` | — | Print help |

## Modes

### NORMAL (default)

Serves static files from `--dir`. When a request matches a directory, renders a clickable directory listing. Missing files return a 404.

### SPA

Single Page Application mode. Serves static files AND falls back to `--indexFile` for any route that doesn't match a file on disk. Use this for React, Vue, or Angular apps with client-side routing.

### PROXY_STATIC_FILE_WISE

Hybrid mode. Serves static files from `--dir` first. Any request that doesn't match a static file gets proxied to `--proxyTarget`. Supports WebSocket upgrade for HMR/dev servers. `/` maps to `--indexFile`.

> **Note:** `--proxyStaticFileWise` reuses `--proxyTarget` and is mutually exclusive with `--proxyPattern`.

## Proxy

Two proxy strategies are available:

**Pattern-based** (`--proxyPattern` + `--proxyTarget`) — only requests matching the pattern are proxied. Everything else is served as static files.

```bash
# Proxy /api/* requests to backend, serve everything else from ./public
instant_http --dir ./public --proxyTarget http://localhost:3001 --proxyPattern /api/*
```

**Static-first** (`--proxyStaticFileWise`) — try the file system first, then proxy the rest.

```bash
# Dev mode: serve Vite build, proxy everything else (HMR, API) to dev server
instant_http --proxyStaticFileWise --proxyTarget http://localhost:5173
```

Proxy headers (`x-forwarded-for`, `x-forwarded-host`, `x-forwarded-proto`, `via`) are stripped from upstream requests to avoid proxy detection. The `referer` and `origin` headers are rewritten to match the target.

## HTTPS

Enable with `--https`. Uses bundled `server.key` and `server.cert` for development — **not for production**. Provide your own cert with `--httpsKey` and `--httpsCert`:

```bash
instant_http --https --httpsKey ./privkey.pem --httpsCert ./fullchain.pem
```

## Programmatic API

```js
// ESM
import { run } from 'instantly_http';

// CommonJS
const { run } = require('instantly_http');

const server = run({
port: '8080',
dir: './public',
mode: 'SPA',
indexFile: 'index.html',
https: true,
// httpsKey: './key.pem',
// httpsCert: './cert.pem',
});

// server is an http.Server or https.Server instance
```

The `run()` function returns a Node.js `http.Server` (or `https.Server`) instance. Call `server.close()` to shut down.

## Build standalone binary

```bash
git clone https://github.com/pillsilly/InstantHttp
cd InstantHttp
npm install
npm run build-binary
```

Outputs a self-contained `instant_http` binary in `./executable/` — no Node.js runtime needed. Uses [pkg](https://www.npmjs.com/package/pkg) under the hood.

## Test

```bash
npm test
```

Coverage targets: 100% branches, functions, lines, and statements.
6 changes: 0 additions & 6 deletions babel.config.js

This file was deleted.

13 changes: 6 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"name": "instantly_http",
"version": "1.2.2",
"version": "1.3.0",
"description": "Tool to instantly create your own http server for development-use",
"bin": "./dist/bin.js",
"main": "./dist/index.js",
"scripts": {
"testpack": "rm ./tmp/* -rf && npm pack --pack-destination=./tmp",
"test": "npx jest --debug",
"lint": "tsc --noEmit && eslint",
"build:dts": "tsc -p tsconfig.json --emitDeclarationOnly --outDir dist",
"compile:prod": "rm -rf dist/* && npx tsup && npm run build:dts && ls -lha dist",
"check:types": "tsc -p tsconfig.check-types.json --noEmit",
"compile:prod": "rm -rf dist/* && npx tsup && ls -lha dist",
"prerelease": "npm run compile:prod",
"release": "npx release-it",
"audit": "npm audit --omit=dev",
Expand All @@ -31,7 +31,7 @@
"src/bin.ts"
],
"clean": true,
"dts": false,
"dts": true,
"format": [
"cjs",
"esm"
Expand All @@ -57,8 +57,6 @@
],
"homepage": "https://github.com/pillsilly/InstantHttp",
"devDependencies": {
"@babel/preset-env": "7.29.2",
"@babel/preset-typescript": "7.28.5",
"@eslint/eslintrc": "3.3.5",
"@eslint/js": "9.39.2",
"@types/compression": "1.8.1",
Expand All @@ -80,7 +78,8 @@
"release-it": "20.0.1",
"supertest": "7.2.2",
"tsup": "8.5.1",
"typescript": "6.0.3"
"typescript": "6.0.3",
"ws": "8.20.1"
},
"overrides": {
"basic-ftp": "5.3.0",
Expand Down
39 changes: 28 additions & 11 deletions src/bin.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#!/usr/bin/env node

import { MODE, run } from './run';
import { Command } from 'commander';
import {MODE, run} from './run'
import {Command} from 'commander'

import pkgJson from '../package.json';
import pkgJson from '../package.json'

export function getOptions (): any {
const program = new Command();
export function getOptions(): any {
const program = new Command()
program
.name('instant_http ')
.version(pkgJson.version)
Expand All @@ -27,6 +27,10 @@ export function getOptions (): any {
'-P, --proxyPattern [proxyPattern]',
'URL matcher to be used to identify which url to proxy'
)
.option('--proxyStaticFileWise', 'Serve static files first and proxy everything else')
.option('--https', 'Enable HTTPS listener')
.option('--httpsKey [httpsKey]', 'HTTPS private key file')
.option('--httpsCert [httpsCert]', 'HTTPS certificate file')
.option('-m, --mode [mode]', 'Which mode to use', MODE.NORMAL)
.option(
'-i, --indexFile [indexFile]',
Expand All @@ -37,13 +41,26 @@ export function getOptions (): any {
'-q, --quiet [quiet]',
'Set it to false to see more debug outputs',
false
);
)

// Parse only args from node onwards, skip jest-specific args
program.parse(process.argv, { from: 'user' });
const opts = program.opts();
console.info(opts);
return opts;
program.parse(process.argv, {from: 'user'})
const opts = program.opts()
console.info(opts)
return opts
}

export function main() {
try {
run(getOptions())
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
console.error(message)
process.exit(1)
}
}

run(getOptions());
/* c8 ignore next 3 */
if (require.main === module) {
main()
}
Loading