Timezone Tetris in Panama City

Last month I was pair‑programming with Carla, a junior dev clocked in from Málaga, when our React codebase needed yet another boilerplate component. Typing the same props scaffold for the third time, I joked, “We could write a CLI to spit this out faster than our internet can lag.” Forty‑five minutes later—between thunderstorms rolling over Panama City—we had a working create‑expat‑component command, built on oclif 4.21.0npm. That late‑night sprint reminded me how a tiny command‑line helper can erase hours of repetitive UI drudgery.


Why a Custom CLI Matters in 2025

Component libraries, Storybook setups, and Vite configs multiply the steps a newcomer must memorize. A bespoke CLI funnels tribal knowledge into one ergonomic npx call, leveling the field for boot‑camp grads and remote contractors alike. oclif, the Open CLI Framework maintained by Salesforce, abstracts flag parsing, plugin loading, and even auto‑update logic, so you can stay focused on generating gorgeous React code instead of parsing process.argvoclif.github.io.


Toolbelt at a Glance

Tool / ConceptOne‑liner purpose
oclif 4.21Framework for Node/TypeScript CLIs.
ts‑nodeRun TypeScript without pre‑compile.
chalkTerminal string styling.
CLI CommandWhat it does
npm i -g oclifInstalls oclif generator globally.
oclif generate mycliScaffolds a new CLI project.
npm run devRuns CLI in watch mode with ts‑node.
npm pack && npm i -g *.tgzTest install locally.

Concept Primer — Plain English


Step‑by‑Step Walkthrough

1 — Scaffold

bashCopyEditnpm i -g oclif
oclif generate react-cli    # prompts for TypeScript, npm scope, etc.
cd react-cli && npm i

The generator outputs a /src/commands folder with a sample hello.ts.

2 — Create a component Command

tsCopyEdit// src/commands/component.ts
import { Args, Command, Flags } from '@oclif/core';
import { writeFileSync, mkdirSync } from 'fs';
import * as path from 'path';
import chalk from 'chalk';

export default class Component extends Command {
  static description = 'Generate a typed React component';

  static args = {
    name: Args.string({ required: true, description: 'Component name' }),
  };

  static flags = {
    style: Flags.boolean({ char: 's', description: 'Add CSS module' }),
  };

  async run() {
    const { args, flags } = await this.parse(Component);
    const dir = path.resolve('src/components', args.name);
    mkdirSync(dir, { recursive: true });

    const jsx = `import React from 'react';
${flags.style ? `import styles from './${args.name}.module.css';\n` : ''}
export function ${args.name}() {
  return <div${flags.style ? ' className={styles.root}' : ''}>${args.name}</div>;
}
`;
    writeFileSync(path.join(dir, `${args.name}.tsx`), jsx);
    this.log(chalk.green(`✓ Created ${args.name}.tsx`));
  }
}

Line by line

3 — Run in Dev Mode

bashCopyEditnpm run dev component Button -s

ts-node-dev watches for file changes—perfect for rapid tweaks while your teammate in Brazil reviews the diff.

4 — Bundle & Publish

bashCopyEditnpm version minor
npm run build          # oclif compiles + ts-node-to-js
npm publish --access public

Now anyone can bootstrap components with npx @your-scope/react-cli component Card -s.


Common Pitfalls & Fixes

  1. “Cannot find module ts‑node/register”
    Happens when local vs. global dependencies mismatch. Fix: add ts-node to devDependencies even if you installed it globally.
  2. Flag Parsing Collisions
    Commands sharing -s across plugins can clash. Fix: leverage oclif’s //oclif.manifest.json to scope flags or switch to verbose --style.
  3. Big Binary Size on Windows
    pkg builds inflate from unnecessary node modules. Fix: list extraneous files in oclif.pack.exclude field.

Remote‑Work Insight Box

Reviewing CLI PRs async is easier than UI code. A teammate in Santo Domingo can run npm run test inside Docker—no browser context, no design diff. The repeatability of a CLI shrinks onboarding from days to minutes, especially when your team straddles six time zones.


Performance & Accessibility Checkpoints


Choosing the Right Distribution Strategy

StrategyProsCons
npm PublishInstant npx usage; semver tags.Users need Node installed.
Standalone TarballSingle binary; no Node runtime.Larger upload; tricky native deps.
Homebrew TapMac devs get brew install.Extra maintenance.

For internal teams, npm plus a private registry often wins; external dev‑tooling audiences may appreciate a one‑shot binary.


Wrap‑Up: Key Takeaways

Have improvements or stories from your own custom React CLI? Drop a comment below and let’s keep optimising across continents.


0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x