howth mascot

howth

A commodius vicus of recirculation for your JavaScript.

Fast TypeScript builds, Vite-compatible dev server, and complete JS toolchain

1.2ms
Cold Transpile
0.1ms
Warm Build
29x
Faster Tests

Quick Start

# Install
cargo install howth

# Start the Vite-compatible dev server
howth dev src/main.tsx --port 3000 --open

# Build your project
howth build

# Bundle for production
howth bundle src/index.ts -o dist/bundle.js --minify

# Run tests (29x faster than node)
howth test

# Execute TypeScript directly
howth run script.ts

Vite-Compatible Dev Server New

Unbundled ES module serving with instant startup and per-module HMR.

howth dev serves individual ES modules on demand instead of bundling everything. Each file is transformed only when the browser requests it. Dependencies from node_modules are pre-bundled on startup for efficient loading.

How it works

Browser requests GET /src/App.tsx 1. Resolve — Plugin hooks + file system resolution 2. Load — Plugin hooks or read from disk 3. Transpile — SWC converts TSX → JS (sub-millisecond) 4. Transform — Plugin hooks (React Refresh, etc.) 5. Rewrite — Bare imports → /@modules/react 6. Serveapplication/javascript with no-cache

Import rewriting

All imports are rewritten so the browser can load them as native ES modules:

// What you write: import React from 'react'; import { Button } from './Button'; import './styles.css'; // What the browser receives: import React from '/@modules/react'; import { Button } from '/src/Button.tsx'; import '/@style/src/styles.css';

Dependency pre-bundling

On startup, howth scans your entry point for node_modules imports and pre-bundles each package into .howth/deps/. These are served at /@modules/{pkg} with immutable cache headers — the browser caches them permanently, so only your source code is re-fetched on changes.

Server routes

Route Purpose
/ Index HTML with <script type="module"> entry point
/__hmr WebSocket endpoint for hot module replacement
/@hmr-client HMR client runtime (Vite-compatible import.meta.hot API)
/@react-refresh React Fast Refresh runtime
/@modules/{pkg} Pre-bundled npm dependencies (immutable cache)
/@style/{path} CSS files served as JS modules (inject <style> tags)
/{path} On-demand module transform or static file serving

Hot Module Replacement New

Vite-compatible import.meta.hot API for granular updates without full page reloads.

When you save a file, howth walks the module graph to find HMR boundaries — modules that have called import.meta.hot.accept(). Only those modules and their dependents are re-fetched and re-executed. If no boundary is found, a full page reload is triggered.

// Self-accepting module (re-executes itself on update) if (import.meta.hot) { import.meta.hot.accept(); } // Accept updates for specific dependencies if (import.meta.hot) { import.meta.hot.accept('./utils.ts', (newModule) => { console.log('utils updated:', newModule); }); } // Cleanup before replacement if (import.meta.hot) { import.meta.hot.dispose((data) => { clearInterval(data.timer); }); } // Persist data across updates import.meta.hot.data.count = count; // Force full reload import.meta.hot.invalidate(); // Custom events (bidirectional with server) import.meta.hot.on('my-event', (data) => { /* ... */ }); import.meta.hot.send('my-event', { foo: 'bar' });

React Fast Refresh New

Built-in, zero-config component-level HMR for React.

Instant Updates

Edit a component and see the change immediately. No full page reload.

State Preserved

Component state (useState, useReducer) is kept across edits. No lost form input.

Zero Config

Enabled by default for .tsx and .jsx files. No plugins to install or configure.

SWC-Powered

Uses SWC for JSX transformation. Same compiler as Next.js and Parcel.

howth detects React components in .tsx and .jsx files after SWC transpilation and automatically injects the React Refresh preamble and footer. The refresh runtime is served at /@react-refresh and initialized in the index HTML.

CSS Hot Reload

CSS files imported in JavaScript (import './style.css') are served as ES modules that inject <style> tags. On edit, the old style tag is removed and a new one is injected — instant visual updates with no flash of unstyled content.

Vite-Compatible Plugin System New

Rollup hooks + Vite dev server hooks. Existing Vite plugins can work without modification.

Plugin Ordering

enforce: Pre | Normal | Post controls when plugins run in the pipeline.

Config Hooks

config() and config_resolved() let plugins modify and read dev server settings.

Server Hooks

configure_server() adds custom middleware and routes to the dev server.

HTML Transform

transform_index_html() injects scripts, meta tags, or modifies the HTML.

HMR Control

handle_hot_update() gives plugins custom control over what happens on file changes.

Rollup Compat

resolve_id, load, transform, render_chunk — all Rollup hooks work.

Built-in plugins

Plugin Description
ReactRefreshPlugin React Fast Refresh (auto-enabled in dev)
ReplacePlugin Global identifier replacement (e.g., process.env.NODE_ENV)
AliasPlugin Import path aliases (@/components./src/components)
VirtualPlugin Create modules that don't exist on disk
BannerPlugin Add header/footer to bundled output
JsonPlugin Import JSON files as ES modules

Bundler

Tree Shaking

Dead code elimination. Only include what's actually used in your bundle.

Code Splitting

Automatic chunk splitting on dynamic imports. Lazy load routes and features.

CSS + Assets

Bundle CSS with minification. Copy assets with content hashes for caching.

Multiple Formats

Output ESM, CommonJS, or IIFE. Target any JavaScript environment.

Build System

Parallel Hashing

Content-based caching with parallel file hashing. Only rebuild what changed.

Lazy Fingerprinting

Skip expensive output fingerprinting on first build. Computed lazily on cache hits.

Watch Mode

Transpile-only by default for instant feedback. Typecheck is opt-in.

SWC Backend

Uses SWC for transpilation. Rust-native, no Node.js overhead.

Transpile Benchmarks

TypeScript transpilation (Apple M3 Pro)

Tool Cold Warm Peak RSS
howth 1.2ms 0.1ms 8.2MB
tsc --noEmit 975ms - 143MB

Test Runner Benchmarks

500 files, 10,000 test cases (Apple M3 Pro)

Tool Median p95 Peak RSS
howth 139ms 146ms -
bun test 368ms 394ms 138MB
node --test 4.08s 6.26s 138MB

howth is 29x faster than node and 2.7x faster than bun.

What's Next

The dev server architecture is in place. Here's what's still being built.

The essentials

Things most projects need before howth can be their daily driver.

User index.html

Detect and serve your project's own index.html instead of generating a synthetic one. Meta tags, favicons, analytics — all preserved.

Config File

howth.config.ts for aliases, proxy, define globals, and plugin registration without recompiling.

JS Plugin Loading

Load Vite/Rollup plugins written in JavaScript. Opens the door to the entire Vite ecosystem.

SPA Fallback

Serve index.html for non-file routes so client-side routing works on page refresh.

CSS and styling

Gaps that block common frontend workflows.

CSS Modules

.module.css with scoped class names. Widely used in React and Vue projects.

PostCSS

Auto-detect postcss.config.js and apply Tailwind, autoprefixer, and other plugins.

Preprocessors

Sass, Less, and Stylus support. Just install the preprocessor package and import.

url() & @import

Rewrite CSS asset references and inline @import chains in dev mode.

Environment and resolution

.env Files

Load .env, .env.local, .env.development and expose via import.meta.env.

tsconfig paths

Resolve @/* aliases from tsconfig.json without separate config.

browser Field

Respect package.json browser field for browser-specific module remapping.

Exports Wildcards

Support * patterns, nested conditions, and null exclusions in package.json exports.

Dev server features

Proxy

Forward /api/* to a backend. Path rewriting, WebSocket proxying, changeOrigin.

public/ Directory

Static assets served at root URL, copied as-is in production builds.

Error Overlay

Code frame with syntax highlighting, file/line/column, clickable links to open in editor.

CORS & HTTPS

Configurable CORS headers and TLS support for secure-origin APIs.

Module features and build

import.meta.glob()

File-based routing and auto-imports. Lazy or eager. Used by Astro, Vite templates, etc.

Asset Queries

?raw, ?url, ?inline — import files as strings, URLs, or data URIs.

SSR

transformRequest and ssrLoadModule for Next.js, Nuxt, and SvelteKit.

Library Mode

Build packages with UMD, ESM, and CJS outputs via build.lib.

Philosophy

howth takes a Vite-like approach to development: serve individual ES modules on demand, transpile only what the browser requests, and pre-bundle dependencies once on startup. The result is instant server start, sub-millisecond HMR updates, and a plugin system that works with the Vite ecosystem.

For production, howth bundle produces optimized output with tree shaking, code splitting, and minification — the same plugin hooks work in both dev and build.