zntcbuild [root] # HTML rewrite + hashed assets → dist/
zntcpreview [outdir] # serve built files only
The default app layout is index.html, public/, src/main.ts(x), and .env*.
zntc build uses <script type="module" src> as bundle entries and rewrites CSS
url(), HTML asset URLs, and %ENV% tokens, and injects modulepreload links
for static split chunks. zntc dev uses the same HTML/env/public prepare step and
updates stylesheets for CSS edits without a full page reload.
in preview, fall back route-like 404 requests to index.html or the given file
--jsx*
JSX runtime (--jsx, --jsx-dev, --jsx-import-source, --jsx-factory, --jsx-fragment). When unset, the app root tsconfig.jsonjsx / jsxImportSource is used
--loader:.ext=<type>
Per-extension loader override — same vocabulary as zntc --bundle
--asset-names <pattern>
Asset filename pattern (default: [name]-[hash])
--asset-inline-limit <n>
Inline assets of at most n bytes as data URLs (default: 4096, 0 = never)
Assets referenced from bundled JS and CSS (import logo from "./logo.png",
url(./font.woff2)) go through the bundler asset pipeline, so zntc dev /
zntc build accept the same --loader:.ext=type / --asset-names /
--asset-inline-limit options as zntc --bundle. Common image, font, and media
extensions already default to the file loader, so most apps need no flag at all
— see Bundling — Assets.
zntc dev / zntc build resolve the JSX runtime in this order: CLI --jsx*
options → app root tsconfig.json (compilerOptions.jsx / jsxImportSource) →
default classic (React.createElement). Non-React apps such as preact/solid only
need "jsx": "react-jsx", "jsxImportSource": "preact" in tsconfig.json for both
dev and build to work.
If the app root contains postcss.config.{js,mjs,cjs,json} or .postcssrc*,
ZNTC automatically applies it to CSS. In zntc dev, original CSS files and PostCSS
dependency / dir-dependency messages are watched and CSS-only edits are sent
as stylesheet HMR updates. Tailwind v4 works via @tailwindcss/postcss. CSS
Modules (.module.css) in app mode are transformed into scoped class maps with
default exports and valid named exports. .scss / .sass files are compiled to
CSS before PostCSS when the optional sass dependency is installed.
This is a separate npx entry point that adds ZNTC scripts and config to an
existing React Native CLI project. Expo project creation/initialization is
currently out of scope.
Terminal window
npx@zntc/init
npx@zntc/init--help
Usage: zntc-init [react-native] [options]
Overlay ZNTC onto an existing React Native CLI project.
Options:
--root <dir> Project root (default: cwd)
--platform <ios|android> Default platform for the start script (default: ios)
--zntc-version <range> Version range for @zntc packages (default: latest)
--package-manager <pm> Install command hint: bun, npm, pnpm, or yarn
--no-metro-fallback Do not add Metro fallback scripts
--force Overwrite an existing zntc.config.ts
--dry-run Print planned changes without writing files
--help, -h Show this help message
Option
Description
--root <dir>
Project root. Defaults to the current directory
--platform <ios|android>
Default RN platform for the start script. Defaults to ios
--zntc-version <range>
Version range for @zntc/core and @zntc/react-native
ES target: es2015–esnext or engine versions (chrome80,safari14)
--browserslist=<query>
Browserslist query as the ES downlevel target. The Zig CLI accepts only simple engine+version forms ("chrome >= 87, firefox 78"); stat-based queries ("defaults", "last 2 versions", "> 0.5%") need caniuse-lite data and work only through the JS wrapper
--runtime-polyfills=auto|usage|entry|off
Inject core-js runtime API polyfills. auto/usage use graph usage
These four are accepted for compatibility but ignored at runtime (stderr warning): --asset-catalog-dest=<dir> / --unstable-transform-profile=<name> / --transform-option=<k=v> / --resolver-option=<k=v>. Rationale and the recommended replacements live in the React Native guide — compatibility flags accepted but ignored.
@jsx / @jsxFrag only take effect when the effective runtime is classic (the automatic
runtime doesn’t use a factory). E.g. a project on React (jsx: react-jsx) can have one file
use preact by adding just /** @jsxImportSource preact */ — that file alone uses
preact/jsx-runtime.
Inline assets of at most this size as data URLs instead of emitting files (default 4096, 0 = never). Applies only to assets that default to file by extension — an explicit --loader:.ext=file is never inlined
--loader:.ext=type
Loader by extension (file|dataurl|base64|text|binary|copy|empty|json|css|js|ts|jsx|tsx). Common image / font / media extensions already default to file
--metafile / --metafile=<path>
Build meta JSON (stdout or file)
--analyze
Bundle analysis report (printed to stderr). Pair with --metafile=<path> to also write JSON to disk; upload it at /analyze/
--legal-comments=<mode>
License comments: none|inline|eof|linked|external (linked/external currently fall back to eof)
--packages=external
Treat all bare package imports as external
--banner:js=<text>
Prepend text (the bare --banner= form is JS-wrapper-only)
--footer:js=<text>
Append text (the bare --footer= form is JS-wrapper-only)
--intro=<text>
Prepend wrapper-internal bundle text (JS-wrapper-only — native parser does not accept it)
--outro=<text>
Append wrapper-internal bundle text (JS-wrapper-only — native parser does not accept it)
--global:FROM=TO
Map an IIFE/UMD external specifier to a global variable name
--global-identifier=<name>
Reserve a global identifier during scope hoisting (repeatable)
--polyfill=<path>
Run-on-startup polyfill module path (repeatable, resolved to absolute path)
--run-before-main=<path>
Module to execute right before the entry module (repeatable, resolved to absolute path)
--public-path=<url>
Asset URL prefix
--shim-missing-exports
Shim missing exports with undefined
--tree-shaking[=false] / --no-tree-shaking
Tree shaking (default true). Turn off only for debugging / preserving dead code
--scope-hoist[=false] / --no-scope-hoist
Scope hoisting (default true). Off keeps per-module wrappers — for output diffing / debugging
--min-chunk-size=<n>
Merge common chunks smaller than n bytes (curbs chunk fragmentation under code splitting)
Vite-style query suffixes need no flag: ./data.txt?raw (string), ./icon.png?url
(asset URL — ignores --asset-inline-limit), ./icon.png?inline (data URL),
./x.worker.js?worker (Worker constructor). The query is part of the module
identity, so ./x.png and ./x.png?raw are different modules. Unknown queries
(?vue&type=style&lang.css) pass through untouched — see
Bundling — Query suffixes.
A subcommand that runs the requested phases N times and prints mean/median/p95/p99/stddev/min/max statistics. Use baseline save/compare for before/after optimization analysis.
Option
Description
--phase=<list>
Profile categories to measure as a CSV (required, e.g. parse,transform). all/none are not allowed
--iterations=<n>
Iteration count (default: 100, must be ≥ 1)
--warmup=<n>
Warmup runs before measured runs (default: 10)
--save=<path>
Save the run as a baseline JSON
--compare=<path>
Compare against an existing baseline JSON
--format=<fmt>
Output format — table|tree|json|csv (default: table)