Install zshy
mainInstall zshy as a development dependency using your preferred package manager:
npm install --save-dev zshy
yarn add --dev zshy
pnpm add --save-dev zshynpm install --save-dev zshyrepository·main·Indexed 22 days ago
https://github.com/colinhacks/zshyA bundler-free build tool for TypeScript libraries that uses tsc to perform dual-module (ESM and CJS) builds. zshy automates the generation of package.json exports, handles file extension rewriting for imports, and supports wildcard entrypoints. It includes features for CJS interop, path alias resolution, import.meta shimming, and automatic jsr.json export updates.
Install zshy as a development dependency using your preferred package manager:
npm install --save-dev zshy
yarn add --dev zshy
pnpm add --save-dev zshynpm install --save-dev zshyExecute the build using npx zshy. It is recommended to add a build script to your package.json.
Via npx:
npx zshyVia npm script:
package.json:"scripts": {
"build": "zshy"
}npm run buildUse the --dry-run flag to simulate the build without writing or updating any files.
jsr.json file, zshy can automatically update its exports field. Because JSR does not support wildcard exports, zshy expands any wildcard patterns defined in your configuration into explicit source entrypoints within jsr.json.Specify your TypeScript entrypoints in the zshy field of your package.json. You can provide a single string for one entrypoint or an object with an exports map for multiple entrypoints, including support for wildcards.
Single entrypoint:
{
"name": "my-pkg",
"zshy": "./src/index.ts"
}Multiple entrypoints with wildcards:
{
"name": "my-pkg",
"zshy": {
"exports": {
".": "./src/index.ts",
"./utils": "./src/utils.ts",
"./plugins/*": "./src/plugins/*",
"./components/**/*": "./src/components/**/*"
}
}
}Wildcard Rules:
/*./* for shallow matches or /**/* for deep recursive matches.zshy matches .ts, .tsx, .cts, and .mts files.{
"zshy": {
"exports": {
".": "./src/index.ts",
"./utils": "./src/utils.ts",
"./plugins/*": "./src/plugins/*",
"./components/**/*": "./src/components/**/*"
}
}
}When building a CLI package, zshy can automatically generate the bin field in your package.json based on your configuration. This ensures that the executable paths correctly point to the generated output files (handling extensions like .js, .mjs, or .cjs based on your ESM/CJS settings).
You can specify bin in your configuration as either a single string (mapping to the package name) or an object mapping command names to source file paths.
The ProjectOptions interface defines how zshy transforms and emits your project. Key configuration areas include:
format ('cjs' or 'esm') and ext ('cjs' | 'js' | 'mjs') to control the module system and file extensions.compilerOptions must include module, moduleResolution, and outDir. You can also provide paths and baseUrl for TypeScript path mapping resolution.format: 'cjs'), setting cjsInterop: true enables transformations for single default exports.rootDir is used to resolve asset imports found during transformation so they can be copied to the outDir.dryRun: true allows you to simulate the build and inspect writtenFiles and copiedAssets in the BuildContext without actually writing to disk.export interface ProjectOptions {
configPath: string;
compilerOptions: ts.CompilerOptions & Required<Pick<ts.CompilerOptions, "module" | "moduleResolution" | "outDir">>;
ext: "cjs" | "js" | "mjs";
format: "cjs" | "esm";
pkgJsonDir: string; // Add package root for relative path display
rootDir: string; // Add source root for asset copying
verbose: boolean;
dryRun: boolean;
cjsInterop?: boolean; // Enable CJS interop for single default exports
paths?: Record<string, string[]>; // TypeScript paths configuration
baseUrl?: string; // TypeScript baseUrl configuration
}You can control whether the build process exits with an error code based on compilation results using the failThreshold setting:
never: The build will always exit with code 0, even if there are errors or warnings (it will only log a warning).warn: The build will exit with code 1 if there are any warnings.package.json#/zshy/bin. zshy will automatically generate the `zshy, add a `The createImportMetaShimTransformer function returns a TypeScript transformer factory designed to shim import.meta properties for CommonJS (CJS) compatibility. When used during a build process, it replaces ESM-specific import.meta access with CJS equivalents:
import.meta.url is transformed into a call to pathToFileURL(__filename) using require('url').import.meta.dirname is transformed into __dirname.import.meta.filename is transformed into __filename.import * as ts from "typescript";
import { createImportMetaShimTransformer } from "./tx-import-meta-shim";
// Example usage in a custom TypeScript transformation pipeline
const transformer = createImportMetaShimTransformer();
// This transformer can then be passed to ts.transform() along with your source fileThe compileProject function is the primary entry point for programmatic compilation using zshy. It orchestrates the TypeScript compilation process, applies custom transformers (like extension rewriting and CJS interop), handles asset copying, and manages error reporting.
To use it, you must provide a ProjectOptions object, an array of entry point file paths, and a BuildContext object to track the build state.
import { compileProject, type ProjectOptions, type BuildContext } from './src/compile.js';
const options: ProjectOptions = {
configPath: './tsconfig.json',
compilerOptions: {
module: ts.ModuleKind.ESNext,
moduleResolution: ts.ModuleResolutionKind.Node16,
outDir: './dist',
// ... other ts.CompilerOptions
},
ext: 'mjs',
format: 'esm',
pkgJsonDir: './',
rootDir: './src',
verbose: true,
dryRun: false
};
const ctx: BuildContext = {
writtenFiles: new Set(),
copiedAssets: new Set(),
errorCount: 0,
warningCount: 0
};
const entryPoints = ['./src/index.ts'];
await compileProject(options, entryPoints, ctx);The createPathsResolverTransformer function creates a TypeScript transformer that resolves path aliases (defined in tsconfig.json's paths property) into relative paths during the build process. This allows you to use path aliases in your source code while ensuring the output contains valid relative imports.
To use this, you must provide a PathsConfig object that describes your project structure and path mappings.
import { createPathsResolverTransformer, PathsConfig } from 'zshy/tx-paths-resolver';
const config: PathsConfig = {
baseUrl: './',
paths: {
'@/*': ['src/*']
},
tsconfigDir: '/path/to/project',
rootDir: '/path/to/project'
};
const transformer = createPathsResolverTransformer(config);
// Use this transformer in your TypeScript build pipeline