Skip to content

Commit 4cb2e4e

Browse files
authored
feat: added package installation progress (#1134)
1 parent ec52cd9 commit 4cb2e4e

File tree

2 files changed

+74
-14
lines changed

2 files changed

+74
-14
lines changed

Diff for: .changeset/sour-rings-tell.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"create-t3-app": minor
3+
---
4+
5+
feat: added package installation progress

Diff for: cli/src/helpers/installDependencies.ts

+69-14
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,82 @@
11
import chalk from "chalk";
22
import { execa } from "execa";
3-
import ora from "ora";
4-
import { getUserPkgManager } from "~/utils/getUserPkgManager.js";
3+
import ora, { Ora } from "ora";
4+
import {
5+
getUserPkgManager,
6+
PackageManager,
7+
} from "~/utils/getUserPkgManager.js";
58
import { logger } from "~/utils/logger.js";
69

710
type Options = {
811
projectDir: string;
912
};
1013

14+
/*eslint-disable @typescript-eslint/no-floating-promises*/
15+
const runInstallCommand = async (
16+
pkgManager: PackageManager,
17+
projectDir: string,
18+
): Promise<Ora | null> => {
19+
switch (pkgManager) {
20+
// When using npm, inherit the stderr stream so that the progress bar is shown
21+
case "npm":
22+
await execa(pkgManager, ["install"], {
23+
cwd: projectDir,
24+
stderr: "inherit",
25+
});
26+
27+
return null;
28+
// When using yarn or pnpm, use the stdout stream and ora spinner to show the progress
29+
case "pnpm":
30+
const pnpmSpinner = ora("Running pnpm install...").start();
31+
const pnpmSubprocess = execa(pkgManager, ["install"], {
32+
cwd: projectDir,
33+
stdout: "pipe",
34+
});
35+
36+
await new Promise<void>((res, rej) => {
37+
pnpmSubprocess.stdout?.on("data", (data: Buffer) => {
38+
const text = data.toString();
39+
40+
if (text.includes("Progress")) {
41+
pnpmSpinner.text = text.includes("|")
42+
? text.split(" | ")[1] ?? ""
43+
: text;
44+
}
45+
});
46+
pnpmSubprocess.on("error", (e) => rej(e));
47+
pnpmSubprocess.on("close", () => res());
48+
});
49+
50+
return pnpmSpinner;
51+
case "yarn":
52+
const yarnSpinner = ora("Running yarn...").start();
53+
const yarnSubprocess = execa(pkgManager, [], {
54+
cwd: projectDir,
55+
stdout: "pipe",
56+
});
57+
58+
await new Promise<void>((res, rej) => {
59+
yarnSubprocess.stdout?.on("data", (data: Buffer) => {
60+
yarnSpinner.text = data.toString();
61+
});
62+
yarnSubprocess.on("error", (e) => rej(e));
63+
yarnSubprocess.on("close", () => res());
64+
});
65+
66+
return yarnSpinner;
67+
}
68+
};
69+
/*eslint-enable @typescript-eslint/no-floating-promises*/
70+
1171
export const installDependencies = async ({ projectDir }: Options) => {
1272
logger.info("Installing dependencies...");
1373
const pkgManager = getUserPkgManager();
14-
const spinner =
15-
pkgManager === "yarn"
16-
? ora("Running yarn...\n").start()
17-
: ora(`Running ${pkgManager} install...\n`).start();
18-
19-
// If the package manager is yarn, use yarn's default behavior to install dependencies
20-
if (pkgManager === "yarn") {
21-
await execa(pkgManager, [], { cwd: projectDir });
22-
} else {
23-
await execa(pkgManager, ["install"], { cwd: projectDir });
24-
}
2574

26-
spinner.succeed(chalk.green("Successfully installed dependencies!\n"));
75+
const installSpinner = await runInstallCommand(pkgManager, projectDir);
76+
77+
// If the spinner was used to show the progress, use succeed method on it
78+
// If not, use the succeed on a new spinner
79+
(installSpinner || ora()).succeed(
80+
chalk.green("Successfully installed dependencies!\n"),
81+
);
2782
};

0 commit comments

Comments
 (0)