Skip to content

Running Flagship Apps

Benjamin Hanes edited this page Oct 20, 2020 · 6 revisions

Contents

Step 1: Yarn

Flagship and Flagship apps use Yarn for dependency management. Simply run yarn in the project root to make sure that your project's dependencies are up-to-date.

Step 2: TypeScript Compiler (TSC)

Whenever you pull down or write new code, you'll need to run TSC in order to compile the TypeScript code into vanilla JS before it can be run on device with React Native.

From your project root, run ./node_modules/.bin/tsc or simply tsc if you have the package installed globally.

Note: Most Flagship apps and the Flagship Template project define TSC as part of the prepare hook in package.json, meaning that TSC will run whenever you run yarn, making this extra step unnecessary.

Step 3: Init

Whenever you pull down a project for the first time, add native dependencies to your project, or update your environment files you'll need to run Flagship init.

Note that you do not need to re-run init unless you change native dependencies or environment files!

The init script does the following:

  • Copies the ios and android folders from @brandingbrand/flagship into your project. These contain the native projects for iOS and Android.
  • Edits the native projects to customize values per your configuration for items such as app name and bundle identifier.
  • Runs react-native link to install native dependencies.
  • Runs custom scripts defined in the Flagship package to set up native dependencies that don't link automatically.
  • Adds native dependencies using Cocoapods (iOS) and Gradle (Android).
  • Registers your environment files and generates env.js for the current selected environment.

You can manually run init as follows: ./node_modules/.bin/flagship init

However, we recommend adding a convenience script to your project's package.json that wraps the script with a clean step that removes the ios and android directories ahead of time. (This already exists in projects created with the Flagship Project Template.)

"scripts": {
  "init": "flagship clean && flagship init native"
}

This would be run as follows: yarn run init

Step 4: Run the App

iOS

Simulator

To start your app in an iOS simulator, you can simply run ./node-modules/.bin/react-native run-ios. However, please note that this doesn't account for TypeScript so you'll need to run tsc whenever you make a change before it'll appear on your simulator.

To accommodate for this, Branding Brand apps and the Flagship Template app define a convenience script in package.json that starts up a TypeScript file watcher, the React Native packager, and the app in one go.

It normally looks like this in package.json:

"compile-ios": "react-native run-ios --simulator \"iPhone X\" --no-packager",
"ios": "run-p start tsc:watch compile-ios"

And you run it like this:

yarn run ios

This will launch the app in a simulator and automatically run TSC whenever your code changes.

Physical Device

  1. Connect your device to your computer with a USB cable
  2. Open Xcode
  3. Use the "Open" menu to open /ios/.xcworkspace
  4. Select your device from the devices dropdown (top left next to the app name)
  5. Click the Run (▶) button to run the app on your selected device
  6. Note that you will need to run tsc after making changes in your code to be reflected in your app

Android

Emulator

Unlike iOS, React Native cannot start an Android emulator. As such, you'll need to manually start an emulator before continuing.

  1. Open Android Studio
  2. Select Tools > AVD Manager
  3. Click "Create Virtual Device" and follow the wizard to create a new emulator, or click the start (▶) button to launch an existing emulator

To start your app in an Android emulator, you can simply run ./node-modules/.bin/react-native run-android. However, please note that this doesn't account for TypeScript so you'll need to run tsc whenever you make a change before it'll appear on your simulator.

To accommodate for this, Branding Brand apps and the Flagship Template app define a convenience script in package.json that starts up a TypeScript file watcher, the React Native packager, and the app in one go.

It normally looks like this in package.json:

"compile-android": "react-native run-android --no-packager",
"android": "run-p start tsc:watch compile-android"

And you run it like this:

yarn run android

This will launch the app in the emulator and automatically run TSC whenever your code changes.

Physical Device

  1. Connect an Android device to your computer via USB
  2. Open the Settings app
  3. Navigate to "About phone"
  4. Tap on the "Build number" item 10x in a row to enable developer mode
  5. Go back to the main Settings menu and select "Developer options"
  6. Verify that the "USB debugging" checkbox is enabled
  7. You may need to change your phone's USB mode from charging only to data transfer mode. Refer to your phone's documentation for more information.
  8. From your computer, run adb devices which will list all physical and emulator devices and their debugging status
    • If the device isn't displayed, either the phone isn't in developer mode, USB debugging mode is disabled, or the USB mode is set to charging only
    • If the device is listed as "unauthorized", USB debugging is disabled or you haven't given the current computer permission to access your device. Try tapping "Revoke USB debugging authorizations" and then turn USB debugging off then on again and you should get a prompt to allow debugging
    • If the device is listed as "device" debugging should be ready to go.

Once your device is set up for development, the process is the same as running on an emulator: run ./node_modules/.bin/react-native run-android or yarn run android and the app will run on your connected Android device. Note that if you use run-android you'll need to manually run tsc whenever you make a change to your code.

Web

When running for web, you'll need to make sure that your application has been initialized for web so that the /web folder has been generated. You can do this by running flagship init web.

Development

Running in development mode will compile your application and serve it immediately, updating as you make changes. You can do this by running yarn start inside of the /web folder. Generally this is done with a script in your package.json that looks like: "compile-web": "(test -d 'web' || flagship init web) && cd ./web/ && yarn start"

If you need to proxy api requests, you can run a seperate server which will handle that with yarn server-dev inside of the /web folder.

Production

You can also build the application for production mode, which will compile everything into the /web-compiled folder. This can be served directly by running start-prod inside the /web folder, or you can run it with proxy support with server-prod.

Server-side Rendering

Available in Flagship 10.0.0+

Once you've built for production, you can also compile your application to be rendered server-side by running build-ssr inside the /web folder. This will build a function that you can pass an Express application into which will add middleware routes for each of your screens, which will wind up as /web/ssr-build/attachSSR.js. For it to build this, you'll need to create a ssr.ts file inside your /src folder. This will look the same as your index.web.ts file, but replace these lines:

const app = new FSApp(webConfig);
export default app;

with:

export default function(app: any, options?: SSROptions): void {
  attachSSR(app, webConfig, options);
}

To share data that you've loaded server-side with your client-side application, you'll also want to add this to your index.web.ts file before calling new FSApp to initialize redux with that data:

// @ts-ignore May be set by SSR
if (window.initialState) {
  webConfig.initialState = {
    ...webConfig.initialState,
    // @ts-ignore
    ...window.initialState
  };
}

Once you've built for both production and server-side rendering, you can either use it with your own Express app or run server-ssr inside the /web folder to run your application with proxy and server-side-rendering support.

By default, your screens will be served at /_s/{screenname}, but can be overridden by setting a static path string on the screen.

If you want to load some data specifically for the screen, add a static loadInitialData function to it of the form:

(data: FSAppTypes.SSRData, req: Express.Request) => Promise<FSAppTypes.SSRData>

where data is the initialState from the application configuration and a variables object, and returns a Promise including an update of that. req is the Express request object, in case there is any information you need to pull out of it.

If you have a screen where you want it to skip being rendered server-side and you want your Express application to handle it instead, set a static instantNext value to true. If you need some sort of logic based on the responses from loadInitialData or anything else, you can specify shouldNext, which takes this form:

(data: FSAppTypes.SSRData, req: Express.Request) => Promise<boolean>

and should return true if you want to abort rendering and call next instead.

You can also specify a cache number for how long a screen's responses should be cached.

For data that should be loaded more globally, you'll want to specify cachedData and/or uncachedData functions in your application configuration. These take the form:

(initialData: FSAppTypes.SSRData, req?: Express.Request): Promise<FSAppTypes.SSRData>

and are run both server-side and client-side, where req is undefined client-side. The exception is that uncachedData is not run server-side for cached pages, so should contain any requests for user-specific data, like account or cart data.

Clone this wiki locally