Use this playbook whenever you add a package to the monorepo. Following these steps keeps builds, tests, and documentation aligned across workspaces.
mkdir -p packages/your-package-name/srcCopy over any shared assets (README, LICENSE, etc.) from an existing package such as packages/flipper/.
Create packages/your-package-name/package.json:
{
"name": "@flippercloud/your-package-name",
"description": "Brief description of your package",
"version": "0.0.1",
"author": "Jonathan Hoyt",
"license": "MIT",
"main": "./dist/cjs/index.js",
"module": "./dist/esm/index.js",
"types": "./dist/esm/index.d.ts",
"exports": {
".": {
"types": "./dist/esm/index.d.ts",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.js"
}
},
"files": ["dist", "README.md", "LICENSE"],
"scripts": {
"build": "bun run build:esm && bun run build:cjs",
"build:esm": "tsc --module esnext --outDir dist/esm && tsc-esm-fix --target dist/esm --ext .js",
"build:cjs": "tsc --module commonjs --moduleResolution node --outDir dist/cjs",
"test": "NODE_OPTIONS='--localstorage-file=/tmp/jest.db' node --experimental-vm-modules --no-warnings=ExperimentalWarning ../../node_modules/jest/bin/jest.js",
"test:watch": "NODE_OPTIONS='--localstorage-file=/tmp/jest.db' node --experimental-vm-modules --no-warnings=ExperimentalWarning ../../node_modules/jest/bin/jest.js --watch",
"test:coverage": "NODE_OPTIONS='--localstorage-file=/tmp/jest.db' node --experimental-vm-modules --no-warnings=ExperimentalWarning ../../node_modules/jest/bin/jest.js --coverage",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"type-check": "tsc --noEmit",
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
"clean": "node -e \"try { require('fs').rmSync('dist', { recursive: true, force: true }); require('fs').rmSync('coverage', { recursive: true, force: true }); } catch (e) {}\"",
"prepublishOnly": "bun run clean && bun run build && bun test"
},
"dependencies": {
"@flippercloud/flipper": "workspace:*"
},
"devDependencies": {
"tsc-esm-fix": "^2.20.26"
},
"engines": {
"node": ">=18.0.0",
"bun": ">=1.3.2"
},
"publishConfig": {
"access": "public"
}
}Adjust the scripts and dependencies as needed for your package. Keep both build:esm and build:cjs targets so imports work in any environment.
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist/esm",
"rootDir": "./src",
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}If you emit both ESM and CJS builds, point build:cjs at a custom tsconfig.cjs.json or override CLI flags as shown above.
import type { Config } from 'jest'
const config: Config = {
preset: 'ts-jest',
testEnvironment: 'node',
reporters: [['default', { verbose: false }]],
testMatch: ['<rootDir>/src/**/*.test.ts'],
testTimeout: 5000,
collectCoverageFrom: ['src/**/*.ts', '!src/**/*.test.ts'],
coverageDirectory: 'coverage',
coverageReporters: ['text', 'lcov', 'html'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
transform: {
'^.+\\.ts$': ['ts-jest', { useESM: true }],
},
extensionsToTreatAsEsm: ['.ts'],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
}
export default configCopy over the shared configuration:
cp packages/flipper/eslint.config.js packages/your-package-name/packages/your-package-name/
├── README.md
├── eslint.config.js
├── jest.config.ts
├── package.json
├── tsconfig.json
├── src/
│ ├── index.ts
│ ├── index.test.ts
│ └── ...
└── dist/ (generated)
Place tests next to the modules they verify and export public types from src/index.ts.
Run the install from the repository root so Bun wires up the workspace correctly.
bun installbun run build -w @flippercloud/your-package-name
bun run test -w @flippercloud/your-package-nameIf you added new scripts (lint, type-check, etc.) make sure they succeed as well:
bun run lint -w @flippercloud/your-package-name
bun run type-check -w @flippercloud/your-package-name- Publish a package-specific README describing usage and API.
- Update Workspace command reference if you add new scripts.
- Mention the package in the release notes when you publish.
Before releasing, run the prepublish script locally:
bun run prepublishOnly -w @flippercloud/your-package-nameThis ensures builds, tests, and lint checks all pass prior to pushing to the registry.