Skip to main content

CLI Tools

Custom command-line utilities built for the Bitrate project.

📦 Overview

The project includes several reusable CLI tools built as standalone packages:

PackageCommandPurpose
@bitrate/svgrreact-svgrSVG → React components
@bitrate/vite-svgrVite plugin: SVG generation in build pipeline
@bitrate/convertermedia-converterAudio/video conversion

All tools follow the same pattern:

  • ✅ CLI with --help flag
  • ✅ Programmatic API
  • ✅ TypeScript support
  • ✅ Fast execution

⚡ vite-svgr

Vite plugin that integrates @bitrate/svgr into the Vite build pipeline — no separate pre-build step needed.

Installation

pnpm add @bitrate/vite-svgr

Usage

Add to vite.config.ts before other plugins so SVG components are generated before transforms run:

import { svgrPlugin } from '@bitrate/vite-svgr'
import { defineConfig } from 'vite'

export default defineConfig({
plugins: [
svgrPlugin({
input: './assets/icons', // supports @scope/pkg/subpath
output: 'src/icons/svgr',
variables: ['primaryColor', 'secondaryColor'],
}),
// ... other plugins
],
})

Options

OptionTypeDescriptionRequired
inputstringSVG source directory (supports @scope/pkg/subpath, relative, or absolute paths)
outputstringOutput directory for generated React components
variablesstring[]Color variable names for multicolor icons

Features

  • Build mode: runs once in buildStart, before any module transforms
  • Watch mode (vite build --watch): re-generates on any .svg change
  • Dev server (vite dev / Storybook): attaches to chokidar, triggers full-reload on SVG changes
  • Package path resolution: @scope/package/subpath resolved via pnpm workspace
  • Automatic cleanup: cleans output dir before each generation

🎨 svgr

Convert SVG files to React components with dynamic color support.

Installation

pnpm add @bitrate/svgr

CLI Usage

# Build mode
react-svgr build \
-i ./assets/icons \
-o src/icons/svgr \
--variables "primaryColor,secondaryColor"

# Watch mode
react-svgr dev \
-i ./assets/icons \
-o src/icons/svgr

Options

FlagShortDescriptionRequired
--input-iInput directory/package
--output-oOutput directory
--variables-Color variable names

Input

SVG files with fill or stroke attributes:

<!-- icons/music.svg -->
<svg viewBox="0 0 24 24">
<path fill="#000000" d="M12 3v10.55..."/>
<circle fill="#FF0000" cx="9" cy="17" r="3"/>
</svg>

Output

React components with props:

// src/icons/svgr/Music.tsx
export interface MusicProps {
primaryColor?: string
secondaryColor?: string
className?: string
}

export const Music: React.FC<MusicProps> = ({
primaryColor = '#000000',
secondaryColor = '#FF0000',
className
}) => (
<svg viewBox="0 0 24 24" className={className}>
<path fill={primaryColor} d="M12 3v10.55..."/>
<circle fill={secondaryColor} cx="9" cy="17" r="3"/>
</svg>
)

Usage in Code

import { Music } from './icons/svgr/Music'

<Music
primaryColor="#3b82f6"
secondaryColor="#f59e0b"
className="w-6 h-6"
/>

🎵 media-converter

Convert media files using FFmpeg (Audio → OGG Opus, Video → AAC).

Installation

pnpm add @bitrate/converter

Prerequisites

FFmpeg must be installed:

# Ubuntu/Debian
sudo apt install ffmpeg

# macOS
brew install ffmpeg

# Windows
# Download from https://ffmpeg.org/download.html

CLI Usage

Audio Conversion

# Default (128k CBR)
media-converter audio -i song.mp3

# Custom bitrate with VBR
media-converter audio -i song.mp3 -b 192k -v

# Voice optimization
media-converter audio -i podcast.mp3 --application voip -b 64k

# High quality
media-converter audio -i song.flac -b 256k -v -q 10

Video Conversion

# Extract audio from video
media-converter video -i movie.mp4

# Custom bitrate
media-converter video -i movie.mp4 -b 192k -q 2

# HE-AAC for low bitrates
media-converter video -i video.avi -b 64k --profile aac_he

Audio Options

FlagDescriptionDefault
-i, --inputInput fileRequired
-o, --outputOutput fileinput.opus
-b, --bitrateBitrate (64k-320k)128k
-q, --qualityCompression (0-10)10
-v, --vbrEnable VBRfalse
--applicationaudio/voip/lowdelayaudio

Video Options

FlagDescriptionDefault
-i, --inputInput fileRequired
-o, --outputOutput fileinput.m4a
-b, --bitrateBitrate128k
-q, --qualityQuality (0.1-2)1
--profileAAC profileaac_low

Programmatic API

import { convertAudio, convertVideo } from '@bitrate/converter'

// Audio conversion
const result = await convertAudio({
input: 'song.mp3',
output: 'song.opus',
bitrate: '192k',
quality: 10,
vbr: true,
application: 'audio'
})

console.log(result)
// {
// input: 'song.mp3',
// output: 'song.opus',
// inputSize: '5.2 MB',
// outputSize: '3.1 MB'
// }

// Video conversion
const videoResult = await convertVideo({
input: 'movie.mp4',
output: 'audio.m4a',
bitrate: '192k',
quality: 1.5,
profile: 'aac_low'
})

🔄 Using in npm Scripts

package.json Example

{
"scripts": {
"icons": "react-svgr build -i ./assets/icons -o src/icons",
"icons:watch": "react-svgr dev -i ./assets/icons -o src/icons",
"build": "vite build",
"dev": "vite build --watch",
"convert": "media-converter audio -i input.mp3 -o output.opus"
}
}

Running Scripts

# Generate tokens
pnpm tokens

# Build icons
pnpm icons

# Watch icons
pnpm icons:watch

# Build package (SVG generation + Vite build, all in one)
pnpm build

# Watch mode
pnpm dev

📝 Best Practices

1. Version Control

Add generated files to .gitignore:

# Generated files
/dist
/src/styles/palette.css
/src/styles/layout.css
/src/icons/svgr/

2. CI/CD Integration

# .github/workflows/build.yml
- name: Generate tokens
run: pnpm tokens

- name: Generate icons
run: pnpm icons

- name: Build packages
run: pnpm build

3. Type Safety

Import generated types:

import type { MusicProps } from './icons/svgr/Music'

4. Performance

Use watch mode during development:

# Terminal 1: Watch icons
pnpm icons:watch

# Terminal 2: Watch build
pnpm dev

🐛 Troubleshooting

Command Not Found

# Install package
pnpm install

# Or use pnpm exec

FFmpeg Not Found

# Verify installation
ffmpeg -version

# Install if missing (see Prerequisites)

Build Errors

# Clean and rebuild
rm -rf dist node_modules
pnpm install
pnpm build

Next: Deployment - Deploy to production