diff --git a/packages/create/src/cli.js b/packages/create/src/cli.js index 77ca874..e438f0f 100644 --- a/packages/create/src/cli.js +++ b/packages/create/src/cli.js @@ -151,14 +151,34 @@ exports.run = async function run(options = {}) { result.on("download", () => setLoadingMessage(spinner, "Downloading app...") ); - result.on("install", () => - setLoadingMessage(spinner, "Installing npm modules...") + result.on("install", installer => { + // Stop the spinner so the package manager's own output is readable. + clearTimeout(spinner.timeout); + spinner.stopAndPersist({ + symbol: chalk.cyan("→"), + text: `Installing dependencies with ${installer}...\n` + }); + }); + result.on("install-error", (_err, installer) => + spinner.warn( + `\`${installer} install\` did not finish cleanly. Your project was still ` + + `created — you may need to install dependencies manually.\n` + ) ); - result.on("init", () => setLoadingMessage(spinner, "Initializing repo...")); - const { projectPath, scripts: { start, dev } = {} } = await result; + result.on("init", () => { + spinner.start(); + setLoadingMessage(spinner, "Initializing repo..."); + }); + const { + projectPath, + scripts: { start, dev } = {}, + installer, + installed + } = await result; spinner.succeed( "Project created! To get started, run:\n\n" + chalk.cyan(` cd ${path.relative(process.cwd(), projectPath)}\n`) + + (installed ? "" : chalk.cyan(` ${installer} install\n`)) + (dev ? chalk.cyan(" npm run dev\n") : start diff --git a/packages/create/src/exec.js b/packages/create/src/exec.js index 0e1aa21..63b0965 100644 --- a/packages/create/src/exec.js +++ b/packages/create/src/exec.js @@ -2,10 +2,13 @@ const spawn = require("child_process").spawn; module.exports = function exec(cwd, bin, args) { return new Promise((resolve, reject) => { - spawn(bin, args, { + // Pass a single command string rather than (bin, args) with `shell: true`. + // Passing an args array together with `shell: true` triggers Node's DEP0190 + // deprecation warning. bin/args are always internally controlled here. + spawn([bin, ...args].join(" "), { cwd, shell: true, - stdio: "ignore", + stdio: "inherit", windowsHide: true }) .once("error", reject) diff --git a/packages/create/src/index.js b/packages/create/src/index.js index 1a681df..21ff951 100644 --- a/packages/create/src/index.js +++ b/packages/create/src/index.js @@ -56,10 +56,10 @@ async function create(options = {}, emitter) { await downloadRepo(template, projectPath, options, emitter); const { scripts } = await rewritePackageJson(projectPath, name); - await installPackages(installer, projectPath, emitter); + const installed = await installPackages(installer, projectPath, emitter); await initGitRepo(projectPath, emitter); - return { projectPath, scripts }; + return { projectPath, scripts, installer, installed }; } exports.getExamples = async function () { @@ -149,8 +149,17 @@ async function rewritePackageJson(fullPath, name) { } async function installPackages(installer, fullPath, emitter) { - emitter.emit("install"); - await exec(fullPath, installer, ["install"]); + emitter.emit("install", installer); + try { + await exec(fullPath, installer, ["install"]); + return true; + } catch (err) { + // Don't fail the whole scaffold if dependency install exits non-zero. + // Some package managers (e.g. pnpm's ignored-build-scripts warning) exit + // non-zero even though the project is usable, so warn and keep going. + emitter.emit("install-error", err, installer); + return false; + } } function getExampleUrl(example, tag) {