UNPKG

qr-local-dev

Version:

Print a QR code for your local dev server in the terminal

296 lines (225 loc) 8.12 kB
# qr-local-dev Display a QR code in your terminal that points to your machine's local network URL, so you can open your dev server on a phone or another computer instantly. ## Install ```bash npm i -D qr-local-dev ``` Or use it globally: ```bash npm i -g qr-local-dev ``` ## CLI ```bash qr-local -p 3000 ``` Options: - `-p, --port <number>`: Port to include in the URL (e.g., 3000) - `--ports <list>`: Comma list of ports to try (e.g., 3000,5173,8080) - `--http`/`--https` or `--protocol <p>`: `http` | `https` | `auto` - `--path <path>`: Optional path to append (e.g., /app) - `-H, --host <ip>`: Override detected host/IP - `-s, --small`: Use smaller terminal QR variant - `-d, --detect`: Try common ports and pick a running dev server - `-c, --copy`: Copy the resolved URL to your clipboard - `--mdns`: Broadcast via mDNS/Bonjour (if available) - `--mdns-name <n>`: Custom mDNS service name - `--force-qr`: Print QR even if not a TTY - `-w, --wait`: Wait for the server to become available - `--wait-timeout <ms>`: Max wait time in ms (default 15000) - `--wait-interval <ms>`: Probe interval in ms (default 500) - `--square`: Render square-style QR (uses qrcode-terminal) ## API ```js const { printLocalhostQR } = require("qr-local-dev"); await printLocalhostQR({ port: 3000 }); // Auto-detect server and protocol (useful across frameworks) await printLocalhostQR({ protocol: "auto", detect: true, small: true, square: true, copy: true, mdns: true, wait: true, waitTimeout: 15000, waitInterval: 500, }); ``` TypeScript users: this package ships `.d.ts` types. Import as: ```ts import { printLocalhostQR } from "qr-local-dev"; ``` ## Express example ```js const express = require("express"); const { printLocalhostQR } = require("qr-local-dev"); const app = express(); const port = process.env.PORT || 3000; app.get("/", (_req, res) => { res.send("Hello from Express"); }); app.listen(port, async () => { await printLocalhostQR({ port }); }); ``` ## Next.js: auto-print QR on dev start (no extra scripts) Add an instrumentation file so the QR shows right after `npm run dev`: 1. Create `instrumentation.js` or `instrumentation.ts` at your project root: ```ts // instrumentation.(js|ts) (Next.js App Router) export async function register() { // Only run in Node.js runtime (skip Edge) and only in dev if (process.env.NEXT_RUNTIME !== "nodejs") return; if (process.env.NODE_ENV === "production") return; // Prevent duplicate prints during Fast Refresh const shownKey = "__qr_local_dev_shown__"; if ((globalThis as any)[shownKey]) return; (globalThis as any)[shownKey] = true; const { printLocalhostQR } = await import("qr-local-dev"); const envBool = (v?: string) => v === "1" || v === "true"; const portsEnv = process.env.QR_LOCAL_PORTS; const ports = portsEnv ? portsEnv .split(",") .map((p) => Number(p.trim())) .filter(Boolean) : undefined; const delay = Number(process.env.QR_LOCAL_DELAY ?? 300); setTimeout(() => { printLocalhostQR({ protocol: process.env.QR_LOCAL_PROTOCOL || "auto", detect: envBool(process.env.QR_LOCAL_DETECT ?? "1"), wait: envBool(process.env.QR_LOCAL_WAIT ?? "1"), waitTimeout: Number(process.env.QR_LOCAL_WAIT_TIMEOUT ?? 15000), waitInterval: Number(process.env.QR_LOCAL_WAIT_INTERVAL ?? 500), small: envBool(process.env.QR_LOCAL_SMALL ?? "1"), square: envBool(process.env.QR_LOCAL_SQUARE ?? "0"), copy: envBool(process.env.QR_LOCAL_COPY ?? "0"), mdns: envBool(process.env.QR_LOCAL_MDNS ?? "0"), mdnsName: process.env.QR_LOCAL_MDNS_NAME, forceQr: envBool(process.env.QR_LOCAL_FORCE_QR ?? "0"), host: process.env.QR_LOCAL_HOST, path: process.env.QR_LOCAL_PATH || "", port: process.env.PORT ? Number(process.env.PORT) : undefined, ports, }).catch(() => {}); }, delay); } ``` 2. Pin your dev port so the QR matches: ```json { "scripts": { "dev": "next dev -p 3000" } } ``` 3. Run your app as usual: ```bash npm run dev ``` Optional HTTPS: ```bash next dev -p 3000 --experimental-https ``` If you use HTTPS, set `protocol: "https"` in `printLocalhostQR`. Troubleshooting: - Requires App Router (instrumentation file convention). For Pages Router-only apps, use the CLI approach. - Ensure the file name is exactly `instrumentation.js` or `instrumentation.ts` in your project root (or `app/`). - If the port can change, use `--wait`/`detect` or pin the port with `-p`. ## Framework tips - Vite (React/Vue/Svelte/Solid): default ports 5173/4173; use `--protocol auto --detect --ports 5173,4173` - Next.js: default 3000; use instrumentation above or `concurrently` with `next dev -p 3000` - Nuxt: default 3000; prefer `--protocol auto --detect --ports 3000,4000` - Astro: default 4321; use `--protocol auto --detect --ports 4321` - SvelteKit: default 5173; use `--protocol auto --detect --ports 5173` - Angular: default 4200; use `--protocol auto --detect --ports 4200` - Vue CLI: default 8080; use `--protocol auto --detect --ports 8080` General advice: - Pin your dev port to keep the QR stable (avoid auto-increment ports). - If your dev server switches to HTTPS, `--protocol auto` will probe and pick it. - Add `-c/--copy` so you can paste the URL quickly on your device. ## Framework recipes (copy/paste) Install helpers once: ```bash npm i -D concurrently wait-on ``` Add one of these to your app's `package.json` scripts. 1. Next.js (Pages Router only): ```json { "scripts": { "dev": "concurrently -k -s first \"next dev -p 3000\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --wait\"" } } ``` 2. Vite (React/Vue/Svelte/Solid): ```json { "scripts": { "dev": "concurrently -k -s first \"vite\" \"wait-on http://localhost:5173 && qr-local --protocol auto --detect --ports 5173,4173 --wait\"" } } ``` 3. Nuxt: ```json { "scripts": { "dev": "concurrently -k -s first \"nuxi dev -p 3000\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --wait\"" } } ``` 4. Astro: ```json { "scripts": { "dev": "concurrently -k -s first \"astro dev\" \"wait-on http://localhost:4321 && qr-local --protocol auto --detect --ports 4321 --wait\"" } } ``` 5. SvelteKit: ```json { "scripts": { "dev": "concurrently -k -s first \"vite\" \"wait-on http://localhost:5173 && qr-local --protocol auto --detect --ports 5173 --wait\"" } } ``` 6. Angular: ```json { "scripts": { "dev": "concurrently -k -s first \"ng serve --host 0.0.0.0 --port 4200\" \"wait-on http://localhost:4200 && qr-local --protocol auto --detect --ports 4200 --wait\"" } } ``` 7. Vue CLI: ```json { "scripts": { "dev": "concurrently -k -s first \"vue-cli-service serve --host 0.0.0.0 --port 8080\" \"wait-on http://localhost:8080 && qr-local --protocol auto --detect --ports 8080 --wait\"" } } ``` 8. Remix: ```json { "scripts": { "dev": "concurrently -k -s first \"remix dev\" \"wait-on http://localhost:3000 && qr-local --protocol auto --detect --ports 3000 --wait\"" } } ``` Notes: - Use `--square` for a square-looking QR: append `--square` to the QR command. - Add `--copy` to copy URL to clipboard automatically. - For HTTPS, prefer `--protocol auto` (it will probe) or pass `--https`. ### WSL (Windows Subsystem for Linux) - Your LAN IP might differ between Windows and WSL. This tool uses `os.networkInterfaces()` inside the current runtime. - If mobile cannot reach the URL, try overriding host with the Windows LAN IP: `qr-local -H 192.168.x.y -p 3000`. - If the port is forwarded or bound to 127.0.0.1 only, ensure your dev server binds to `0.0.0.0`. ### Docker/containers - On Linux, `--network host` allows containers to use the host network (QR will point to the host IP). - Otherwise, expose the port and run the QR command on the host, not inside the container. ### TTY/CI - Some environments pipe output; the QR may be hidden. Use `--force-qr` to print anyway or rely on the URL line. - You can disable QR (URL only) by omitting `--force-qr` in non-TTY contexts.