You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

575 lines
18 KiB

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.startAsync = startAsync;
function _devServer() {
const data = require("@expo/dev-server");
_devServer = function () {
return data;
};
return data;
}
function _chalk() {
const data = _interopRequireDefault(require("chalk"));
_chalk = function () {
return data;
};
return data;
}
function _wrapAnsi() {
const data = _interopRequireDefault(require("wrap-ansi"));
_wrapAnsi = function () {
return data;
};
return data;
}
function _xdl() {
const data = require("xdl");
_xdl = function () {
return data;
};
return data;
}
function _log() {
const data = _interopRequireDefault(require("../../log"));
_log = function () {
return data;
};
return data;
}
function _handleErrors() {
const data = require("../../utils/handleErrors");
_handleErrors = function () {
return data;
};
return data;
}
function _prompts() {
const data = require("../../utils/prompts");
_prompts = function () {
return data;
};
return data;
}
function _accounts() {
const data = require("../auth/accounts");
_accounts = function () {
return data;
};
return data;
}
function _TerminalLink() {
const data = require("../utils/TerminalLink");
_TerminalLink = function () {
return data;
};
return data;
}
function _openInEditorAsync() {
const data = require("../utils/openInEditorAsync");
_openInEditorAsync = function () {
return data;
};
return data;
}
function _urlOpts() {
const data = _interopRequireDefault(require("../utils/urlOpts"));
_urlOpts = function () {
return data;
};
return data;
}
function _ensureWebSetup() {
const data = require("../utils/web/ensureWebSetup");
_ensureWebSetup = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const CTRL_C = '\u0003';
const CTRL_D = '\u0004';
const CTRL_L = '\u000C';
const BLT = `\u203A`;
const {
bold: b,
italic: i,
underline: u
} = _chalk().default;
const printHelp = () => {
logCommandsTable([{
key: '?',
msg: 'show all commands'
}]);
};
const div = _chalk().default.dim(``);
const printUsageAsync = async (projectRoot, options) => {
const {
dev
} = await _xdl().ProjectSettings.readAsync(projectRoot);
const devMode = dev ? 'development' : 'production';
const isMac = process.platform === 'darwin';
const {
platforms = ['ios', 'android', 'web']
} = options;
const isAndroidDisabled = !platforms.includes('android');
const isIosDisabled = !platforms.includes('ios');
const isWebDisable = !platforms.includes('web');
logCommandsTable([{}, {
key: 'a',
msg: `open Android`,
disabled: isAndroidDisabled
}, {
key: 'shift+a',
msg: `select a device or emulator`,
disabled: isAndroidDisabled
}, isMac && {
key: 'i',
msg: `open iOS simulator`,
disabled: isIosDisabled
}, isMac && {
key: 'shift+i',
msg: `select a simulator`,
disabled: isIosDisabled
}, {
key: 'w',
msg: `open web`,
disabled: isWebDisable
}, {}, !!options.isRemoteReloadingEnabled && {
key: 'r',
msg: `reload app`
}, !!options.isWebSocketsEnabled && {
key: 'm',
msg: `toggle menu`
}, !!options.isWebSocketsEnabled && {
key: 'shift+m',
msg: `more tools`
}, !!options.isWebSocketsEnabled && {
key: 'j',
msg: `open JavaScript inspector for Hermes`
}, {
key: 'o',
msg: `open project code in your editor`
}, {
key: 'c',
msg: `show project QR`
}, {
key: 'p',
msg: `toggle build mode`,
status: devMode
},
// TODO: Drop with SDK 40
!options.isRemoteReloadingEnabled && {
key: 'r',
msg: `restart bundler`
}, !options.isRemoteReloadingEnabled && {
key: 'shift+r',
msg: `restart and clear cache`
}, {}]);
};
const printBasicUsageAsync = async options => {
const isMac = process.platform === 'darwin';
const {
platforms = ['ios', 'android', 'web']
} = options;
const isAndroidDisabled = !platforms.includes('android');
const isIosDisabled = !platforms.includes('ios');
const isWebDisable = !platforms.includes('web');
logCommandsTable([{}, {
key: 'a',
msg: `open Android`,
disabled: isAndroidDisabled
}, isMac && {
key: 'i',
msg: `open iOS simulator`,
disabled: isIosDisabled
}, {
key: 'w',
msg: `open web`,
disabled: isWebDisable
}, {}, !!options.isRemoteReloadingEnabled && {
key: 'r',
msg: `reload app`
}, !!options.isWebSocketsEnabled && {
key: 'm',
msg: `toggle menu`
}, {}]);
};
function logCommandsTable(ui) {
_log().default.nested(ui.filter(Boolean)
// @ts-ignore: filter doesn't work
.map(({
key,
msg,
status,
disabled
}) => {
if (!key) return '';
let view = `${BLT} `;
if (key.length === 1) view += 'Press ';
view += `${b(key)} ${div} `;
view += msg;
if (status) {
view += ` ${_chalk().default.dim(`(${i(status)})`)}`;
}
if (disabled) {
view = _chalk().default.dim(view);
}
return view;
}).join('\n'));
}
const printServerInfo = async (projectRoot, options) => {
const wrapLength = process.stdout.columns || 80;
const item = text => `${BLT} ` + (0, _wrapAnsi().default)(text, wrapLength).trimStart();
if (!options.webOnly) {
try {
const url = await _xdl().UrlUtils.constructDeepLinkAsync(projectRoot);
const getURLForQR = async () => {
const {
devClient
} = await _xdl().ProjectSettings.readAsync(projectRoot);
if (_xdl().Env.isInterstitiaLPageEnabled() && !devClient && (await (0, _xdl().isDevClientPackageInstalled)(projectRoot))) {
return await _xdl().UrlUtils.constructLoadingUrlAsync(projectRoot, null);
} else {
return url;
}
};
_urlOpts().default.printQRCode(await getURLForQR());
_log().default.nested(item(`Metro waiting on ${u(url)}`));
// Log.newLine();
// TODO: if development build, change this message!
_log().default.nested(item(`Scan the QR code above with Expo Go (Android) or the Camera app (iOS)`));
} catch (error) {
// @ts-ignore: If there is no development build scheme, then skip the QR code.
if (error.code !== 'NO_DEV_CLIENT_SCHEME') {
throw error;
} else {
const serverUrl = await _xdl().UrlUtils.constructManifestUrlAsync(projectRoot, {
urlType: 'http'
});
_log().default.nested(item(`Metro waiting on ${u(serverUrl)}`));
_log().default.nested(item(`Linking is disabled because the client scheme cannot be resolved.`));
}
}
}
const webUrl = await _xdl().Webpack.getUrlAsync(projectRoot);
if (webUrl) {
_log().default.addNewLineIfNone();
_log().default.nested(item(`Webpack waiting on ${u(webUrl)}`));
_log().default.nested(_chalk().default.gray(item(`Expo Webpack (web) is in beta, and subject to breaking changes!`)));
}
await printBasicUsageAsync(options);
printHelp();
_log().default.addNewLineIfNone();
};
async function openJsInsectorAsync(projectRoot) {
_log().default.log(`Opening JavaScript inspector in the browser...`);
const {
packagerPort
} = await _xdl().ProjectSettings.readPackagerInfoAsync(projectRoot);
const metroServerOrigin = `http://localhost:${packagerPort}`;
const apps = await (0, _devServer().queryAllInspectorAppsAsync)(metroServerOrigin);
if (apps.length === 0) {
_log().default.warn(`No compatible apps connected. This feature is only available for apps using the Hermes runtime. ${(0, _TerminalLink().learnMore)('https://docs.expo.dev/guides/using-hermes/')}`);
return;
}
for (const app of apps) {
(0, _devServer().openJsInspector)(app);
}
}
async function startAsync(projectRoot, options) {
const {
stdin
} = process;
const startWaitingForCommand = () => {
if (!stdin.setRawMode) {
_log().default.warn('Non-interactive terminal, keyboard commands are disabled. Please upgrade to Node 12+');
return;
}
stdin.setRawMode(true);
stdin.resume();
stdin.setEncoding('utf8');
stdin.on('data', handleKeypress);
};
const stopWaitingForCommand = () => {
stdin.removeListener('data', handleKeypress);
if (!stdin.setRawMode) {
_log().default.warn('Non-interactive terminal, keyboard commands are disabled. Please upgrade to Node 12+');
return;
}
stdin.setRawMode(false);
stdin.resume();
};
startWaitingForCommand();
_xdl().Prompts.addInteractionListener(({
pause
}) => {
if (pause) {
stopWaitingForCommand();
} else {
startWaitingForCommand();
}
});
_xdl().UserManager.setInteractiveAuthenticationCallback(async () => {
stopWaitingForCommand();
try {
return await (0, _accounts().loginOrRegisterIfLoggedOutAsync)();
} finally {
startWaitingForCommand();
}
});
await printServerInfo(projectRoot, options);
async function handleKeypress(key) {
try {
await handleKeypressAsync(key);
} catch (err) {
await (0, _handleErrors().handleErrorsAsync)(err, {});
process.exit(1);
}
}
async function handleKeypressAsync(key) {
const shouldPrompt = !options.nonInteractive && ['I', 'A'].includes(key);
if (shouldPrompt) {
_log().default.clear();
}
const {
platforms = ['ios', 'android', 'web']
} = options;
switch (key) {
case 'A':
case 'a':
if (options.webOnly && !_xdl().Webpack.isTargetingNative()) {
_log().default.log(`${BLT} Opening the web project in Chrome on Android...`);
const results = await _xdl().Android.openWebProjectAsync({
projectRoot,
shouldPrompt
});
if (!results.success) {
_log().default.nestedError(results.error);
}
} else {
var _options$devClient;
const isDisabled = !platforms.includes('android');
if (isDisabled) {
_log().default.nestedWarn(`Android is disabled, enable it by adding ${_chalk().default.bold`android`} to the platforms array in your app.json or app.config.js`);
break;
}
_log().default.log(`${BLT} Opening on Android...`);
const results = await _xdl().Android.openProjectAsync({
projectRoot,
shouldPrompt,
devClient: (_options$devClient = options.devClient) !== null && _options$devClient !== void 0 ? _options$devClient : false
});
if (!results.success && results.error !== 'escaped') {
_log().default.nestedError(typeof results.error === 'string' ? results.error : results.error.message);
}
}
printHelp();
break;
case 'I':
case 'i':
if (options.webOnly && !_xdl().Webpack.isTargetingNative()) {
_log().default.log(`${BLT} Opening the web project in Safari on iOS...`);
const results = await _xdl().Simulator.openWebProjectAsync({
projectRoot,
shouldPrompt
});
if (!results.success) {
_log().default.nestedError(results.error);
}
} else {
var _options$devClient2;
const isDisabled = !platforms.includes('ios');
if (isDisabled) {
_log().default.nestedWarn(`iOS is disabled, enable it by adding ${_chalk().default.bold`ios`} to the platforms array in your app.json or app.config.js`);
break;
}
_log().default.log(`${BLT} Opening on iOS...`);
const results = await _xdl().Simulator.openProjectAsync({
projectRoot,
shouldPrompt,
devClient: (_options$devClient2 = options.devClient) !== null && _options$devClient2 !== void 0 ? _options$devClient2 : false
});
if (!results.success && results.error !== 'escaped') {
_log().default.nestedError(results.error);
}
}
printHelp();
break;
}
switch (key) {
case CTRL_C:
case CTRL_D:
{
// @ts-ignore: Argument of type '"SIGINT"' is not assignable to parameter of type '"disconnect"'.
process.emit('SIGINT');
// Prevent terminal UI from accepting commands while the process is closing.
// Without this, fast typers will close the server then start typing their
// next command and have a bunch of unrelated things pop up.
_xdl().Prompts.pauseInteractions();
break;
}
case CTRL_L:
{
_log().default.clear();
break;
}
case '?':
{
await printUsageAsync(projectRoot, options);
break;
}
case 'w':
{
try {
if (await (0, _ensureWebSetup().ensureWebSupportSetupAsync)(projectRoot)) {
if (!platforms.includes('web')) {
var _options$platforms;
platforms.push('web');
(_options$platforms = options.platforms) === null || _options$platforms === void 0 ? void 0 : _options$platforms.push('web');
}
}
} catch (e) {
_log().default.nestedWarn(e.message);
break;
}
const isDisabled = !platforms.includes('web');
if (isDisabled) {
// Use warnings from the web support setup.
break;
}
// Ensure the Webpack dev server is running first
const isStarted = await _xdl().Webpack.getUrlAsync(projectRoot);
if (!isStarted) {
await _xdl().Project.startAsync(projectRoot, {
webOnly: true
});
// When this is the first time webpack is started, reprint the connection info.
await printServerInfo(projectRoot, options);
}
_log().default.log(`${BLT} Open in the web browser...`);
await _xdl().Webpack.openAsync(projectRoot);
printHelp();
break;
}
case 'c':
{
_log().default.clear();
await printServerInfo(projectRoot, options);
break;
}
case 'D':
case 'd':
{
_log().default.warn(`\n${BLT} Dev Tools Web UI has been removed. ${(0, _TerminalLink().learnMore)('https://blog.expo.dev/sunsetting-the-web-ui-for-expo-cli-ab12936d2206')}`);
break;
}
case 'j':
{
await openJsInsectorAsync(projectRoot);
break;
}
case 'm':
{
if (options.isWebSocketsEnabled) {
_log().default.log(`${BLT} Toggling dev menu`);
_xdl().Project.broadcastMessage('devMenu');
_xdl().Webpack.broadcastMessage('devMenu');
}
break;
}
case 'M':
{
if (options.isWebSocketsEnabled) {
_xdl().Prompts.pauseInteractions();
try {
const value = await (0, _prompts().selectAsync)({
// Options match: Chrome > View > Developer
message: `Dev tools ${_chalk().default.dim`(native only)`}`,
choices: [{
title: 'Inspect elements',
value: 'toggleElementInspector'
}, {
title: 'Toggle performance monitor',
value: 'togglePerformanceMonitor'
}, {
title: 'Toggle developer menu',
value: 'toggleDevMenu'
}, {
title: 'Reload app',
value: 'reload'
}
// TODO: Maybe a "View Source" option to open code.
// Toggling Remote JS Debugging is pretty rough, so leaving it disabled.
// { title: 'Toggle Remote Debugging', value: 'toggleRemoteDebugging' },
]
});
_xdl().Project.broadcastMessage('sendDevCommand', {
name: value
});
_xdl().Webpack.broadcastMessage('sendDevCommand', {
name: value
});
} catch {
// do nothing
} finally {
_xdl().Prompts.resumeInteractions();
printHelp();
}
}
break;
}
case 'p':
{
_log().default.clear();
const projectSettings = await _xdl().ProjectSettings.readAsync(projectRoot);
const dev = !projectSettings.dev;
await _xdl().ProjectSettings.setAsync(projectRoot, {
dev,
minify: !dev
});
_log().default.log(`Metro bundler is now running in ${_chalk().default.bold(dev ? 'development' : 'production')}${_chalk().default.reset(` mode.`)}
Please reload the project in Expo Go for the change to take effect.`);
printHelp();
break;
}
case 'r':
if (options.isRemoteReloadingEnabled) {
_log().default.log(`${BLT} Reloading apps`);
// Send reload requests over the dev servers
_xdl().Project.broadcastMessage('reload');
_xdl().Webpack.broadcastMessage('reload');
} else if (!options.webOnly) {
// [SDK 40]: Restart bundler
_log().default.clear();
_xdl().Project.startAsync(projectRoot, {
...options,
reset: false
});
_log().default.log('Restarting Metro bundler...');
}
break;
case 'R':
if (!options.isRemoteReloadingEnabled) {
// [SDK 40]: Restart bundler with cache
_log().default.clear();
_xdl().Project.startAsync(projectRoot, {
...options,
reset: true
});
_log().default.log('Restarting Metro bundler and clearing cache...');
}
break;
case 'o':
_log().default.log(`${BLT} Opening the editor...`);
await (0, _openInEditorAsync().openInEditorAsync)(projectRoot, {
editor: process.env.EXPO_EDITOR
});
}
}
}
//# sourceMappingURL=TerminalUI.js.map