Other features

Assorted things netpack does today that don’t warrant their own page yet.

Output formats

By default netpack emits ES modules; --format (esm, cjs, umd, systemjs) picks the envelope each JavaScript bundle is wrapped in. See Output formats for the details, limitations, and why ESM is the best choice.

Tree shaking

netpack computes which exports of each module are actually used across the whole graph (once per build, cached) and drops the rest — an export no importer ever references doesn’t make it into the output bundle.

Source maps

npx netpack bundle src/index.html --sourcemap

Emits a .js.map next to each JavaScript bundle. serve always emits source maps, regardless of this flag, since you’re debugging live.

Minification

npx netpack bundle src/index.html --minify

Optimizes JS, CSS and the HTML shell for size. bundle’s summary table shows the effect directly — compare a build with and without --minify.

Log level (--log-level)

Controls how much netpack prints. It is a global flag — it works with any command (bundle, serve, analyze, …):

npx netpack bundle src/index.html --log-level warning

The levels, least to most verbose, are silent, error, warning, info (default), debug, and verbose. Each shows its own tier and everything below it — warning shows warnings and errors but not the normal build chatter, silent shows nothing, and debug/verbose add extra diagnostic detail on top of the usual output.

Compile-time constants (--define)

Replaces a global identifier or member expression with a constant expression before parsing — the value is inlined, so dead branches tree-shake away.

npx netpack bundle src/index.html --define __VERSION__=\"1.4.0\" --define DEBUG=false

The replacement text must be valid JavaScript, so a string constant keeps its quotes (--define API=\"/v2\"). process.env.NODE_ENV is defined for you (development under serve, production for an optimized build); a --define of your own overrides it. Both bundle and serve accept the flag, repeatably.

Import aliases (--alias)

Rewrites an import specifier to another package or a local file.

npx netpack bundle src/index.html --alias react=preact/compat --alias @=./src

A bare target (preact/compat) is resolved like any dependency; a path target (./src) is resolved from the working directory. Matching is on the specifier, so import "@" picks up the alias.

TypeScript paths

netpack also honours the compilerOptions.paths mapping from the tsconfig.json closest to the importing file as a resolution fallback, so aliases like @/*./src/* work without a matching --alias. Because the lookup is per-file, a monorepo where each package has its own tsconfig.json (and its own paths) resolves correctly:

// tsconfig.json
{ "compilerOptions": { "baseUrl": ".", "paths": { "@/*": ["./src/*"] } } }

With that, import { Foo } from "@/components" resolves to src/components. Targets are resolved relative to baseUrl (or the tsconfig’s own directory when baseUrl is absent). Each tsconfig.json is parsed at most once and the directory lookup is cached, and the mapping is only consulted when a specifier doesn’t resolve normally, so it adds no cost to regular imports. An explicit --alias still wins.

Loaders (--loader)

Overrides how a file extension is turned into a module, replacing the built-in handling.

npx netpack bundle src/index.html --loader .svg=text --loader .frag=text

Available loaders: js, jsx, ts, tsx, json, css, text (import the file’s contents as a string), base64, dataurl (inline as a data: URI), file/copy (emit the file and import its URL), and empty. The inline loaders (text/base64/dataurl/empty) produce a JS module, so they apply to files imported from JavaScript.

Cache-busting file names (--entry-names)

Adds a content hash to emitted bundle names so they can be served with a long-lived cache. References from the HTML entry (and between bundles) are rewritten to the hashed names automatically.

npx netpack bundle src/index.html --entry-names [name]-[hash]

The template understands [name] and [hash]; the default is [name] (no hash). The entry HTML document keeps its own name so it stays linkable. Imported assets are content-hashed already, independently of this flag. The hash reflects each bundle’s own contents, so a change confined to a shared bundle re-hashes that bundle but not the entries that import it.

Public path (--public-path)

Prepends a base path or URL to every reference to an emitted file — bundle chunks, assets, and the script/link/img targets in the HTML shell — so the output can be served from a CDN or a sub-path instead of next to the document.

npx netpack bundle src/index.html --public-path https://cdn.example.com/app

With no public path (the default) references stay document-relative (./app.js); with one they become https://cdn.example.com/app/app.js. It applies across every output format.

Places arbitrary text on the very first line of the entry JS bundle, followed by a newline — typically a license/copyright header or a runtime pragma.

npx netpack bundle src/index.html --banner "// (c) 2026 Acme, Inc. — MIT"

The banner is emitted verbatim, so it is your responsibility to make it valid for the position it lands in (a // or /* … */ comment, a "use client"-style directive, a shebang, …). It goes on top of every entry JS bundle; shared split chunks are left untouched. An empty banner (the default) emits nothing. Source maps stay accurate: mappings are shifted to account for the added lines. Both bundle and serve accept the flag.

Licenses (--licenses)

By default netpack collects the legal comments in your dependencies — the /*! … */, //! …, @license, @preserve and @copyright blocks bundlers are expected to preserve — and keeps the relevant ones in each bundle’s head (after any --banner). --licenses picks how that’s handled:

ValueBehaviour
skip (default)Don’t collect or emit any licenses.
preambleKeep each module’s legal comments at the top of the bundle it lands in, after the banner.
jsonWrite a licenses.json manifest (package name, version, license id, license text) to the output directory.
spdxWrite a licenses.spdx manifest in the SPDX tag-value format.
npx netpack bundle src/index.html --licenses spdx

The json/spdx manifests list one entry per resolved dependency (deduplicated by name+version). If a file with that name already exists in the output (for example one copied from public/), a short suffix is added — licenses-1a2b3c.json — so nothing is clobbered. The declared license comes from each package’s package.json license field; the license text, when present, from its LICENSE file.

Exports conditions (--conditions)

Adds custom exports conditions on top of the platform defaults, widening which conditional branches of a dependency’s package.json exports map are eligible.

npx netpack bundle src/index.html --conditions development --conditions browser

User conditions take priority over the platform’s built-ins; default always matches last.

Externalizing packages (--packages)

--packages external keeps every bare (i.e. node_modules) import external instead of bundling it — the standard way to build a library, or a Node app whose dependencies are installed separately. Relative and absolute imports are still bundled.

npx netpack bundle src/lib.ts --packages external --format esm

This is the bulk equivalent of listing every dependency with --external.

Watch mode & HMR

netpack serve watches the filesystem and recompiles on every change with no extra configuration — see Getting started for how updates reach the browser (granular hot-swap vs. full reload), and React & JSX for how React component state survives an edit when react-refresh is installed.

For a build without a server, netpack bundle --watch rebuilds and rewrites the output directory whenever a source file that took part in the build changes:

npx netpack bundle src/index.html --outdir dist --watch

It writes to disk (no dev server, no HMR) and runs until interrupted — handy when another process serves dist/.

Bundle analyzer

Covered in full in Bundle analyzer — the interactive graph explorer, the dependency vulnerability audit, and the optimization recommendations that flag where your chunks could be split more efficiently.

Build-time code generation

Covered in full in Build-time code generation — a .codegen file is executed as a small Node module at build time, and whatever it returns becomes that module’s JavaScript source.

Import maps, externals & shared dependencies

Covered in full in Import maps & externals.

Module Federation

Covered in full in Module Federation.

Native, npm-installable binary

netpack ships as a single Ahead-of-Time-compiled binary per platform (@netpack/linux-x64, @netpack/osx-arm64, @netpack/win-x64), installed through the netpack npm wrapper like any other JS build tool — no JIT warmup, no separate runtime to install. This is also why the Node dependency called out above (Sass/LESS/PostCSS/codegen) is opt-in rather than a baseline requirement: it only spins up when you actually import something that needs it.