diff --git a/src/common/commandExecutor.ts b/src/common/commandExecutor.ts index 9a19cd0c1..23b607f12 100644 --- a/src/common/commandExecutor.ts +++ b/src/common/commandExecutor.ts @@ -32,6 +32,7 @@ export enum CommandStatus { } export class CommandExecutor { + private static ReactNativeCommand = "react-native"; private static ReactNativeVersionCommand = "-v"; private currentWorkingDirectory: string; @@ -121,7 +122,7 @@ export class CommandExecutor { */ public spawnReactCommand(command: string, args?: string[], options: Options = {}): ISpawnResult { const reactCommand = HostPlatform.getNpmCliCommand(CommandExecutor.ReactNativeCommand); - return this.spawnChildProcess(reactCommand, this.combineArguments(command, args), options); + return this.spawnChildProcess(reactCommand, [command, ...args], options); } /** @@ -209,8 +210,4 @@ export class CommandExecutor { private generateRejectionForCommand(command: string, reason: any): Q.Promise { return Q.reject(ErrorHelper.getNestedError(reason, InternalErrorCode.CommandFailed, command)); } - - private combineArguments(firstArgument: string, otherArguments: string[] = []) { - return [firstArgument].concat(otherArguments); - } } diff --git a/src/common/exponent/exponentHelper.d.ts b/src/common/exponent/exponentHelper.d.ts new file mode 100644 index 000000000..133e5ad7e --- /dev/null +++ b/src/common/exponent/exponentHelper.d.ts @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for details. + +declare class AppJson { + public name: string; + public displayName?: string; + public expo?: ExpConfig; +} + +declare class ExpConfig { + public name: string; + public slug: string; + public sdkVersion: string; + public version?: string; + public entryPoint?: string; + public packagerOpts?: ExpConfigPackager; +} + +declare class ExpConfigPackager { + public assetExts?: string[]; +} \ No newline at end of file diff --git a/src/common/exponent/exponentHelper.ts b/src/common/exponent/exponentHelper.ts index efeea0981..0be797f34 100644 --- a/src/common/exponent/exponentHelper.ts +++ b/src/common/exponent/exponentHelper.ts @@ -1,43 +1,31 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for details. +/// + import * as path from "path"; import * as Q from "q"; import * as XDL from "./xdlInterface"; -import stripJsonComments = require("strip-json-comments"); +import { Package } from "../node/package"; +import { ReactNativeProjectHelper } from "../reactNativeProjectHelper"; +import { FileSystem } from "../node/fileSystem"; +import { Log } from "../log/log"; +import stripJSONComments = require("strip-json-comments"); -import {FileSystem} from "../node/fileSystem"; -import {Package} from "../node/package"; -import {ReactNativeProjectHelper} from "../reactNativeProjectHelper"; -import {CommandVerbosity, CommandExecutor} from "../commandExecutor"; -import {HostPlatform} from "../hostPlatform"; -import {Log} from "../log/log"; +const APP_JSON = "app.json"; +const EXP_JSON = "exp.json"; -const VSCODE_EXPONENT_JSON = "vscodeExponent.json"; const EXPONENT_INDEX = "exponentIndex.js"; -const DEFAULT_EXPONENT_INDEX = "main.js"; +const DEFAULT_EXPONENT_INDEX = "index.js"; const DEFAULT_IOS_INDEX = "index.ios.js"; const DEFAULT_ANDROID_INDEX = "index.android.js"; -const EXP_JSON = "exp.json"; -const SECONDS_IN_DAY = 86400; -enum ReactNativePackageStatus { - FACEBOOK_PACKAGE, - EXPONENT_PACKAGE, - UNKNOWN -} +const DBL_SLASHES = /\\/g; export class ExponentHelper { - private projectRootPath: string; private workspaceRootPath: string; - private fileSystem: FileSystem; - private commandExecutor: CommandExecutor; - - private expSdkVersion: string; - private entrypointFilename: string; - private entrypointComponentName: string; - - private dependencyPackage: ReactNativePackageStatus; + private projectRootPath: string; + private fs: FileSystem; private hasInitialized: boolean; public constructor(workspaceRootPath: string, projectRootPath: string) { @@ -50,33 +38,15 @@ export class ExponentHelper { // are correctly initialized. } - /** - * Convert react native project to exponent. - * This consists on three steps: - * 1. Change the dependency from facebook's react-native to exponent's fork - * 2. Create exp.json - * 3. Create index and entrypoint for exponent - */ public configureExponentEnvironment(): Q.Promise { this.lazilyInitialize(); Log.logMessage("Making sure your project uses the correct dependencies for exponent. This may take a while..."); - return this.changeReactNativeToExponent() - .then(() => { - Log.logMessage("Dependencies are correct. Making sure you have any necessary configuration file."); - return this.ensureExpJson(); - }).then(() => { - Log.logMessage("Project setup is correct. Generating entrypoint code."); - return this.createIndex(); - }); - } + return this.isExpoApp(true) + .then(isExpo => { + Log.logString(".\n"); - /** - * Change dependencies to point to original react-native repo - */ - public configureReactNativeEnvironment(): Q.Promise { - this.lazilyInitialize(); - Log.logMessage("Checking react native is correctly setup. This may take a while..."); - return this.changeExponentToReactNative(); + return this.patchAppJson(isExpo); + }); } /** @@ -105,305 +75,210 @@ export class ExponentHelper { }); } - public getExponentPackagerOptions(): Q.Promise { + public getExpPackagerOptions(): Q.Promise { this.lazilyInitialize(); - return this.readFromExpJson("packagerOpts"); + return this.getFromExpConfig("packagerOpts") + .then(opts => opts || {}); } /** - * File used as an entrypoint for exponent. This file's component should be registered as "main" - * in the AppRegistry and should only render a entrypoint component. + * Path to a given file inside the .vscode directory */ - private createIndex(): Q.Promise { + private dotvscodePath(filename: string): string { + return path.join(this.workspaceRootPath, ".vscode", filename); + } + + private createExpoEntry(name: string): Q.Promise { this.lazilyInitialize(); - const pkg = require("../../../package.json"); - const extensionVersionNumber = pkg.version; - const extensionName = pkg.name; - - return Q.all([this.entrypointComponent(), this.entrypoint()]) - .spread((componentName: string, entryPointFile: string) => { - const fileContents = - `// This file is automatically generated by ${extensionName}@${extensionVersionNumber} -// Please do not modify it manually. All changes will be lost. -var React = require('${this.projectRootPath}/node_modules/react'); -var {Component} = React; + return this.detectEntry() + .then((entryPoint: string) => { + const content = this.generateFileContent(name, entryPoint); + return this.fs.writeFile(this.dotvscodePath(EXPONENT_INDEX), content); + }); -var ReactNative = require('${this.projectRootPath}/node_modules/react-native'); -var {AppRegistry} = ReactNative; + } -var entryPoint = require('${this.projectRootPath}/${entryPointFile}'); + private detectEntry(): Q.Promise { + this.lazilyInitialize(); + return Q.all([ + this.fs.exists(this.pathToFileInWorkspace(DEFAULT_EXPONENT_INDEX)), + this.fs.exists(this.pathToFileInWorkspace(DEFAULT_IOS_INDEX)), + this.fs.exists(this.pathToFileInWorkspace(DEFAULT_ANDROID_INDEX)), + ]) + .spread((expo: boolean, ios: boolean): string => { + return expo ? this.pathToFileInWorkspace(DEFAULT_EXPONENT_INDEX) : + ios ? this.pathToFileInWorkspace(DEFAULT_IOS_INDEX) : + this.pathToFileInWorkspace(DEFAULT_ANDROID_INDEX); + }); + } + private generateFileContent(name: string, entryPoint: string): string { + return `// This file is automatically generated by VS Code +// Please do not modify it manually. All changes will be lost. +var React = require('${this.pathToFileInWorkspace("/node_modules/react")}'); +var { Component } = React; +var ReactNative = require('${this.pathToFileInWorkspace("/node_modules/react-native")}'); +var { AppRegistry } = ReactNative; +var entryPoint = require('${entryPoint}'); AppRegistry.registerRunnable('main', function(appParameters) { - AppRegistry.runApplication('${componentName}', appParameters); + AppRegistry.runApplication('${name}', appParameters); });`; - return this.fileSystem.writeFile(this.dotvscodePath(EXPONENT_INDEX), fileContents); - }); } - /** - * Create exp.json file in the workspace root if not present - */ - private ensureExpJson(): Q.Promise { - this.lazilyInitialize(); - let defaultSettings = { - "sdkVersion": "", - "entryPoint": this.dotvscodePath(EXPONENT_INDEX), - "slug": "", - "name": "", - }; - return this.readVscodeExponentSettingFile() - .then(exponentJson => { - const expJsonPath = this.pathToFileInWorkspace(EXP_JSON); - if (!this.fileSystem.existsSync(expJsonPath) || exponentJson.overwriteExpJson) { + private patchAppJson(isExpo: boolean = true): Q.Promise { + return this.readAppJson() + .catch(() => { + // if app.json doesn't exist but it's ok, we will create it + return {}; + }) + .then((config: AppJson) => { + let expoConfig = (config.expo || {}); + if (!expoConfig.name || !expoConfig.slug) { return this.getPackageName() - .then(name => { - // Name and slug are supposed to be the same, - // but slug only supports alpha numeric and -, - // while name should be human readable - defaultSettings.slug = name.replace(" ", "-"); - defaultSettings.name = name; - return this.exponentSdk(); - }) - .then(exponentVersion => { - if (!exponentVersion) { - return XDL.supportedVersions() - .then((versions) => { - return Q.reject(new Error(`React Native version not supported by exponent. Major versions supported: ${versions.join(", ")}`)); - }); - } - defaultSettings.sdkVersion = exponentVersion; - return this.fileSystem.writeFile(expJsonPath, JSON.stringify(defaultSettings, null, 4)); + .then((name: string) => { + expoConfig.slug = expoConfig.slug || config.name || name.replace(" ", "-"); + expoConfig.name = expoConfig.name || config.name || name; + config.expo = expoConfig; + return config; }); } - }); - } - /** - * Changes npm dependency from react native to exponent's fork - */ - private changeReactNativeToExponent(): Q.Promise { - Log.logString("Checking if react native is from exponent."); - return this.usingReactNativeExponent(true) - .then(usingExponent => { - Log.logString(".\n"); - if (usingExponent) { - return Q.resolve(void 0); + return config; + }) + .then((config: AppJson) => { + if (!config.expo.sdkVersion) { + return this.exponentSdk(true) + .then(sdkVersion => { + config.expo.sdkVersion = sdkVersion; + return config; + }); } - Log.logString("Getting appropriate Exponent SDK Version to install."); - return this.exponentSdk(true) - .then(sdkVersion => { - Log.logString(".\n"); - if (!sdkVersion) { - return XDL.supportedVersions() - .then((versions) => { - return Q.reject(new Error(`React Native version not supported by exponent. Major versions supported: ${versions.join(", ")}`)); - }); - } - const exponentFork = `github:exponentjs/react-native#sdk-${sdkVersion}`; - Log.logString("Uninstalling current react native package."); - return Q(this.commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"), ["uninstall", "react-native", "--verbose"], { verbosity: CommandVerbosity.PROGRESS })) - .then(() => { - Log.logString("Installing exponent react native package."); - return this.commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"), ["install", exponentFork, "--cache-min", SECONDS_IN_DAY.toString(10), "--verbose"], { verbosity: CommandVerbosity.PROGRESS }); - }); - }); + return config; }) - .then(() => { - this.dependencyPackage = ReactNativePackageStatus.EXPONENT_PACKAGE; - }); - } + .then((config: AppJson) => { + if (!isExpo) { + config.expo.entryPoint = this.dotvscodePath(EXPONENT_INDEX); + } - /** - * Changes npm dependency from exponent's fork to react native - */ - private changeExponentToReactNative(): Q.Promise { - Log.logString("Checking if the correct react native is installed."); - return this.usingReactNativeExponent() - .then(usingExponent => { - Log.logString(".\n"); - if (!usingExponent) { - return Q.resolve(void 0); + return config; + }) + .then((config: AppJson) => { + if (config) { + return this.writeAppJson(config); } - Log.logString("Uninstalling current react native package."); - return Q(this.commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"), ["uninstall", "react-native", "--verbose"], { verbosity: CommandVerbosity.PROGRESS })) - .then(() => { - Log.logString("Installing correct react native package."); - return this.commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"), ["install", "react-native", "--cache-min", SECONDS_IN_DAY.toString(10), "--verbose"], { verbosity: CommandVerbosity.PROGRESS }); - }); }) - .then(() => { - this.dependencyPackage = ReactNativePackageStatus.FACEBOOK_PACKAGE; - }); - } - - /** - * Reads VSCODE_EXPONENT Settings file. If it doesn't exists it creates one by - * guessing which entrypoint and filename to use. - */ - private readVscodeExponentSettingFile(): Q.Promise { - // Only create a new one if there is not one already - return this.fileSystem.exists(this.dotvscodePath(VSCODE_EXPONENT_JSON)) - .then((vscodeExponentExists: boolean) => { - if (vscodeExponentExists) { - return this.fileSystem.readFile(this.dotvscodePath(VSCODE_EXPONENT_JSON), "utf-8") - .then(function (jsonContents: string): Q.Promise { - return JSON.parse(stripJsonComments(jsonContents)); - }); - } else { - let defaultSettings = { - "entryPointFilename": "", - "entryPointComponent": "", - "overwriteExpJson": false, - }; - return this.getPackageName() - .then(packageName => { - // By default react-native uses the package name for the entry component. This is our safest guess. - defaultSettings.entryPointComponent = packageName; - this.entrypointComponentName = defaultSettings.entryPointComponent; - return Q.all([ - this.fileSystem.exists(this.pathToFileInWorkspace(DEFAULT_IOS_INDEX)), - this.fileSystem.exists(this.pathToFileInWorkspace(DEFAULT_EXPONENT_INDEX)), - ]); - }) - .spread((indexIosExists: boolean, mainExists: boolean) => { - // If there is an ios entrypoint we want to use that, if not let's go with android - defaultSettings.entryPointFilename = - mainExists ? DEFAULT_EXPONENT_INDEX - : indexIosExists ? DEFAULT_IOS_INDEX - : DEFAULT_ANDROID_INDEX; - this.entrypointFilename = defaultSettings.entryPointFilename; - return this.fileSystem.writeFile(this.dotvscodePath(VSCODE_EXPONENT_JSON), JSON.stringify(defaultSettings, null, 4)); - }) - .then(() => { - return defaultSettings; - }); + .then((config: AppJson) => { + if (!isExpo) { + return this.createExpoEntry(config.expo.name); } }); - } + }; /** * Exponent sdk version that maps to the current react-native version * If react native version is not supported it returns null. */ private exponentSdk(showProgress: boolean = false): Q.Promise { - if (showProgress) Log.logString("..."); - if (this.expSdkVersion) { - return Q(this.expSdkVersion); + if (showProgress) { + Log.logString("..."); } - return this.readFromExpJson("sdkVersion") - .then((sdkVersion) => { + + let reactNativeProjectHelper = new ReactNativeProjectHelper(this.projectRootPath); + return reactNativeProjectHelper.getReactNativeVersion() + .then(version => { if (showProgress) Log.logString("."); - if (sdkVersion) { - this.expSdkVersion = sdkVersion; - return this.expSdkVersion; - } - let reactNativeProjectHelper = new ReactNativeProjectHelper(this.projectRootPath); - return reactNativeProjectHelper.getReactNativeVersion() - .then(version => { - if (showProgress) Log.logString("."); - return XDL.mapVersion(version) - .then(exponentVersion => { - this.expSdkVersion = exponentVersion; - return this.expSdkVersion; - }); + return XDL.mapVersion(version) + .then(sdkVersion => { + if (!sdkVersion) { + return XDL.supportedVersions() + .then((versions) => { + return Q.reject(new Error(`React Native version not supported by exponent. Major versions supported: ${versions.join(", ")}`)); + }); + } + return sdkVersion; }); }); } + /** - * Returns the specified setting from exp.json if it exists + * Name specified on user's package.json */ - private readFromExpJson(setting: string): Q.Promise { - const expJsonPath = this.pathToFileInWorkspace(EXP_JSON); - return this.fileSystem.exists(expJsonPath) - .then((exists: boolean) => { - if (!exists) { - return null; + private getPackageName(): Q.Promise { + return new Package(this.projectRootPath, { fileSystem: this.fs }).name(); + } + + private getExpConfig(): Q.Promise { + return this.readExpJson() + .catch(err => { + if (err.code === "ENOENT") { + return this.readAppJson() + .then((config: AppJson) => { + return config.expo || {}; + }); } - return this.fileSystem.readFile(expJsonPath, "utf-8") - .then(function (jsonContents: string): Q.Promise { - return JSON.parse(stripJsonComments(jsonContents))[setting]; - }); + + return err; }); } - /** - * Looks at the _from attribute in the package json of the react-native dependency - * to figure out if it's using exponent. - */ - private usingReactNativeExponent(showProgress: boolean = false): Q.Promise { - if (showProgress) Log.logString("..."); - if (this.dependencyPackage !== ReactNativePackageStatus.UNKNOWN) { - return Q(this.dependencyPackage === ReactNativePackageStatus.EXPONENT_PACKAGE); - } - // Look for the package.json of the dependecy - const pathToReactNativePackageJson = path.resolve(this.projectRootPath, "node_modules", "react-native", "package.json"); - return this.fileSystem.readFile(pathToReactNativePackageJson, "utf-8") - .then(jsonContents => { - const packageJson = JSON.parse(jsonContents); - const isExp = /\bexponentjs\/react-native\b/.test(packageJson._from); - this.dependencyPackage = isExp ? ReactNativePackageStatus.EXPONENT_PACKAGE : ReactNativePackageStatus.FACEBOOK_PACKAGE; - if (showProgress) Log.logString("."); - return isExp; - }).catch(() => { - if (showProgress) Log.logString("."); - // Not in a react-native project - return false; - }); + private getFromExpConfig(key: string): Q.Promise { + return this.getExpConfig() + .then((config: ExpConfig) => config[key]); } /** - * Name of the file (we assume it lives in the workspace root) that should be used as entrypoint. - * e.g. index.ios.js + * Returns the specified setting from exp.json if it exists */ - private entrypoint(): Q.Promise { - if (this.entrypointFilename) { - return Q(this.entrypointFilename); - } - return this.readVscodeExponentSettingFile() - .then((settingsJson) => { - // Let's load both to memory to make sure we are not reading from memory next time we query for this. - this.entrypointFilename = settingsJson.entryPointFilename; - this.entrypointComponentName = settingsJson.entryPointComponent; - return this.entrypointFilename; + private readExpJson(): Q.Promise { + const expJsonPath = this.pathToFileInWorkspace(EXP_JSON); + return this.fs.readFile(expJsonPath) + .then(content => { + return JSON.parse(stripJSONComments(content)); }); } - /** - * Name of the component used as an entrypoint for the app. - */ - private entrypointComponent(): Q.Promise { - if (this.entrypointComponentName) { - return Q(this.entrypointComponentName); - } - return this.readVscodeExponentSettingFile() - .then((settingsJson) => { - // Let's load both to memory to make sure we are not reading from memory next time we query for this. - this.entrypointComponentName = settingsJson.entryPointComponent; - this.entrypointFilename = settingsJson.entrypointFilename; - return this.entrypointComponentName; + private readAppJson(): Q.Promise { + const appJsonPath = this.pathToFileInWorkspace(APP_JSON); + return this.fs.readFile(appJsonPath) + .then(content => { + return JSON.parse(stripJSONComments(content)); }); } - /** - * Path to a given file inside the .vscode directory - */ - private dotvscodePath(filename: string): string { - return path.join(this.workspaceRootPath, ".vscode", filename); + private writeAppJson(config: AppJson): Q.Promise { + const appJsonPath = this.pathToFileInWorkspace(APP_JSON); + return this.fs.writeFile(appJsonPath, JSON.stringify(config, null, 2)) + .then(() => config); } /** * Path to a given file from the workspace root */ private pathToFileInWorkspace(filename: string): string { - return path.join(this.projectRootPath, filename); + return path.join(this.projectRootPath, filename).replace(DBL_SLASHES, "/"); } - /** - * Name specified on user's package.json - */ - private getPackageName(): Q.Promise { - return new Package(this.projectRootPath, { fileSystem: this.fileSystem }).name(); + private isExpoApp(showProgress: boolean = false): Q.Promise { + Log.logString("Checking if this is Expo app."); + if (showProgress) { + Log.logString("..."); + } + + const packageJsonPath = this.pathToFileInWorkspace("package.json"); + return this.fs.readFile(packageJsonPath) + .then(content => { + const packageJson = JSON.parse(content); + const isExp = packageJson.dependencies && !!packageJson.dependencies.expo || false; + if (showProgress) Log.logString("."); + return isExp; + }).catch(() => { + if (showProgress) { + Log.logString("."); + } + // Not in a react-native project + return false; + }); } /** @@ -412,9 +287,7 @@ AppRegistry.registerRunnable('main', function(appParameters) { private lazilyInitialize(): void { if (!this.hasInitialized) { this.hasInitialized = true; - this.fileSystem = new FileSystem(); - this.commandExecutor = new CommandExecutor(this.projectRootPath); - this.dependencyPackage = ReactNativePackageStatus.UNKNOWN; + this.fs = new FileSystem(); XDL.configReactNativeVersionWargnings(); XDL.attachLoggerStream(this.projectRootPath, { @@ -433,4 +306,4 @@ AppRegistry.registerRunnable('main', function(appParameters) { }); } } -} +} \ No newline at end of file diff --git a/src/common/exponent/xdlInterface.ts b/src/common/exponent/xdlInterface.ts index 619c72bbc..3d8d1d225 100644 --- a/src/common/exponent/xdlInterface.ts +++ b/src/common/exponent/xdlInterface.ts @@ -9,7 +9,11 @@ import * as XDLPackage from "xdl"; import * as path from "path"; import * as Q from "q"; -const XDL_VERSION = "36.1.0"; +const EXPO_DEPS: string[] = [ + "xdl", + "@expo/ngrok", // devDependencies for xdl +]; + let xdlPackage: Q.Promise; function getPackage(): Q.Promise { @@ -31,7 +35,7 @@ function getPackage(): Q.Promise { } let commandExecutor = new CommandExecutor(); xdlPackage = commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"), - ["install", `xdl@${XDL_VERSION}`, "--verbose"], + ["install", EXPO_DEPS.join(" "), "--verbose"], { verbosity: CommandVerbosity.PROGRESS, cwd: path.dirname(require.resolve("../../../"))}) .then((): typeof XDLPackage => { @@ -49,13 +53,13 @@ export function configReactNativeVersionWargnings(): Q.Promise { }); } -export function attachLoggerStream(rootPath: string, options?: XDLPackage.IBunyanStream): Q.Promise { +export function attachLoggerStream(rootPath: string, options?: XDLPackage.IBunyanStream | any): Q.Promise { return getPackage() .then((xdl) => xdl.ProjectUtils.attachLoggerStream(rootPath, options)); } -export function supportedVersions(): Q.Promise> { +export function supportedVersions(): Q.Promise { return getPackage() .then((xdl) => xdl.Versions.facebookReactNativeVersionsAsync()); diff --git a/src/common/packager.ts b/src/common/packager.ts index af48b1b0e..c41b5b0e2 100644 --- a/src/common/packager.ts +++ b/src/common/packager.ts @@ -79,15 +79,19 @@ export class Packager { }) .then(() => XDL.setOptions(this.projectPath, { packagerPort: port }) - ).then(() => + ) + .then(() => XDL.startExponentServer(this.projectPath) - ).then(() => + ) + .then(() => XDL.startTunnels(this.projectPath) - ).then(() => + ) + .then(() => XDL.getUrl(this.projectPath, { dev: true, minify: false }) ).then(exponentUrl => { return "exp://" + url.parse(exponentUrl).host; - }).catch(reason => { + }) + .catch(reason => { return Q.reject(reason); }); } @@ -191,28 +195,36 @@ export class Packager { executedStartPackagerCmd = true; return this.monkeyPatchOpnForRNPackager() .then(() => { - let args = ["--port", port.toString()]; + let args: string[] = ["--port", port.toString()]; if (resetCache) { args = args.concat("--resetCache"); } if (runAs !== PackagerRunAs.EXPONENT) { - return args; + return args; } - args = args.concat(["--root", path.relative(this.projectPath, path.resolve(this.workspacePath, ".vscode"))]); + args.push("--root", path.relative(this.projectPath, path.resolve(this.workspacePath, ".vscode"))); + let helper = new ExponentHelper(this.workspacePath, this.projectPath); - return helper.getExponentPackagerOptions() - .then((options) => { - return Object.keys(options).reduce((args, key) => { - return args.concat(["--" + key, options[key]]); - }, args); - }) - .catch(() => { - Log.logWarning("Couldn't read packager's options from exp.json, continue..."); - return args; - }); - }) + return helper.getExpPackagerOptions() + .then((options: ExpConfigPackager) => { + Object.keys(options).forEach(key => { + args.concat([`--${key}`, options[key]]); + }); + + // Patch for CRNA + if (args.indexOf("--assetExts") === -1) { + args.push("--assetExts", "ttf"); + } + + return args; + }) + .catch(() => { + Log.logWarning("Couldn't read packager's options from exp.json, continue..."); + return args; + }); + }) .then((args) => { let reactNativeProjectHelper = new ReactNativeProjectHelper(this.projectPath); reactNativeProjectHelper.getReactNativeVersion().then(version => { @@ -238,8 +250,8 @@ export class Packager { packagerSpawnResult.outcome.done(() => { }, () => { }); /* Q prints a warning if we don't call .done(). We ignore all outcome errors */ return packagerSpawnResult.startup; + }); }); - }); } }) .then(() => diff --git a/src/extension/commandPaletteHandler.ts b/src/extension/commandPaletteHandler.ts index 7de3980b2..c01b48a1f 100644 --- a/src/extension/commandPaletteHandler.ts +++ b/src/extension/commandPaletteHandler.ts @@ -40,9 +40,8 @@ export class CommandPaletteHandler { return this.reactNativePackager.stop(); } }) - ).then(() => - this.exponentHelper.configureReactNativeEnvironment() - ).then(() => this.runStartPackagerCommandAndUpdateStatus()); + ) + .then(() => this.runStartPackagerCommandAndUpdateStatus()); } /** diff --git a/src/extension/extensionServer.ts b/src/extension/extensionServer.ts index 4dc993db3..271f0b0b6 100644 --- a/src/extension/extensionServer.ts +++ b/src/extension/extensionServer.ts @@ -103,9 +103,8 @@ export class ExtensionServer implements vscode.Disposable { Log.logMessage("Attaching to running React Native packager"); } - }).then(() => - this.exponentHelper.configureReactNativeEnvironment() - ).then(() => { + }) + .then(() => { const portToUse = ConfigurationReader.readIntWithDefaultSync(port, SettingsHelper.getPackagerPort()); return this.reactNativePackager.startAsReactNative(portToUse); })