Generate package.json#exports from src
Automatically generate package.json exports from your source files with support for TypeScript, JavaScript, JSX/TSX, and CSS. Features include index file flattening, custom transform modes, and monorepo live types support.
Install @ngrok/gen-x to your devDependencies with your preferred package manager:
| package manager | command |
|---|---|
| npm | npm install -DE @ngrok/gen-x |
| yarn | yarn add -DE @ngrok/gen-x |
| pnpm | pnpm add -DE @ngrok/gen-x |
| bun | bun add -DE @ngrok/gen-x |
# Generate exports from src/ to dist/
npx gen-x
# Preview changes without writing
npx gen-x --dry-runThis will scan your src/ directory and generate package.json exports like:
{
"exports": {
"./package.json": "./package.json",
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./utils": {
"import": "./dist/utils.js",
"types": "./dist/utils.d.ts"
}
}
}- ✅ Index file flattening -
index.ts→".",lib/index.ts→"./lib" - ✅ CSS support - Preserves extensions for assets, no types field
- ✅ Multiple file types - .ts, .tsx, .js, .jsx, .mjs, .cjs, .css
- ✅ Transform modes - camelCase, kebab-case, PascalCase, snake_case
- ✅ Replace patterns - Rename exports with regex or string patterns
- ✅ Custom conditions - For monorepo live types
- ✅ Watch mode - Automatically regenerate exports on file changes
- ✅ Source-only mode - Emit plain source file paths without import/types conditions
- ✅ Cross-platform - Always generates POSIX paths for package.json
- ✅ Collision detection - Errors on duplicate export keys
gen-x is configured entirely through CLI flags.
Options:
-V, --version output the version number
--dry-run, --dryRun Preview changes to stdout
--exclude <exclude...> Globs to exclude (default: ["**/*.d.ts","**/*.test.*","**/*.spec.*","**/__tests__/**"])
--include <include...> Globs to include (default: ["**/*.{ts,tsx,cts,mts,js,jsx,mjs,cjs,css}"])
-i, --input <input> Input directory (default: "src")
-m, --mode <mode> Transform mode: passthrough|camelCase|kebab-case|PascalCase|snake_case (default: "passthrough")
--customCondition <condition> Custom condition for monorepo live types
-o, --output <output> Output directory (default: "dist")
-p, --package <package> Path to package.json (default: "package.json")
-r, --replace <pattern:=>replacement...> Replace export keys
--sourceOnly Only emit plain source file paths in exports
-w, --watch Watch the input directory for changes and regenerate exports
-h, --help display help for commandnpx gen-x# Transform to camelCase
npx gen-x --mode camelCase
# hello-world.ts → ./helloWorld
# Transform to kebab-case
npx gen-x --mode kebab-case
# HelloWorld.ts → ./hello-world# Remove _pb suffix from protobuf files
npx gen-x --replace "/_pb/:=>"
# user_pb.ts → ./user (but still imports from user_pb.js)
# Multiple replacements
npx gen-x --replace "/_pb/:=>" --replace "/^api-/:=>api/"For consuming packages in the same monorepo to use source TypeScript files:
npx gen-x --customCondition "@my-org/my-package/source"Generates:
{
"exports": {
".": {
"@my-org/my-package/source": "./src/index.ts",
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
}
}
}See Live Types in TypeScript Monorepo for more info.
CSS files automatically preserve their extensions:
# src/styles/theme.css → ./styles/theme.css
npx gen-xOutput:
{
"./styles/theme.css": {
"import": "./dist/styles/theme.css"
}
}# Include only TypeScript files
npx gen-x --include "**/*.ts" --include "**/*.tsx"
# Exclude internal files
npx gen-x --exclude "**/internal/**" --exclude "**/*.test.*"Automatically regenerate exports when files are added, deleted, or renamed:
npx gen-x --watchWrites are skipped when exports haven't changed, avoiding unnecessary downstream rebuilds in tools like Turborepo.
import { generateExports } from "@ngrok/gen-x";
const exports = await generateExports({
input: "src",
output: "dist",
mode: "camelCase",
});
console.log(exports);We use mise to manage the toolchain (Node.js and pnpm). Versions are pinned in .nvmrc (Node) and package.json#packageManager (pnpm), and locked in the committed mise.lock.
First, install mise (or run ./scripts/install-mise to install the pinned version):
| OS | command |
|---|---|
| macOS | brew install mise |
| other | curl https://mise.run | sh |
For all other install methods, see the mise installation guide.
Don't forget to activate mise in your shell.
Next, clone the repo and move into the directory:
git clone https://github.com/ngrok/gen-x.git
cd gen-xNext, run:
mise trust
mise install
mise run setupThis installs the pinned node and pnpm versions and then runs pnpm install --frozen-lockfile to install all node_modules.
Useful mise tasks:
mise run doctor— verify the active tools match the committed pinsmise run relock— refreshmise.lockafter bumping.nvmrcorpackage.json#packageManager(then runmise installand commit both)
Prefer to install and manage the tooling yourself?
- Install the
nodeversion pinned in.nvmrcwith your node version manager of choice. - Enable
pnpmwithcorepack:corepack enable pnpm - Install
pnpmwithcorepack:corepack install - Install project dependencies with
pnpm:pnpm install