Development Guide
How to contribute and build the library
This page explains how to contribute to BeautifulCLI — the combined toolkit that includes chalk for terminal styling and degit for project scaffolding. You will find everything you need to set up a local development environment, build the library, and submit quality contributions. Following these guidelines helps maintainers review and merge your work efficiently and keeps the project healthy for everyone.
Before contributing, make sure you have the following installed and configured:
- Node.js ≥ 8.0.0
- npm (bundled with Node.js)
- git — required to clone the repository and submit pull requests
- A working terminal with a shell that supports standard UNIX commands
- Familiarity with Node.js module authoring and ES module syntax (the codebase uses
import/export)
You should also read and agree to the Contributor Covenant Code of Conduct before participating.
Follow these steps to set up the BeautifulCLI repository locally.
-
Fork and clone the repository
git clone https://github.com/<your-username>/beautifulcli.git cd beautifulcli -
Install all dependencies
npm install -
Build the degit bundle
The
degitcomponent uses Rollup to produce a CommonJS distribution indist/. After editing source files undersrc/, rebuild with:npx rollup --config members/degit/rollup.config.jsRollup bundles two entry points —
src/index.js(the programmatic API) andsrc/bin.js(the CLI binary) — intodist/index.jsanddist/bin.jsrespectively, with source maps. -
Verify your setup
Run the benchmark suite to confirm chalk is wired up correctly:
node benchmark.jsYou should see timing output for each style combination (1 style, 2 styles, 3 styles, cached variants, and template literal usage).
Most build-time behaviour is controlled by the Rollup configuration in members/degit/rollup.config.js. The key options and their effects are described below.
| Option | Default | Effect |
|---|---|---|
input.index | src/index.js | Entry point for the programmatic API that consumers import from degit. |
input.bin | src/bin.js | Entry point for the degit CLI binary. |
output.dir | dist | Directory where compiled files are written. Do not commit the dist/ folder; it is generated on release. |
output.format | cjs | Output module format. CommonJS is used for broadest Node.js compatibility. |
output.sourcemap | true | Emits .js.map files alongside each bundle so stack traces point to original source lines. Change to false only when debugging bundle size. |
output.exports | auto | Lets Rollup decide between named and default exports automatically. |
external | All dependencies + Node.js built-ins | Packages listed in package.json dependencies and all Node.js built-in modules are excluded from the bundle and expected to be present at runtime. |
For the chalk component, there is no separate build step — chalk ships its source directly as ES modules. No additional configuration is required.
Writing and testing chalk changes
Chalk's API is entirely contained in index.js. When you modify a style, color, or chaining behaviour, validate your change by writing a small script that exercises the affected code path:
import chalk from './index.js';
// Test a single style
console.log(chalk.red('Changed style'));
// Test chaining
console.log(chalk.bold.blue.bgWhite('Chained styles'));
// Test 256-color and RGB
console.log(chalk.ansi256(196)('256-color red'));
console.log(chalk.rgb(255, 136, 0)('RGB orange'));
Run the script with:
node my-test.js
Benchmarking chalk changes
If your change touches the hot path (style resolution or ANSI code generation), run the benchmark before and after to check for regressions:
node benchmark.js
The benchmark covers the most common patterns: single styles, chained styles (2–3 modifiers), cached style instances, strings with embedded newlines, nested styles, and template literal usage.
Building and testing degit changes
After editing files under src/, rebuild the dist bundle:
npx rollup --config members/degit/rollup.config.js
Then test the CLI directly from the built output:
node dist/bin.js user/repo my-output-dir
Or exercise the programmatic API:
import degit from './dist/index.js';
const emitter = degit('user/repo', { cache: false, verbose: true });
await emitter.clone('my-output-dir');
Submitting a pull request
- Create a feature branch:
git checkout -b feat/my-improvement - Make your changes and rebuild as needed.
- Commit with a clear message describing what and why.
- Push and open a pull request against the
mainbranch.
Example 1 — Running the chalk benchmark to establish a performance baseline
node benchmark.js
Expected output (timings will vary by machine):
chalk
1 style .............. 1,234,567 ops/sec
2 styles .............. 987,654 ops/sec
3 styles .............. 876,543 ops/sec
cached: 1 style .............. 2,345,678 ops/sec
...
Use these numbers as a reference. If a pull request causes a measurable drop in ops/sec for cached or single-style cases, investigate before merging.
Example 2 — Building the degit bundle with Rollup and verifying the output
npx rollup --config members/degit/rollup.config.js
ls dist/
Expected output:
bin.js bin.js.map
index.js index.js.map
The two .map files confirm source maps were emitted. If they are missing, check that output.sourcemap is true in members/degit/rollup.config.js.
Example 3 — Manually verifying a chalk style change
// verify-style.js
import chalk from './index.js';
console.log(chalk.green('✔ Success'));
console.log(chalk.bold.red('✖ Error'));
console.log(chalk.blue.bgWhite.underline('ℹ Info'));
node verify-style.js
Expected terminal output: three lines of styled text — a green success message, a bold red error, and a blue underlined info message on a white background.
Example 4 — Smoke-testing the rebuilt degit CLI
node dist/bin.js tiged/tiged test-output --verbose
ls test-output/
Expected: the repository files appear in test-output/ with no .git directory present, confirming that history was stripped and only a snapshot was downloaded.
Issue: rollup command not found after npm install
- Symptom: Running
npx rollup --config members/degit/rollup.config.jsoutputscommand not foundorCannot find module. - Cause: Rollup and its plugins are declared as dev dependencies. If
npm installwas skipped or failed, the local binary is missing. - Fix: Run
npm installfrom the repository root, then retry the Rollup command.
Issue: dist/ files are stale or missing after editing src/
- Symptom: Changes to
src/index.jsorsrc/bin.jsare not reflected when runningnode dist/index.jsornode dist/bin.js. - Cause: The
dist/folder is not rebuilt automatically; it requires an explicit Rollup invocation. - Fix: Always run
npx rollup --config members/degit/rollup.config.jsafter editing source files before testing the built output.
Issue: benchmark.js fails with a syntax or import error
- Symptom: Running
node benchmark.jsthrowsSyntaxError: Cannot use import statementor similar. - Cause: The benchmark uses ES module
importsyntax. Node.js requires either a.mjsextension or"type": "module"inpackage.jsonto treat.jsfiles as ES modules. - Fix: Run with a Node.js version ≥ 8.0.0 and confirm
package.jsonincludes"type": "module". Do not renamebenchmark.jsto work around this — fix the project configuration instead.
Issue: Chalk produces no color output in the terminal during development
- Symptom: Styled strings print as plain text with no ANSI codes.
- Cause: Chalk automatically disables color when it detects that the output is not a TTY (for example, when output is piped), or when the
NO_COLORenvironment variable is set. - Fix: Run your script directly in a terminal rather than piping output. If you need to force colors for testing purposes, you can check chalk's color-level detection behavior, but do not hard-code ANSI escape codes manually — let chalk manage them.
Issue: Rollup emits warnings about missing named exports
- Symptom: During the build you see
(!) Missing exportsorMixing named and default exportswarnings. - Cause: The
output.exports: 'auto'setting infers export style. Ifsrc/index.jsmixes default and named exports inconsistently, Rollup may warn. - Fix: Ensure
src/index.jsuses a single consistent export style. If the module has one primary export, useexport default. Do not changeoutput.exportsto suppress the warning without fixing the underlying inconsistency.