microsoft/vscode-react-native

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
e7a2c40d1102db28f3c062f2c66fc12d706ec850

Branches

Tags

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

Clone

HTTPS

Download ZIP

src/debugger/scriptImporter.ts

194lines · modeblame

a31b007cunknown10 years ago1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
a6562589RedMickey6 years ago4import { logger } from "vscode-debugadapter";
0a68f8dbArtem Egorov8 years ago5import { ensurePackagerRunning } from "../common/packagerStatus";
3fb37ad5unknown10 years ago6import path = require("path");
34472878RedMickey5 years ago7import { Request } from "../common/node/request";
8import { SourceMapUtil } from "./sourceMap";
3fb37ad5unknown10 years ago9import url = require("url");
a1324704Artem Egorov8 years ago10import * as semver from "semver";
0d77292aJiglioNero4 years ago11import { ProjectVersionHelper } from "../common/projectVersionHelper";
d124bf0eYuri Skorokhodov7 years ago12import { ErrorHelper } from "../common/error/errorHelper";
13import { InternalErrorCode } from "../common/error/internalErrorCode";
ce5e88eeYuri Skorokhodov5 years ago14import { FileSystem } from "../common/node/fileSystem";
3fb37ad5unknown10 years ago15
5c8365a6Artem Egorov8 years ago16export interface DownloadedScript {
4677921cdigeff10 years ago17contents: string;
18filepath: string;
19}
20
5c8365a6Artem Egorov8 years ago21interface IStrictUrl extends url.Url {
22pathname: string;
23href: string;
24}
25
3fb37ad5unknown10 years ago26export class ScriptImporter {
2743f19cdlebu10 years ago27public static DEBUGGER_WORKER_FILE_BASENAME = "debuggerWorker";
28public static DEBUGGER_WORKER_FILENAME = ScriptImporter.DEBUGGER_WORKER_FILE_BASENAME + ".js";
6eeec3c0Serge Svekolnikov8 years ago29private packagerAddress: string;
e3ae4227digeff10 years ago30private packagerPort: number;
4677921cdigeff10 years ago31private sourcesStoragePath: string;
6eeec3c0Serge Svekolnikov8 years ago32private packagerRemoteRoot?: string;
33private packagerLocalRoot?: string;
4bd0c669dlebu10 years ago34private sourceMapUtil: SourceMapUtil;
3fb37ad5unknown10 years ago35
34472878RedMickey5 years ago36constructor(
37packagerAddress: string,
38packagerPort: number,
39sourcesStoragePath: string,
40packagerRemoteRoot?: string,
41packagerLocalRoot?: string,
42) {
6eeec3c0Serge Svekolnikov8 years ago43this.packagerAddress = packagerAddress;
e3ae4227digeff10 years ago44this.packagerPort = packagerPort;
4677921cdigeff10 years ago45this.sourcesStoragePath = sourcesStoragePath;
6eeec3c0Serge Svekolnikov8 years ago46this.packagerRemoteRoot = packagerRemoteRoot;
47this.packagerLocalRoot = packagerLocalRoot;
4bd0c669dlebu10 years ago48this.sourceMapUtil = new SourceMapUtil();
3fb37ad5unknown10 years ago49}
50
0d77292aJiglioNero4 years ago51public async downloadAppScript(
34472878RedMickey5 years ago52scriptUrlString: string,
53projectRootPath: string,
54): Promise<DownloadedScript> {
1c32fe84Patricio Beltran9 years ago55const parsedScriptUrl = url.parse(scriptUrlString);
34472878RedMickey5 years ago56const overriddenScriptUrlString =
57parsedScriptUrl.hostname === "localhost"
58? this.overridePackagerPort(scriptUrlString)
59: scriptUrlString;
0d77292aJiglioNero4 years ago60
e00f7325unknown10 years ago61// We'll get the source code, and store it locally to have a better debugging experience
0d77292aJiglioNero4 years ago62let scriptBody = await Request.request(overriddenScriptUrlString, true);
e00f7325unknown10 years ago63
0d77292aJiglioNero4 years ago64const rnVersions = await ProjectVersionHelper.getReactNativeVersions(projectRootPath);
65// unfortunatelly Metro Bundler is broken in RN 0.54.x versions, so use this workaround unless it will be fixed
66// https://github.com/facebook/metro/issues/147
67// https://github.com/microsoft/vscode-react-native/issues/660
68if (
69ProjectVersionHelper.getRNVersionsWithBrokenMetroBundler().indexOf(
70rnVersions.reactNativeVersion,
71) >= 0
72) {
73let noSourceMappingUrlGenerated = scriptBody.match(/sourceMappingURL=/g) === null;
74if (noSourceMappingUrlGenerated) {
75let sourceMapPathUrl = overriddenScriptUrlString.replace("bundle", "map");
76scriptBody = this.sourceMapUtil.appendSourceMapPaths(scriptBody, sourceMapPathUrl);
77}
78}
79
80// Extract sourceMappingURL from body
81let scriptUrl = <IStrictUrl>url.parse(overriddenScriptUrlString); // scriptUrl = "http://localhost:8081/index.ios.bundle?platform=ios&dev=true"
82let sourceMappingUrl = this.sourceMapUtil.getSourceMapURL(scriptUrl, scriptBody); // sourceMappingUrl = "http://localhost:8081/index.ios.map?platform=ios&dev=true"
979d7bfemax-mironov8 years ago83
0d77292aJiglioNero4 years ago84let waitForSourceMapping: Promise<void> = Promise.resolve();
85if (sourceMappingUrl) {
86/* handle source map - request it and store it locally */
87waitForSourceMapping = this.writeAppSourceMap(sourceMappingUrl, scriptUrl).then(() => {
88scriptBody = this.sourceMapUtil.updateScriptPaths(
89scriptBody,
90<IStrictUrl>sourceMappingUrl,
91);
92if (semver.gte(rnVersions.reactNativeVersion, "0.61.0")) {
93scriptBody = this.sourceMapUtil.removeSourceURL(scriptBody);
94}
979d7bfemax-mironov8 years ago95});
0d77292aJiglioNero4 years ago96}
97await waitForSourceMapping;
98const scriptFilePath = await this.writeAppScript(scriptBody, scriptUrl);
99logger.verbose(`Script ${overriddenScriptUrlString} downloaded to ${scriptFilePath}`);
100return { contents: scriptBody, filepath: scriptFilePath };
e00f7325unknown10 years ago101}
102
0d77292aJiglioNero4 years ago103public async downloadDebuggerWorker(
34472878RedMickey5 years ago104sourcesStoragePath: string,
105projectRootPath: string,
106debuggerWorkerUrlPath?: string,
107): Promise<void> {
108const errPackagerNotRunning = ErrorHelper.getInternalError(
109InternalErrorCode.CannotAttachToPackagerCheckPackagerRunningOnPort,
110this.packagerPort,
111);
0a68f8dbArtem Egorov8 years ago112
0d77292aJiglioNero4 years ago113await ensurePackagerRunning(this.packagerAddress, this.packagerPort, errPackagerNotRunning);
114
115const rnVersions = await ProjectVersionHelper.getReactNativeVersions(projectRootPath);
116let debuggerWorkerURL = this.prepareDebuggerWorkerURL(
117rnVersions.reactNativeVersion,
118debuggerWorkerUrlPath,
119);
120let debuggerWorkerLocalPath = path.join(
121sourcesStoragePath,
122ScriptImporter.DEBUGGER_WORKER_FILENAME,
123);
124logger.verbose(
125"About to download: " + debuggerWorkerURL + " to: " + debuggerWorkerLocalPath,
126);
127
128const body = await Request.request(debuggerWorkerURL, true);
129
130return new FileSystem().writeFile(debuggerWorkerLocalPath, body);
2743f19cdlebu10 years ago131}
132
cf911877Yuri Skorokhodov7 years ago133public prepareDebuggerWorkerURL(rnVersion: string, debuggerWorkerUrlPath?: string): string {
134let debuggerWorkerURL: string;
135// It can be empty string
136if (debuggerWorkerUrlPath !== undefined) {
137debuggerWorkerURL = `http://${this.packagerAddress}:${this.packagerPort}/${debuggerWorkerUrlPath}${ScriptImporter.DEBUGGER_WORKER_FILENAME}`;
138} else {
139let newPackager = "";
34472878RedMickey5 years ago140if (
141!semver.valid(
142rnVersion,
143) /*Custom RN implementations should support new packager*/ ||
144semver.gte(rnVersion, "0.50.0")
145) {
cf911877Yuri Skorokhodov7 years ago146newPackager = "debugger-ui/";
147}
148debuggerWorkerURL = `http://${this.packagerAddress}:${this.packagerPort}/${newPackager}${ScriptImporter.DEBUGGER_WORKER_FILENAME}`;
149}
150return debuggerWorkerURL;
151}
152
e00f7325unknown10 years ago153/**
154* Writes the script file to the project temporary location.
155*/
0d77292aJiglioNero4 years ago156private async writeAppScript(scriptBody: string, scriptUrl: IStrictUrl): Promise<string> {
bb77358cMark Oswald10 years ago157let scriptFilePath = path.join(this.sourcesStoragePath, path.basename(scriptUrl.pathname)); // scriptFilePath = "$TMPDIR/index.ios.bundle"
0d77292aJiglioNero4 years ago158await new FileSystem().writeFile(scriptFilePath, scriptBody);
159return scriptFilePath;
3fb37ad5unknown10 years ago160}
161
e00f7325unknown10 years ago162/**
163* Writes the source map file to the project temporary location.
164*/
0d77292aJiglioNero4 years ago165private async writeAppSourceMap(
166sourceMapUrl: IStrictUrl,
167scriptUrl: IStrictUrl,
168): Promise<void> {
169const sourceMapBody = await Request.request(sourceMapUrl.href, true);
170let sourceMappingLocalPath = path.join(
171this.sourcesStoragePath,
172path.basename(sourceMapUrl.pathname),
173); // sourceMappingLocalPath = "$TMPDIR/index.ios.map"
174let scriptFileRelativePath = path.basename(scriptUrl.pathname); // scriptFileRelativePath = "index.ios.bundle"
175let updatedContent = this.sourceMapUtil.updateSourceMapFile(
176sourceMapBody,
177scriptFileRelativePath,
178this.sourcesStoragePath,
179this.packagerRemoteRoot,
180this.packagerLocalRoot,
181);
182return new FileSystem().writeFile(sourceMappingLocalPath, updatedContent);
3fb37ad5unknown10 years ago183}
5e651f3edigeff10 years ago184
185/**
186* Changes the port of the url to be the one configured as this.packagerPort
187*/
188private overridePackagerPort(urlToOverride: string): string {
189let components = url.parse(urlToOverride);
190components.port = this.packagerPort.toString();
191delete components.host; // We delete the host, if not the port change will be ignored
192return url.format(components);
193}
3fb37ad5unknown10 years ago194}