Skip to content
This repository has been archived by the owner on May 3, 2024. It is now read-only.

Latest commit

 

History

History
222 lines (167 loc) · 10.2 KB

Running-In-Production.md

File metadata and controls

222 lines (167 loc) · 10.2 KB

👈 Return to Overview

Running In Production

One App is battle tested as it has been in use in production within American Express with our most highly trafficked customer facing applications since 2016.

It was built with The Twelve-Factor App principles in mind and as such is highly flexible and independent of its runtime.

One App can be started via docker or if built from source by running node lib/server/index.js on your server.

Contents

Building And Deploying Holocron Modules

Holocron Modules are React components that are bundled by one-app-bundler and are the pieces that make up a One App application instance.

Running one-app-bundler on a module builds and packages the module's source code into static assets that can to be deployed to a CDN. It expects ./src/index.js to export a React component and creates a build directory as its output.

Input:

root
|── src
|   └── index.js
└── package.json

Output:

build
└── 1.0.0
    ├── <moduleName>.browser.js
    ├── <moduleName>.legacy.browser.js
    ├── <moduleName>.node.js
    └── en-us
        ├── <moduleName>.json
        ├── integration.json
        └── qa.json

en-us contains the language packs used for internationalization for the en-US locale. As this is an example only en-us is shown but in your module you may have as many or few locales as needed.

<moduleName>.browser.js is the modern browser bundle.

<moduleName>.legacy.browser.js is the legacy browser bundle.

<moduleName>.node.js is the server bundle.

These bundles are used in One App depending on the environment your module is running in. For example if One App detects that your module's bundle is being requested by an older browser then the <moduleName>.legacy.browser.js bundle will be served which includes polyfills and the needed transpilation for that browser. Otherwise it will serve the potentially leaner <moduleName>.browser.js or the <moduleName>.node.js bundle when running on the server.

Note that if you are making use of code splitting via dynamic imports in your module there may be more chunks in your build directory.

One App has no opinion on where module bundles are deployed to, the only thing to keep in mind is that all the assets for a given module must be kept together when deployed, i.e. the file structure generated by one-app-bundler must not be modified. This is because the bundles rely on this structure for knowing where to look for the lang packs. To see examples of how to deploy modules to certain hosting platforms, take a look at our documentation on publishing modules.

Building and Deploying a Holocron Module Map

In order for One App to use a module two things need to happen:

  1. The module's static assets must be deployed to a static server.
  2. A Holocron module map must be created / updated with the module's metadata and hosted on a static server.

A Holocron module map is what tells One App what Modules it should load and where to find them.

It is what allows for Holocron modules to be loaded and used by One App without requiring a One App deployment or restart. When One App is started on a server it reads from the HOLOCRON_MODULE_MAP_URL to find out where it should fetch the module map from and then periodically polls this module map and adds / removes / updates its internal module registry to match any changes to it.

Ultimately a Holocron Module Map is a JSON object of the following shape:

{
  "clientCacheRevision": "123",
  "modules": {
    "<moduleName>": {
      "browser": {
        "integrity": "sha256-ws6s6vTApdkif2pOfsYOGwdfE9LurZ7Bwq4Olvomrf8= sha384-CLKgejOPhJjRFoUKxLRGeuH09z376SvuTfnWw8IhnShureZQmhzf+GoWGQeA++WU",
        "url": "https://example.com/modules/<moduleName>/0.0.0/<moduleName>.browser.js"
      },
      "legacyBrowser": {
        "integrity": "sha256-0wTIJNLsNA9kxoiTPpH0xcseRA+2MezF1r0cdhxx1X0= sha384-jrl8W8VHVqk42r//1LDOYgXG8KIIeBrYMRsEj8bXBEUBNq1X+PUr4XtqGubeoJ36",
        "url": "https://example.com/modules/<moduleName>/0.0.0/<moduleName>.legacy.browser.js"
      },
      "node": {
        "integrity": "sha256-LqwNreqEhpaXBRSmhW8/L1MpxcyBsoMwC4IKj8MSFTE= sha384-QLDAyAeq11y9llJhMXd36WwiGg49uJX23EtgaKsCVV83fUJ0rLrswb8V9IoeRIB2",
        "url": "https://example.com/modules/<moduleName>/0.0.0/<moduleName>.node.js"
      }
    }
  }
}

The clientCacheRevision property is used to cache bust all module bundles. This works because its value is appended to each module asset request from One App.

The modules property contains module objects containing the URL and subresource integrity information for each of the module's assets. There are three assets created by one-app-bundler for each module that need to be referenced here for One App to use, browser, legacyBrowser, and node. The value for the integrity property is generated by one-app-bundler and can be found in the bundle.integrity.manifest.json file within the module's root directory after running one-app-bundler on it.

Your CI / CD process can generate the module map and update it as modules are added / updated / removed and then publish the file to a static server. Just like with module assets One App does not have an opinion of where the module map is published, it only cares that the module map is accessible shaped correctly.

For a complete example on how to deploy your modules and how to update your module map, please visit the Publishing Modules Recipe.

Building One App

You can build the One App Docker image and run it in your cloud / data center of choice:

git clone https://github.com/americanexpress/one-app.git
cd one-app
docker build . --build-arg VERSION=$(cat .nvmrc)

Or you can build from source which creates your server side assets at ./lib and your client side assets to be deployed to a CDN at ./build.

git clone https://github.com/americanexpress/one-app.git
cd one-app
NODE_ENV=development npm ci
NODE_ENV=production npm run build

Configuring One App

One App is configured via environment variables. There are a few environment variables that are required for One App to start up including the one used to let One App know where to fetch a module map from as described above.

Minimum Required Environment Variables:

In order for One App to start after it has been deployed, the following environment variables must be set before attempting to deploy / start the One App container:

  • HOLOCRON_MODULE_MAP_URL
  • ONE_CLIENT_CDN_URL
  • ONE_CLIENT_CSP_REPORTING_URL
  • ONE_CLIENT_REPORTING_URL
  • ONE_CLIENT_ROOT_MODULE_NAME

Example:

HOLOCRON_MODULE_MAP_URL="https://example-module-map.vercel.app/"
ONE_CLIENT_CDN_URL="https://www.my-app-domain.com/_/static/"
ONE_CLIENT_CSP_REPORTING_URL="https://www.my-app-domain.com/_/report/security/csp-violation"
ONE_CLIENT_REPORTING_URL="https://www.my-app-domain.com/_/report/errors"
ONE_CLIENT_ROOT_MODULE_NAME="my-root-module-name"

Deploying to AWS Elastic Beanstalk

Prerequisites:

  • AWS account
  • A valid module map with at least the root module published and deployed. You can follow this guide to create your module map and deploy your modules.

You can deploy the published One App production image from Docker Hub to Elastic Beanstalk by following these steps:

  1. Go to the AWS console, select Elastic Beanstalk and click on "Create Application".
  2. Give your application a name and select "Docker" as the platform.
  3. Select "Sample Application" and click "Create Application".
  4. Before we can upload and install the One App image to our new environment, we need to add the Minimum Required Environment Variables. Click on the "Configuration" of your new environment, under the "Software" category click "Edit". Enter all the required environment variables under the "Environment Properties" section.

Important: Ensure that you have entered a valid HOLOCRON_MODULE_MAP_URL that is publicly accessible and that at least the root module specified in ONE_CLIENT_ROOT_MODULE_NAME is published; failure to do so, will result in One App crashing and unable to start.

  1. Click on "Upload and deploy". You will need to upload a Dockerrun.aws.json file that contains the following:
{
 "AWSEBDockerrunVersion": "1",
 "Image": {
   "Name": "oneamex/one-app:latest"
 },
 "Ports": [
   {
     "ContainerPort": "3000"
   }
 ]
}

Note: You can select the desired version of One App deployed to Docker Hub instead of latest by changing the tag in the image name.

After the deployment is complete, you can navigate to your application by clicking on "Go to environment". If the application health displays an error, One App might be failing to start due to a missing environment variable or missing configuration. You can request the logs and the console should display the reason why One App is crashing.

More information on how to deploy Docker containers on AWS Elastic Beanstalk can be found on the official AWS Documentation.

☝️ Return To Top