Skip to content

Commit def85e9

Browse files
authored
Merge pull request #57 from selemondev/perf/cli
perf(cli): replace chalk with a custom terminal colour functionality for a lightweight output
2 parents 5166c19 + 2d1d6d9 commit def85e9

File tree

6 files changed

+198
-110
lines changed

6 files changed

+198
-110
lines changed

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
"typescript": "^5.3.3"
5353
},
5454
"dependencies": {
55-
"chalk": "^5.3.0",
5655
"commander": "^12.0.0",
5756
"ejs": "^3.1.9",
5857
"fs-extra": "^11.2.0",
@@ -67,4 +66,4 @@
6766
"esbuild"
6867
]
6968
}
70-
}
69+
}

pnpm-lock.yaml

Lines changed: 0 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 50 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,62 @@
1-
import fs from 'fs-extra'
2-
import path from 'node:path'
3-
import options from '../../../core/utils/react/options'
4-
import { ejsRender } from '../../../utils/ejsRender'
5-
import chalk from "chalk"
6-
import { templateFilesMap } from '../../../core/utils/react/templateFile'
7-
import { getFilterFile } from '../../../filter/filterFiles'
8-
import { fileURLToPath } from 'node:url';
9-
import { dirname } from 'node:path';
10-
import ora from 'ora'
1+
import fs from "fs-extra";
2+
import path from "node:path";
3+
import options from "../../../core/utils/react/options";
4+
import { ejsRender } from "../../../utils/ejsRender";
5+
import termColors from "../../../utils/colors";
6+
import { templateFilesMap } from "../../../core/utils/react/templateFile";
7+
import { getFilterFile } from "../../../filter/filterFiles";
8+
import { fileURLToPath } from "node:url";
9+
import { dirname } from "node:path";
10+
import ora from "ora";
1111

1212
async function copyTemplate() {
13-
const __filename = fileURLToPath(import.meta.url);
13+
const __filename = fileURLToPath(import.meta.url);
1414

15-
const __dirname = dirname(__filename);
15+
const __dirname = dirname(__filename);
1616

17-
const spinner = ora('Copying template...').start();
17+
const spinner = ora("Copying template...").start();
1818

19-
const language = options.useTypeScript ? 'react-ts' : 'react-js';
19+
const language = options.useTypeScript ? "react-ts" : "react-js";
2020

21-
options.src = path.resolve(__dirname, `../template/${language}`);
21+
options.src = path.resolve(__dirname, `../template/${language}`);
2222

23-
const dest = options.name && path.resolve(process.cwd(), options.name)
24-
25-
options.dest = dest
23+
const dest = options.name && path.resolve(process.cwd(), options.name);
2624

27-
const templatePath = path.resolve(
28-
__dirname,
29-
`../../../../template/${language}`
30-
);
31-
options.templatePath = templatePath
25+
options.dest = dest;
3226

33-
const filterFileFn = getFilterFile()
27+
const templatePath = path.resolve(
28+
__dirname,
29+
`../../../../template/${language}`,
30+
);
31+
options.templatePath = templatePath;
3432

35-
async function copy() {
36-
const targetDirectory = path.resolve(__dirname, '../');
37-
if(!dest) {
38-
return;
39-
};
40-
await fs.copy(`${targetDirectory}/template/${language}`, dest)
33+
const filterFileFn = getFilterFile();
34+
35+
async function copy() {
36+
const targetDirectory = path.resolve(__dirname, "../");
37+
if (!dest) {
38+
return;
4139
}
42-
await copy();
43-
44-
filterFileFn && await filterFileFn();
45-
46-
options.dest && await fs.move(
47-
path.resolve(options.dest, '.gitignore.ejs'),
48-
path.resolve(options.dest, '.gitignore'),
49-
{ overwrite: true }
50-
);
51-
52-
await Promise.all(
53-
templateFilesMap
54-
.get('react')()
55-
.map((file: string) => options.name && ejsRender(file, options.name))
56-
)
57-
spinner.text = chalk.green('Template successfully copied!');
58-
59-
spinner.succeed()
40+
await fs.copy(`${targetDirectory}/template/${language}`, dest);
41+
}
42+
await copy();
43+
44+
filterFileFn && (await filterFileFn());
45+
46+
options.dest &&
47+
(await fs.move(
48+
path.resolve(options.dest, ".gitignore.ejs"),
49+
path.resolve(options.dest, ".gitignore"),
50+
{ overwrite: true },
51+
));
52+
53+
await Promise.all(
54+
templateFilesMap
55+
.get("react")()
56+
.map((file: string) => options.name && ejsRender(file, options.name)),
57+
);
58+
spinner.text = termColors.green("Template successfully copied!");
59+
60+
spinner.succeed();
6061
}
61-
export default copyTemplate
62+
export default copyTemplate;
Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,83 +1,81 @@
1-
import options from '../../../core/utils/react/options'
2-
import { logger } from '../../../utils/logger'
3-
import { createSpawnCmd } from '../../../utils/createSpawnCmd'
4-
import ora from 'ora';
5-
import chalk from "chalk"
1+
import options from "../../../core/utils/react/options";
2+
import { logger } from "../../../utils/logger";
3+
import { createSpawnCmd } from "../../../utils/createSpawnCmd";
4+
import ora from "ora";
5+
import termColors from "../../../utils/colors";
66
async function installDeps() {
7-
87
// No output will be shown in the console
9-
const cmdIgnore = createSpawnCmd(options.dest, 'ignore')
8+
const cmdIgnore = createSpawnCmd(options.dest, "ignore");
109

11-
const spinner = ora('Copying template...').start();
10+
const spinner = ora("Copying template...").start();
1211

1312
const startTime: number = new Date().getTime();
1413

1514
if (options.useGitInit) {
16-
await cmdIgnore('git', ['init'])
15+
await cmdIgnore("git", ["init"]);
1716

18-
await cmdIgnore('git', ['add .'])
17+
await cmdIgnore("git", ["add ."]);
1918

20-
await cmdIgnore('git', ['commit -m "Initialized by create-react-next"'])
19+
await cmdIgnore("git", ['commit -m "Initialized by create-react-next"']);
2120
}
2221

22+
if (options.package && options.package !== "none") {
23+
spinner.text = termColors.cyan(
24+
`Installing dependencies with ${options.package}. Please wait...`,
25+
);
2326

24-
if (options.package && options.package !== 'none') {
25-
spinner.text = chalk.cyan(`Installing dependencies with ${options.package}. Please wait...`);
26-
27-
await cmdIgnore(options.package, ['install']);
27+
await cmdIgnore(options.package, ["install"]);
2828
}
2929

3030
spinner.stop();
3131

32-
const endTime: number = new Date().getTime()
33-
const usageTime: number = (endTime - startTime) / 1000
32+
const endTime: number = new Date().getTime();
33+
const usageTime: number = (endTime - startTime) / 1000;
3434

35-
console.log()
35+
console.log();
3636

37-
logger.info(
38-
`🚀 Completed in ${usageTime}s`
39-
);
37+
logger.info(`🚀 Completed in ${usageTime}s`);
4038

41-
console.log()
39+
console.log();
4240

43-
logger.success('✅ Project created successfully')
41+
logger.success("✅ Project created successfully");
4442

45-
console.log()
43+
console.log();
4644

47-
logger.info(`cd ${options.name}`)
45+
logger.info(`cd ${options.name}`);
4846

49-
console.log()
47+
console.log();
5048

51-
if (options.package !== 'none') {
49+
if (options.package !== "none") {
5250
logger.info(
53-
options.package === 'npm'
51+
options.package === "npm"
5452
? `${options.package} run dev to start the dev server`
5553
: `${options.package} dev to start the dev server`,
56-
)
54+
);
5755

5856
options.useEslint && console.log();
5957

60-
options.useEslint && logger.info(`${options.package} run lint to format your code`)
61-
62-
options.useVitest && console.log()
63-
64-
options.useVitest && logger.info(`${options.package} run test:unit to run tests`);
58+
options.useEslint &&
59+
logger.info(`${options.package} run lint to format your code`);
6560

61+
options.useVitest && console.log();
6662

63+
options.useVitest &&
64+
logger.info(`${options.package} run test:unit to run tests`);
6765
} else {
68-
logger.info(`npm install - To install dependencies`)
66+
logger.info(`npm install - To install dependencies`);
6967

70-
console.log()
68+
console.log();
7169

72-
options.useEslint && logger.info('npm run lint to format your code')
70+
options.useEslint && logger.info("npm run lint to format your code");
7371

74-
options.useEslint && console.log()
72+
options.useEslint && console.log();
7573

76-
logger.info('npm run dev to start the dev server')
74+
logger.info("npm run dev to start the dev server");
7775

78-
options.useVitest && console.log()
76+
options.useVitest && console.log();
7977

80-
options.useVitest && logger.info('npm run test:unit to run tests')
78+
options.useVitest && logger.info("npm run test:unit to run tests");
8179
}
8280
}
83-
export default installDeps
81+
export default installDeps;

src/utils/colors.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// https://github.com/alexeyraspopov/picocolors/blob/main/picocolors.js
2+
const p = process || {};
3+
const argv = p.argv || [];
4+
const env = p.env || {};
5+
const isColorSupported =
6+
!(!!env.NO_COLOR || argv.includes("--no-color")) &&
7+
(!!env.FORCE_COLOR ||
8+
argv.includes("--color") ||
9+
p.platform === "win32" ||
10+
((p.stdout || {}).isTTY && env.TERM !== "dumb") ||
11+
!!env.CI);
12+
13+
function formatter(open: string, close: string, replace = open) {
14+
return (input: string) => {
15+
const string = `${input}`;
16+
const index = string.indexOf(close, open.length);
17+
return ~index
18+
? open + replaceClose(string, close, replace, index) + close
19+
: open + string + close;
20+
};
21+
}
22+
23+
function replaceClose(
24+
string: string,
25+
close: string,
26+
replace: string,
27+
index: number,
28+
) {
29+
let result = "";
30+
let cursor = 0;
31+
do {
32+
result += string.substring(cursor, index) + replace;
33+
cursor = index + close.length;
34+
index = string.indexOf(close, cursor);
35+
} while (~index);
36+
return result + string.substring(cursor);
37+
}
38+
39+
function createColors(enabled = isColorSupported) {
40+
const f = enabled ? formatter : () => String;
41+
return {
42+
isColorSupported: enabled,
43+
reset: f("\x1B[0m", "\x1B[0m"),
44+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
45+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
46+
italic: f("\x1B[3m", "\x1B[23m"),
47+
underline: f("\x1B[4m", "\x1B[24m"),
48+
inverse: f("\x1B[7m", "\x1B[27m"),
49+
hidden: f("\x1B[8m", "\x1B[28m"),
50+
strikethrough: f("\x1B[9m", "\x1B[29m"),
51+
52+
black: f("\x1B[30m", "\x1B[39m"),
53+
red: f("\x1B[31m", "\x1B[39m"),
54+
green: f("\x1B[32m", "\x1B[39m"),
55+
yellow: f("\x1B[33m", "\x1B[39m"),
56+
blue: f("\x1B[34m", "\x1B[39m"),
57+
magenta: f("\x1B[35m", "\x1B[39m"),
58+
cyan: f("\x1B[36m", "\x1B[39m"),
59+
white: f("\x1B[37m", "\x1B[39m"),
60+
gray: f("\x1B[90m", "\x1B[39m"),
61+
orange: f("\x1B[38;5;208m", "\x1B[39m"),
62+
63+
bgBlack: f("\x1B[40m", "\x1B[49m"),
64+
bgRed: f("\x1B[41m", "\x1B[49m"),
65+
bgGreen: f("\x1B[42m", "\x1B[49m"),
66+
bgYellow: f("\x1B[43m", "\x1B[49m"),
67+
bgBlue: f("\x1B[44m", "\x1B[49m"),
68+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
69+
bgCyan: f("\x1B[46m", "\x1B[49m"),
70+
bgWhite: f("\x1B[47m", "\x1B[49m"),
71+
72+
blackBright: f("\x1B[90m", "\x1B[39m"),
73+
redBright: f("\x1B[91m", "\x1B[39m"),
74+
greenBright: f("\x1B[92m", "\x1B[39m"),
75+
yellowBright: f("\x1B[93m", "\x1B[39m"),
76+
blueBright: f("\x1B[94m", "\x1B[39m"),
77+
magentaBright: f("\x1B[95m", "\x1B[39m"),
78+
cyanBright: f("\x1B[96m", "\x1B[39m"),
79+
whiteBright: f("\x1B[97m", "\x1B[39m"),
80+
81+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
82+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
83+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
84+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
85+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
86+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
87+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
88+
bgWhiteBright: f("\x1B[107m", "\x1B[49m"),
89+
};
90+
}
91+
92+
const termColors = createColors();
93+
export default termColors;

src/utils/logger.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
1-
import chalk from "chalk";
1+
import termColors from "./colors";
22

33
export const logger = {
4-
info: (...args: any[]) => {
5-
console.log(chalk.cyan(...args))
6-
},
4+
info: (...args: any[]) => {
5+
console.log(termColors.cyan(String(...args)));
6+
},
77

8-
error: (...args: any[]) => {
9-
console.log(chalk.red(...args))
10-
},
8+
error: (...args: any[]) => {
9+
console.log(termColors.red(String(...args)));
10+
},
1111

12-
warning: (...args: any[]) => {
13-
console.log(chalk.yellow(...args))
14-
},
12+
warning: (...args: any[]) => {
13+
console.log(termColors.yellow(String(...args)));
14+
},
1515

16-
success: (...args: any[]) => {
17-
console.log(chalk.green(...args))
18-
}
19-
};
16+
success: (...args: any[]) => {
17+
console.log(termColors.green(String(...args)));
18+
},
19+
};

0 commit comments

Comments
 (0)