Thanks for your interest in @ngockhoi96/ctc! This repo is a pnpm + Turborepo monorepo
housing the core clipboard library and its framework adapters. Below is everything you
need to set up, run tests, and ship a change.
- Node.js >= 20 (see
.nvmrcif present) - pnpm >= 10 (
npm i -g pnpm) - Git
git clone https://github.com/anIcedAntFA/ctc.git
cd ctc
pnpm install
pnpm setup # installs lefthook git hooks (pre-commit + commit-msg)After pnpm setup, every commit runs pnpm lint and pnpm test via lefthook, and
commit messages are validated by commitlint.
From the repo root, all tasks are orchestrated by Turborepo:
pnpm lint # biome check across all packages
pnpm test # vitest unit tests across all packages
pnpm test:e2e # playwright tests (packages/core)
pnpm build # tsdown builds across all packages
pnpm validate # publint + arethetypeswrong for all publishable packagesTo run a task for a single package, use a filter:
pnpm --filter @ngockhoi96/ctc-react test
pnpm --filter @ngockhoi96/ctc-vue test
pnpm --filter @ngockhoi96/ctc-svelte test
pnpm --filter @ngockhoi96/ctc test:e2eRun all benchmarks from the repo root:
pnpm bench # vitest bench (performance) + bundle size measurement
pnpm size # size-limit check against thresholds in package.jsonTo run benchmarks for a single package:
pnpm --filter @ngockhoi96/ctc benchesbuild appears in benchmarks/package.json devDependencies but is not the library's build tool — that is tsdown.
esbuild is used exclusively as a bundle size measurement instrument inside benchmarks/scripts/measure-bundle-size.ts. The script calls esbuild.buildSync({ bundle: true, minify: true, format: 'esm', platform: 'browser' }) to produce a single minified ESM bundle for each competitor library, then measures the compressed size with Node.js zlib.gzipSync and zlib.brotliCompressSync. The results feed the Bundle Size Comparison table in BENCHMARKS.md.
Role summary:
tsdown— builds the library output indist/for publicationesbuild— measures minified competitor bundles forBENCHMARKS.mdonly
- Create
packages/<name>/withpackage.json,tsconfig.json, andtsdown.config.ts. Copy the shape from an existing adapter (e.g.packages/react/) and adjust thename,description,peerDependencies, and entry points. - Workspaces are auto-discovered via
pnpm-workspace.yaml(packages/*) — no manual registration needed. - Add
build,lint,test,typecheck,validatescripts so the Turborepo pipeline picks them up. Seeturbo.jsonfor the task graph. - Add a
packages/<name>/README.mdfollowing the structure of existing package READMEs (Title → Install → Peer deps → Quick start → API → Browser support → License). - If the package is publishable, add it to
.changeset/config.jsonworkspace discovery (automatic for anything underpackages/).
Every PR that changes public API or observable behaviour needs a changeset:
pnpm changesetThe CLI prompts you to:
- Select which packages are affected
- Pick a bump type per package:
- patch — bug fix, no API change
- minor — new feature, backwards compatible
- major — breaking change
- Write a one-line summary — this becomes the
CHANGELOG.mdentry.
The custom changelog formatter automatically prepends an emoji based on bump type:
| Bump type | Emoji |
|---|---|
| major | 💥 |
| minor | ✨ |
| patch | 🐞 |
Commit the generated .changeset/*.md file alongside your code changes.
This repo uses changesets in independent mode — each package versions and publishes separately.
The full flow:
- You open a PR with code changes plus a changeset. CI runs
lint,test,test:e2e,build, andvalidate. - After merge to
master, thechangesets/actionbot opens (or updates) aVersion PackagesPR. This PR:- Consumes every pending changeset under
.changeset/ - Bumps the affected packages' versions in their
package.json - Regenerates each package's
CHANGELOG.mdwith the emoji-prefixed entries
- Consumes every pending changeset under
- Merging the Version PR triggers
pnpm changeset publishin CI, which:- Publishes bumped packages to npm (using
NPM_TOKENsecret stored in GitHub Actions) - Creates a GitHub Release per published package with the changelog entries
- Publishes bumped packages to npm (using
- Independent mode note: a single Version PR can bump multiple packages at
different levels — for example
@ngockhoi96/ctc@0.3.0(minor) alongside@ngockhoi96/ctc-react@0.2.1(patch). Packages are never locked in step.
When in doubt about bump type, default to patch for any code change and minor for any new exported function or option. Reserve major for removals or signature-breaking changes.
-
TypeScript strict — no
any, noascasts unless documented -
Named exports only — no default exports (enforced by Biome)
-
Biome handles lint + format:
pnpm lint:fixauto-fixes what it can -
Zero runtime dependencies in published packages — only browser native APIs
-
Conventional commits enforced by commitlint:
feat(clipboard): add new utility function fix(clipboard): handle edge case in Safari chore: update dependencies docs(readme): clarify install instructionsTypes:
feat,fix,chore,docs,test,ci,refactor,perf.
For vulnerability reports, see SECURITY.md. Do not open a public issue for security concerns — use GitHub's private vulnerability reporting.
Open a GitHub Discussion for general questions, or a bug/feature issue via the templates in the "New issue" chooser.