-
Notifications
You must be signed in to change notification settings - Fork 965
Expand file tree
/
Copy pathrun.cmd.ts
More file actions
136 lines (125 loc) · 5.26 KB
/
Copy pathrun.cmd.ts
File metadata and controls
136 lines (125 loc) · 5.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import chalk from 'chalk';
import type { Command, CommandOptions } from '@teambit/cli';
import { formatItem, formatSection } from '@teambit/cli';
import type { Logger } from '@teambit/logger';
import open from 'open';
import type { ApplicationMain } from './application.main.runtime';
function openBrowser(url: string): Promise<void> {
const openUrl =
process.env.BIT_VSCODE_EXTENSION === 'true'
? `vscode://bit.vscode-bit/open-browser?url=${encodeURIComponent(url)}`
: url;
return open(openUrl).then(() => undefined);
}
type RunOptions = {
dev: boolean;
verbose: boolean;
skipWatch: boolean;
watch: boolean;
ssr: boolean;
port: string;
args: string;
noBrowser: boolean;
};
export class RunCmd implements Command {
name = 'run [app-name]';
description = 'start an application component locally';
extendedDescription = `runs application components in their own development server, separate from the "bit start" UI.
apps are components that create deployable applications (React apps, Node.js servers, etc.).
when no app name is specified, automatically detects and runs the app if only one exists in the workspace.`;
helpUrl = 'reference/apps/apps-overview/';
arguments = [
{
name: 'app-name',
description:
"the app's name is registered by the app (run 'bit app list' to list the names of the available apps)",
},
];
alias = 'c';
group = 'run-serve';
_packageManagerArgs: string[] = []; // populated by yargs-adapter from anything after `--` (e.g. `bit run my-app -- --device --ios`)
options = [
['d', 'dev', 'start the application in dev mode.'],
['p', 'port [port-number]', 'port to run the app on'],
['v', 'verbose', 'show verbose output for inspection and print stack trace'],
// ['', 'skip-watch', 'avoid running the watch process that compiles components in the background'],
['w', 'watch', 'watch and compile your components upon changes'],
['n', 'no-browser', 'do not automatically open browser when ready'],
[
'a',
'args <argv>',
'the arguments passing to the app. for example, --args="--a=1 --b". don\'t forget to use quotes to wrap the value to escape special characters.',
],
] as CommandOptions;
constructor(
/**
* access to the extension instance.
*/
private application: ApplicationMain,
private logger: Logger
) {}
async wait([appName]: [string], { dev, watch, ssr, port: exactPort, args, noBrowser }: RunOptions) {
const idsAndNames = await this.application.listAppsIdsAndNames();
if (!idsAndNames.length) {
this.logger.console('no apps found');
process.exit(1);
}
const resolvedApp = appName ? appName : idsAndNames.length === 1 ? idsAndNames[0].name : undefined;
if (!resolvedApp) {
const runStr = chalk.cyan(`bit run <app-name>`);
const sortedNames = idsAndNames.map(({ name }) => name).sort((a, b) => a.localeCompare(b));
const items = sortedNames.map((name) => formatItem(name));
const section = formatSection('available apps', '', items);
this.logger.console(`multiple apps found, please specify one using "${runStr}".\n\n${section}`);
process.exit(1);
}
// merge any args passed after `--` (e.g. `bit run my-app -- --device --ios`) into the args string forwarded to the app.
const extraArgs = this._packageManagerArgs.join(' ');
const mergedArgs = [args, extraArgs].filter(Boolean).join(' ');
// remove wds logs until refactoring webpack to a worker through the Worker aspect.
this.logger.off();
const { port, errors, isOldApi } = await this.application.runApp(resolvedApp, {
dev,
watch,
ssr,
port: +exactPort,
args: mergedArgs,
});
if (errors) {
const errStr =
errors && errors.length ? errors.map((err) => err.toString()).join('\n') : 'unknown error occurred';
this.logger.console(errStr);
process.exit(1);
}
if (isOldApi) {
const url = `http://localhost:${port}`;
this.logger.console(`${appName} app is running on ${url}`);
if (!noBrowser && port) {
await openBrowser(url);
}
} else if (port) {
// New API - also open browser when port is available
const url = `http://localhost:${port}`;
// this.logger.console(`${appName} app is running on ${url}`);
if (!noBrowser) {
await openBrowser(url);
}
}
/**
* normally, when running "bit run <app-name>", the app is running in the background, which keeps the event loop busy.
* when the even loop is busy, the process doesn't exit, which is what we're looking for.
*
* however, if the app is not running in the background, the event loop is free, and the process exits. this is
* very confusing to the end user, because there is no error and no message indicating what's happening.
*
* this "beforeExit" event is a good place to catch this case and print a message to the user.
* it's better than using "exit" event, which can caused by the app itself running "process.exit".
* "beforeExit" is called when the event loop is empty and the process is about to exit.
*/
process.on('beforeExit', (code) => {
if (code === 0) {
this.logger.console('no app is running in the background, please check your app');
}
});
}
}