Skip to content

Commit abd665b

Browse files
committed
fix(serve): fix incorrect message about app-scripts not being installed
fixes ionic-team#3563
1 parent 4dbe922 commit abd665b

3 files changed

Lines changed: 35 additions & 10 deletions

File tree

packages/ionic/src/definitions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ export interface IShell {
348348

349349
run(command: string, args: string[], options: IShellRunOptions): Promise<void>;
350350
output(command: string, args: string[], options: IShellOutputOptions): Promise<string>;
351-
spawn(command: string, args: string[], options: IShellSpawnOptions): ChildProcess;
351+
spawn(command: string, args: string[], options: IShellSpawnOptions): Promise<ChildProcess>;
352352
cmdinfo(cmd: string, args?: string[], options?: ShellCommandOptions): Promise<string | undefined>;
353353
}
354354

packages/ionic/src/lib/serve.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,7 @@ export abstract class ServeCLI<T extends ServeCLIOptions> extends EventEmitter {
493493
this.e.log.nl();
494494
this.e.log.info(
495495
`Looks like ${chalk.green(this.pkg)} isn't installed in this project.\n` +
496-
`This package is required for this command to work properly.`
496+
`This package is required for this command to work properly. The package provides a CLI utility, but the ${chalk.green(this.resolvedProgram)} binary was not found in your PATH.`
497497
);
498498

499499
const installed = await this.promptToInstall();
@@ -509,7 +509,7 @@ export abstract class ServeCLI<T extends ServeCLIOptions> extends EventEmitter {
509509

510510
protected async spawn(options: T): Promise<void> {
511511
const args = await this.buildArgs(options);
512-
const p = this.e.shell.spawn(this.resolvedProgram, args, { stdio: 'pipe', cwd: this.e.project.directory });
512+
const p = await this.e.shell.spawn(this.resolvedProgram, args, { stdio: 'pipe', cwd: this.e.project.directory });
513513

514514
return new Promise<void>((resolve, reject) => {
515515
const errorHandler = (err: NodeJS.ErrnoException) => {

packages/ionic/src/lib/shell.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { ERROR_SHELL_COMMAND_NOT_FOUND, LOGGER_LEVELS, ShellCommandError } from '@ionic/cli-framework';
22
import { createProcessEnv, killProcessTree, onBeforeExit } from '@ionic/cli-framework/utils/process';
3-
import { ShellCommand } from '@ionic/cli-framework/utils/shell';
3+
import { ShellCommand, which } from '@ionic/cli-framework/utils/shell';
44
import { combineStreams } from '@ionic/cli-framework/utils/streams';
55
import chalk from 'chalk';
6-
import { ChildProcess } from 'child_process';
6+
import { ChildProcess, SpawnOptions } from 'child_process';
77
import * as Debug from 'debug';
88
import * as path from 'path';
99
import * as split2 from 'split2';
@@ -32,7 +32,9 @@ export class Shell implements IShell {
3232

3333
async run(command: string, args: string[], { stream, killOnExit = true, showCommand = true, showError = true, fatalOnNotFound = true, fatalOnError = true, truncateErrorOutput, ...crossSpawnOptions }: IShellRunOptions): Promise<void> {
3434
this.prepareSpawnOptions(crossSpawnOptions);
35-
const cmd = new ShellCommand(command, args, crossSpawnOptions);
35+
36+
const cmdpath = await this.resolveCommandPath(command, crossSpawnOptions);
37+
const cmd = new ShellCommand(cmdpath, args, crossSpawnOptions);
3638

3739
const fullCmd = cmd.bashify();
3840
const truncatedCmd = fullCmd.length > 80 ? fullCmd.substring(0, 80) + '...' : fullCmd;
@@ -121,7 +123,8 @@ export class Shell implements IShell {
121123
}
122124

123125
async output(command: string, args: string[], { fatalOnNotFound = true, fatalOnError = true, showError = true, showCommand = false, ...crossSpawnOptions }: IShellOutputOptions): Promise<string> {
124-
const cmd = new ShellCommand(command, args, crossSpawnOptions);
126+
const cmdpath = await this.resolveCommandPath(command, crossSpawnOptions);
127+
const cmd = new ShellCommand(cmdpath, args, crossSpawnOptions);
125128

126129
const fullCmd = cmd.bashify();
127130
const truncatedCmd = fullCmd.length > 80 ? fullCmd.substring(0, 80) + '...' : fullCmd;
@@ -159,10 +162,31 @@ export class Shell implements IShell {
159162
}
160163
}
161164

162-
spawn(command: string, args: string[], { showCommand = true, ...crossSpawnOptions }: IShellSpawnOptions): ChildProcess {
165+
/**
166+
* When `child_process.spawn` isn't provided a full path to the command
167+
* binary, it behaves differently on Windows than other platforms. For
168+
* Windows, discover the full path to the binary, otherwise fallback to the
169+
* command provided.
170+
*
171+
* @see https://github.com/ionic-team/ionic-cli/issues/3563#issuecomment-425232005
172+
*/
173+
async resolveCommandPath(command: string, options: SpawnOptions): Promise<string> {
174+
if (process.platform === 'win32') {
175+
try {
176+
return await which(command, { PATH: options.env.PATH });
177+
} catch (e) {
178+
// ignore
179+
}
180+
}
181+
182+
return command;
183+
}
184+
185+
async spawn(command: string, args: string[], { showCommand = true, ...crossSpawnOptions }: IShellSpawnOptions): Promise<ChildProcess> {
163186
this.prepareSpawnOptions(crossSpawnOptions);
164187

165-
const cmd = new ShellCommand(command, args, crossSpawnOptions);
188+
const cmdpath = await this.resolveCommandPath(command, crossSpawnOptions);
189+
const cmd = new ShellCommand(cmdpath, args, crossSpawnOptions);
166190
const p = cmd.spawn();
167191

168192
if (showCommand && this.e.log.level >= LOGGER_LEVELS.INFO) {
@@ -176,7 +200,8 @@ export class Shell implements IShell {
176200
const opts: IShellSpawnOptions = {};
177201
this.prepareSpawnOptions(opts);
178202

179-
const cmd = new ShellCommand(command, args, opts);
203+
const cmdpath = await this.resolveCommandPath(command, opts);
204+
const cmd = new ShellCommand(cmdpath, args, opts);
180205

181206
try {
182207
const out = await cmd.output();

0 commit comments

Comments
 (0)