netpack is an experiment to see whether .NET tooling can compete with bundlers written in Rust or Go. Thanks to Ahead-of-Time (AoT) compilation it starts at native speed — no JIT to warm up, no runtime to install — while staying arguably more readable than Rust and more capable than Go.
Warning
netpack is pre-1.0 and experimental. It is not production ready, and the chance it works end-to-end for your project today is low. If you like the idea, contribute code or sponsor the project 🍻.
Highlights
- Zero-config — point it at an
index.html(like Vite or Parcel) or a.js/.tsentry directly. - Native startup — an AoT-compiled CLI; competitive with esbuild and faster than rspack/Vite on the benchmarks below.
- Batteries included — TypeScript, JSX, CSS & CSS Modules, Sass/LESS/PostCSS (incl. Tailwind), images (optimized with SkiaSharp), JSON, HTML and arbitrary assets, out of the box.
- Frameworks — React (with Fast Refresh), Preact, Solid, Vue (a native SFC compiler), Svelte, Astro and vanilla.
- A real bundler — tree-shaking, minification, source maps, code-splitting, a dev server with true HMR, and a bundle analyzer.
- Flexible output — ESM / CommonJS / UMD / SystemJS (
--format), web / Node / Deno targets (--platform), import maps, externals, shared dependencies, and Module + Native Federation. - Its own toolchain — a hand-written JavaScript/TypeScript/JSX tokenizer, parser, printer, mangler and tree-shaker in C# — no Acornima, Babel or SWC.
See the documentation for the details behind each of these.
Performance
The whole project is mostly geared towards performance. The key idea is that .NET with AoT (Ahead-of-Time compilation, i.e., no runtime dependency) can be on the same level as Go or Rust. While it still contains a GC (garbage collector, i.e., automatic memory management), the startup time is much improved. There is no JIT that is required to be run, which instantly yields good performance.
| Test | esbuild | rspack | Vite | netpack |
|---|---|---|---|---|
| Small lib | 326ms | 611ms | 601ms | 359ms |
| Small project | 670ms | 912ms | 1658ms | 418ms |
| Medium project | 1931ms | 2877ms | 10601ms | 974ms |
| Large project | 2189ms | 2422ms | 13710ms | 1357ms |
Besides performance there are other reasons for choosing C#/.NET. It's arguably more readable than Rust, more powerful than Go, and better performing than JavaScript. The ecosystem, however, is lacking.
Another reason for having another bundler (but in .NET) is that it could be used natively within the .NET ecosystem, e.g., the post-process or optimize ASP.NET Core and / or Blazor web applications.
Benchmark Details
All benchmarks have been performed using [hyperfine](https://github.com/sharkdp/hyperfine) on Ubuntu 22.04 using an AMD Ryzen 7 3700X 8-Core processor with 32 GB of memory.The benchmarks used netpack v0.0.1, rspack v1.1.8, esbuild v0.24.0, and Vite v6.0.1.
Lib project
netpack:
Benchmark 1: npx netpack bundle src/lib/index.mjs --minify
Time (mean ± σ): 359.4 ms ± 18.3 ms [User: 383.4 ms, System: 56.1 ms]
Range (min … max): 335.4 ms … 386.5 ms 10 runs
esbuild:
Benchmark 1: npx esbuild --bundle src/lib/index.mjs --format=esm --outdir=dist
Time (mean ± σ): 326.3 ms ± 19.4 ms [User: 361.5 ms, System: 35.9 ms]
Range (min … max): 305.1 ms … 361.8 ms 10 runs
rspack:
Benchmark 1: npx rspack build --config rspack.lib.mjs
Time (mean ± σ): 611.0 ms ± 27.9 ms [User: 626.4 ms, System: 109.2 ms]
Range (min … max): 559.1 ms … 643.7 ms 10 runs
Vite:
Benchmark 1: npx vite build
Time (mean ± σ): 601.8 ms ± 20.5 ms [User: 603.1 ms, System: 87.5 ms]
Range (min … max): 573.5 ms … 633.5 ms 10 runs
Small project
netpack:
Benchmark 1: npx netpack bundle src/small/index.html --minify
Time (mean ± σ): 418.5 ms ± 30.3 ms [User: 440.1 ms, System: 71.4 ms]
Range (min … max): 388.2 ms … 475.7 ms 10 runs
esbuild:
Benchmark 1: node esbuild.small.mjs
Time (mean ± σ): 670.3 ms ± 30.8 ms [User: 728.2 ms, System: 57.9 ms]
Range (min … max): 610.1 ms … 711.4 ms 10 runs
rspack:
Benchmark 1: npx rspack build --config rspack.small.mjs
Time (mean ± σ): 912.8 ms ± 39.0 ms [User: 1067.3 ms, System: 223.6 ms]
Range (min … max): 866.0 ms … 1002.9 ms 10 runs
Vite:
Benchmark 1: npx vite build
Time (mean ± σ): 1.658 s ± 0.096 s [User: 2.467 s, System: 0.162 s]
Range (min … max): 1.495 s … 1.827 s 10 runs
Medium project
netpack:
Benchmark 1: npx netpack bundle src/medium/index.html --minify
Time (mean ± σ): 974.9 ms ± 65.2 ms [User: 1409.9 ms, System: 398.3 ms]
Range (min … max): 854.2 ms … 1070.1 ms 10 runs
esbuild:
Benchmark 1: node esbuild.medium.mjs
Time (mean ± σ): 1.931 s ± 0.107 s [User: 1.480 s, System: 0.091 s]
Range (min … max): 1.779 s … 2.149 s 10 runs
rspack:
Benchmark 1: npx rspack build --config rspack.medium.mjs
Time (mean ± σ): 2.877 s ± 0.117 s [User: 6.919 s, System: 1.451 s]
Range (min … max): 2.677 s … 3.025 s 10 runs
Vite:
Benchmark 1: npx vite build
Time (mean ± σ): 10.601 s ± 0.229 s [User: 13.159 s, System: 2.226 s]
Range (min … max): 10.219 s … 11.014 s 10 runs
Large project
netpack:
Benchmark 1: npx netpack bundle src/large/index.html --minify
Time (mean ± σ): 1.357 s ± 0.043 s [User: 2.553 s, System: 0.716 s]
Range (min … max): 1.286 s … 1.433 s 10 runs
esbuild:
Benchmark 1: node esbuild.large.mjs
Time (mean ± σ): 2.189 s ± 0.097 s [User: 1.391 s, System: 0.091 s]
Range (min … max): 2.057 s … 2.334 s 10 runs
Vite:
Benchmark 1: npx vite build
Time (mean ± σ): 13.710 s ± 0.236 s [User: 17.474 s, System: 2.342 s]
Range (min … max): 13.301 s … 14.237 s 10 runs
rspack:
Benchmark 1: npx rspack build --config rspack.large.mjs
Time (mean ± σ): 2.422 s ± 0.133 s [User: 8.956 s, System: 1.381 s]
Range (min … max): 2.283 s … 2.651 s 10 runs
Installation
Add netpack to your Node.js project via your favorite package manager, e.g.:
Now you can run netpack like:
npx netpack bundle src/index.html
Generally, any index.html as for Vite or Parcel should work fine as an entry point. You don't need to supply an HTML file. You can also provide a JavaScript file directly:
npx netpack bundle src/main.mjs
You can start the dev server with the serve command:
npx netpack serve src/index.html
The dev server watches the file system and rebuilds on change. It hot-reloads
modules where it can (with React Fast Refresh when react-refresh is installed)
and falls back to a full browser reload otherwise.
Supported Architectures
- Windows x64 (
win-x64) npm package - Windows x86 (
win-x86) - Windows ARM64 (
win-arm64) npm package - Linux x64 (
linux-x64) npm package - Linux ARM64 (
linux-arm64) npm package - MacOS x64 (
osx-x64) - MacOS ARM64 (
osx-arm64) npm package
Documentation
Usage documentation lives in the docs/ folder (and powers the docs
site at netpack.anglevisions.com/docs):
- Getting started — entry points and the
bundle/serve/analyzecommands. - React & JSX, Vue, Astro, Svelte — framework integrations.
- Styling & assets and images & assets.
- Output formats and platforms —
--formatand--platform. - Import maps & externals, Module Federation, Native Federation.
- Build-time code generation, the bundle analyzer, and other features.
Repository structure
src/ the .NET solution (NetPack.sln)
NetPack/ the bundler and CLI
Syntax/ hand-written JS/TS/JSX tokenizer, parser, printer, mangler, tree-shaker
Graph/ module graph, resolution, bundles, output formats, platforms
Commands/ the bundle / serve / analyze CLI verbs
Assets/ image optimization (SkiaSharp) and other asset handling
Server/ the dev server (watch + reload/HMR)
NodeJs.cs Node IPC bridge for JS-only tools (Sass, LESS, PostCSS, Svelte)
NetPack.Tests/ the xUnit test suite
npm/ npm packaging: the `netpack` wrapper and per-platform `@netpack/*` binaries
resources/ embedded runtime assets (bundle analyzer UI, federation remote)
docs/ user documentation (source for the docs site)
www/ the marketing site (www/home) and docs site (www/docs), both Astro
data/ example projects used for manual testing and benchmarks
art/ logo and brand assets
.github/workflows/ CI (build + test) and the release pipeline
netpack compiles to a single native, AoT-published binary per platform; the npm
netpack package is a thin wrapper that picks the right @netpack/<platform>
binary at install time.
Overview
The following items are features or topics that are relevant for bundlers - netpack in particular.
General Features
- Handle JavaScript
- Handle JSX (configurable factory via
tsconfig.jsonjsxFactoryor a@jsxpragma; defaults toReact.createElement) - Handle TypeScript
- Handle images (optimizes them using SkiaSharp)
- Handle any asset
- Handle CSS
- Handle CSS modules (named/default import of a
.cssfile hashes its class names and exports the original→hashed map) - Handle Vue SFCs (
.vue; native block splitting via AngleSharp) - Handle PostCSS (incl. Tailwind)
- Handle SASS
- Handle LESS
- Handle HTML
- Handle JSON
- Handle codegen
- Handle custom file types with loaders
Frameworks
- Angular
- Astro
- React
- Preact
- Solid (requires
babel-preset-solidinstalled; compiled via the Node bridge) - Svelte (requires
svelteinstalled; compiled via the Node bridge) - Vanilla
- Vue (single-file components; see notes below)
Vue and Astro components are compiled natively (no Node round-trip);
Svelte is compiled by the installed Svelte compiler, and Solid's JSX by
babel-preset-solid, over the Node bridge. See Vue,
Astro, Svelte and Solid
for exactly what's supported and the current limitations.
Bundler Basics
- Sourcemaps
- Minification
- DevServer with reload
- Bundle analyzer (start with
analyze) - Image / asset variants (e.g., width/height optimized)
- Copy public assets ("public" folder below entry-HTML)
- Externals (
--external react react-dom; works also automatically if an importmap is present) - True HMR (not just refresh)
More Advanced Topics
- Importmap support
- Shared dependencies (
--shared react react-dom; automatically adds an importmap if HTML is used) - Module Federation support
- Native Federation support (
federation.jsonwith"kind": "native") - React Fast Refresh support (dev server; requires
react-refreshinstalled) - Custom JSX factory
- Platforms (web, node, deno;
--platform) - Tree shaking
- Other formats (esm, cjs, umd, systemjs;
--format) - Presets / configuration system (JSONC
netpack.json/--preset; composable, with hooks — see Configuration)
Idea Stash
Integration ideas / explorations:
