This skill should be used when creating or editing package.json, tsconfig, managing npm dependencies, configuring monorepos, or publishing npm packages.
This skill defines best practices for packaging, dependency management, monorepo configuration, and publishing TypeScript packages to npm with modern module formats and optimal developer experience.
ALWAYS include these core fields in package.json.
CORRECT:
{
"name": "@scope/package-name",
"version": "1.2.3",
"description": "Clear, concise package description",
"keywords": ["typescript", "library", "utility"],
"author": "Your Name <[email protected]>",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/username/repo.git"
},
"bugs": {
"url": "https://github.com/username/repo/issues"
},
"homepage": "https://github.com/username/repo#readme"
}
ALWAYS use "type": "module" for ESM packages and configure exports properly.
CORRECT for ESM-only package:
{
"name": "@scope/package-name",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
}
},
"files": ["dist"],
"sideEffects": false
}
CORRECT for dual ESM/CJS package:
{
"name": "@scope/package-name",
"version": "1.0.0",
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./package.json": "./package.json"
},
"files": ["dist"],
"sideEffects": false
}
CORRECT for multiple entry points:
{
"name": "@scope/package-name",
"version": "1.0.0",
"type": "module",
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
},
"./utils": {
"import": {
"types": "./dist/utils.d.ts",
"default": "./dist/utils.js"
},
"require": {
"types": "./dist/utils.d.cts",
"default": "./dist/utils.cjs"
}
},
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"utils": ["./dist/utils.d.ts"]
}
}
}
Explicitly list files to publish to avoid bloat.
CORRECT:
{
"files": ["dist", "README.md", "LICENSE"]
}
WRONG:
{
"files": ["src", "dist", "tests", "node_modules"]
}
ALWAYS set sideEffects to enable tree-shaking.
CORRECT for pure library:
{
"sideEffects": false
}
CORRECT for library with some side effects:
{
"sideEffects": ["*.css", "./src/polyfills.ts"]
}
Specify packageManager for consistent dependency resolution.
CORRECT:
{
"packageManager": "[email protected]"
}
Standardize script names across projects.
CORRECT:
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsup",
"test": "vitest",
"test:ui": "vitest --ui",
"test:coverage": "vitest run --coverage",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
"format:check": "prettier --check .",
"typecheck": "tsc --noEmit",
"validate": "pnpm run typecheck && pnpm run lint && pnpm run test:coverage && pnpm run format:check",
"clean": "rm -rf dist coverage",
"prepublishOnly": "pnpm run validate && pnpm run build"
}
}
Specify supported Node.js and package manager versions.
CORRECT:
{
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
}
}
CORRECT for publishable library:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2023"],
"outDir": "./dist",
"rootDir": "./src",
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.spec.ts"]
}
CORRECT:
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"],
"@components/*": ["./src/components/*"],
"@utils/*": ["./src/utils/*"],
"@hooks/*": ["./src/hooks/*"],
"@types/*": ["./src/types/*"]
},
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}
CORRECT base config (tsconfig.base.json):
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"exactOptionalPropertyTypes": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noPropertyAccessFromIndexSignature": true,
"allowUnusedLabels": false,
"allowUnreachableCode": false,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
}
}
Package-specific tsconfig:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "Bundler",
"lib": ["ES2023"],
"outDir": "./dist",
"rootDir": "./src",
"composite": true
},
"include": ["src"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}
CORRECT root tsconfig.json with references:
{
"files": [],
"references": [
{ "path": "./packages/core" },
{ "path": "./packages/utils" },
{ "path": "./packages/cli" },
{ "path": "./apps/web" }
]
}
Build with references:
tsc --build --verbose
ALWAYS use tsup for library bundling (ESM + CJS).
CORRECT tsup.config.ts:
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
treeshake: true,
minify: false,
target: 'es2022',
outDir: 'dist',
});
For multiple entry points:
import { defineConfig } from 'tsup';
export default defineConfig({
entry: {
index: 'src/index.ts',
utils: 'src/utils.ts',
cli: 'src/cli.ts',
},
format: ['cjs', 'esm'],
dts: true,
splitting: false,
sourcemap: true,
clean: true,
treeshake: true,
outDir: 'dist',
});
CORRECT vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
build: {
target: 'es2022',
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
},
},
},
});
CORRECT build script with esbuild:
// build.ts
import * as esbuild from 'esbuild';
await esbuild.build({
entryPoints: ['src/index.ts'],
bundle: true,
outfile: 'dist/index.js',
platform: 'node',
format: 'esm',
target: 'es2022',
sourcemap: true,
external: ['node:*'],
minify: false,
});
Place dependencies in the correct field.
CORRECT:
{
"dependencies": {
"zod": "^3.22.4",
"date-fns": "^3.0.0"
},
"devDependencies": {
"typescript": "^5.3.3",
"vitest": "^1.2.0",
"@types/node": "^20.11.0",
"tsup": "^8.0.1",
"prettier": "^3.2.4",
"eslint": "^8.56.0"
},
"peerDependencies": {
"react": "^18.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false
}
}
}
WRONG:
{
"dependencies": {
"typescript": "^5.3.3",
"vitest": "^1.2.0",
"@types/node": "^20.11.0",
"react": "^18.0.0"
}
}
Use conservative version ranges for libraries, flexible for applications.
CORRECT for libraries:
{
"dependencies": {
"zod": "^3.22.4",
"date-fns": "^3.0.0"
}
}
CORRECT for applications (can be more flexible):
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"zod": "^3.22.4"
}
}
ALWAYS specify peer dependencies for libraries that extend other tools.
CORRECT React component library:
{
"name": "@scope/ui-components",
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": false
}
},
"devDependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
CORRECT TypeScript plugin:
{
"name": "@scope/typescript-plugin",
"peerDependencies": {
"typescript": "^5.0.0"
},
"devDependencies": {
"typescript": "^5.3.3"
}
}
ALWAYS use pnpm workspaces for monorepos.
CORRECT pnpm-workspace.yaml: