microsoft/vscode-react-native

Public

mirrored from https://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.9.2

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/exponent/exponentPlatform.ts

193lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import * as url from "url";
5import * as vscode from "vscode";
6import * as nls from "vscode-nls";
7import { ErrorHelper } from "../../common/error/errorHelper";
8import { InternalErrorCode } from "../../common/error/internalErrorCode";
9import { ExpoHostType, IExponentRunOptions, PlatformType } from "../launchArgs";
10import { GeneralPlatform, MobilePlatformDeps } from "../generalPlatform";
11import { TelemetryHelper } from "../../common/telemetryHelper";
12import { QRCodeContentProvider } from "../qrCodeContentProvider";
13import { ExponentHelper } from "./exponentHelper";
14
15import * as XDL from "./xdlInterface";
16
17nls.config({
18 messageFormat: nls.MessageFormat.bundle,
19 bundleFormat: nls.BundleFormat.standalone,
20})();
21const localize = nls.loadMessageBundle();
22
23export class ExponentPlatform extends GeneralPlatform {
24 private exponentTunnelPath: string | null;
25 private exponentHelper: ExponentHelper;
26 private qrCodeContentProvider: QRCodeContentProvider = new QRCodeContentProvider();
27
28 constructor(runOptions: IExponentRunOptions, platformDeps: MobilePlatformDeps = {}) {
29 super(runOptions, platformDeps);
30 this.exponentHelper = this.packager.getExponentHelper();
31 this.exponentTunnelPath = null;
32 }
33
34 public async runApp(): Promise<void> {
35 let extProps = {
36 platform: {
37 value: PlatformType.Exponent,
38 isPii: false,
39 },
40 };
41
42 extProps = TelemetryHelper.addPlatformPropertiesToTelemetryProperties(
43 this.runOptions,
44 this.runOptions.reactNativeVersions,
45 extProps,
46 );
47
48 await TelemetryHelper.generate("ExponentPlatform.runApp", extProps, async () => {
49 await this.loginToExponentOrSkip(this.runOptions.expoHostType);
50 await XDL.setOptions(this.projectPath, { packagerPort: this.packager.getPort() });
51 await XDL.startExponentServer(this.projectPath);
52
53 // the purpose of this is to save the same sequence of handling 'adb reverse' command execution as in Expo
54 // https://github.com/expo/expo-cli/blob/1d515d21200841e181518358fd9dc4c7b24c7cd6/packages/xdl/src/Project.ts#L2226-L2370
55 // we added this to be sure that our Expo launching logic doesn't have any negative side effects
56
57 if (this.runOptions.expoHostType === "tunnel") {
58 await this.prepareExpoTunnels();
59 } else {
60 await XDL.stopAdbReverse(this.projectPath);
61 }
62
63 const isAdbReversed =
64 this.runOptions.expoHostType !== "local"
65 ? false
66 : // we need to execute 'adb reverse' command to bind ports used by Expo and RN of local machine to ports of a connected Android device or a running emulator
67 await XDL.startAdbReverse(this.projectPath);
68 let exponentUrl = "";
69 switch (this.runOptions.expoHostType) {
70 case "lan":
71 exponentUrl = await XDL.getUrl(this.projectPath, {
72 dev: true,
73 minify: false,
74 hostType: "lan",
75 });
76 break;
77 case "local":
78 if (isAdbReversed) {
79 this.logger.info(
80 localize(
81 "ExpoStartAdbReverseSuccess",
82 "A device or an emulator was found, 'adb reverse' command successfully executed.",
83 ),
84 );
85 } else {
86 this.logger.warning(
87 localize(
88 "ExpoStartAdbReverseFailure",
89 "Adb reverse command failed. Couldn't find connected over usb device or running emulator. Also please make sure that there is only one currently connected device or running emulator.",
90 ),
91 );
92 }
93
94 exponentUrl = await XDL.getUrl(this.projectPath, {
95 dev: true,
96 minify: false,
97 hostType: "localhost",
98 });
99 break;
100 case "tunnel":
101 default:
102 exponentUrl = await XDL.getUrl(this.projectPath, { dev: true, minify: false });
103 }
104 exponentUrl = `exp://${String(url.parse(exponentUrl).host)}`;
105
106 if (!exponentUrl) {
107 throw ErrorHelper.getInternalError(InternalErrorCode.ExpectedExponentTunnelPath);
108 }
109
110 if (this.runOptions.openExpoQR) {
111 const exponentPage = vscode.window.createWebviewPanel(
112 "Expo QR Code",
113 "Expo QR Code",
114 vscode.ViewColumn.Two,
115 {},
116 );
117 exponentPage.webview.html = this.qrCodeContentProvider.provideTextDocumentContent(
118 vscode.Uri.parse(exponentUrl),
119 );
120 }
121
122 this.exponentTunnelPath = exponentUrl;
123 const outputMessage = localize(
124 "ExponentServerIsRunningOpenToSeeIt",
125 "Expo server is running. Open your Expo app at {0} to see it.",
126 this.exponentTunnelPath,
127 );
128 this.logger.info(outputMessage);
129
130 const copyButton = localize("CopyToClipboard", "Copy to clipboard");
131
132 void vscode.window.showInformationMessage(outputMessage, copyButton).then(selection => {
133 if (selection === copyButton) {
134 void vscode.env.clipboard.writeText(exponentUrl);
135 }
136 });
137 });
138 }
139
140 public async loginToExponentOrSkip(expoHostType?: ExpoHostType): Promise<any> {
141 if (expoHostType !== "tunnel") {
142 return;
143 }
144
145 return await this.exponentHelper.loginToExponent(
146 async (message, password) =>
147 (await vscode.window.showInputBox({
148 placeHolder: message,
149 password,
150 })) || "",
151 async message => {
152 const okButton = { title: "Ok" };
153 const cancelButton = { title: "Cancel", isCloseAffordance: true };
154 const answer = await vscode.window.showInformationMessage(
155 message,
156 { modal: true },
157 okButton,
158 cancelButton,
159 );
160 if (answer === cancelButton) {
161 throw ErrorHelper.getInternalError(InternalErrorCode.UserCancelledExpoLogin);
162 }
163 return "";
164 },
165 );
166 }
167
168 public async beforeStartPackager(): Promise<void> {
169 return this.exponentHelper.configureExponentEnvironment();
170 }
171
172 public async enableJSDebuggingMode(): Promise<void> {
173 this.logger.info(
174 localize(
175 "ApplicationIsRunningOnExponentShakeDeviceForRemoteDebugging",
176 "Application is running on Expo. Please shake device and select 'Debug JS Remotely' to enable debugging.",
177 ),
178 );
179 }
180
181 public getRunArguments(): string[] {
182 return [];
183 }
184
185 private async prepareExpoTunnels(): Promise<void> {
186 try {
187 await this.exponentHelper.findOrInstallNgrokGlobally();
188 await XDL.startTunnels(this.projectPath);
189 } finally {
190 this.exponentHelper.removeNodeModulesPathFromEnvIfWasSet();
191 }
192 }
193}