Examples

Example uses of the static site module

Angular SPA

To view an example deployment of an Angular single page application, run runway gen-sample static-angular in any directory. This will create a new static-angular/ directory in your current working directory containing a runway.yml and a sample-app module that can be deployed.

Extra Files in Angular

By default, angular uses environment/environment.ts as its way to pass environment specific configurations into your application. The downside to this is that you need to build your application for each environment and lose ability to build once and deploy everywhere.

The static site extra_files option solves this problem by moving environment configuration out of angular and into Runway. A small change to the way the application references environment config will need to be made.

  1. Wrap configuration access into a service that can be injected into your components.

  2. In the new config service, make an http request to load the config. Since extra_files uploads the files to the static site bucket, this request should be relative to your application.

  3. Cache the config and use normal observable patterns to provide access.

app.config.ts
export interface Config {
  endpoint: string;
}

@Injectable({
  providedIn: 'root'
})
export class AppConfig {
  constructor(private http: HttpClient) {}

  getConfig(): Observable<Config> {
    return this.http.get<Config>('assets/config.json');
  }
}
app.component.ts
export class AppComponent implements OnInit {
  title = 'Angular App';

  constructor(private config: AppConfig) {}

  ngOnInit() {
    this.config.getConfig().subscribe((config) => {
      this.title = config.endpoint;
    });
  }
}
runway.yml
variables:
  website:
    api_endpoint:
      dev: https://api.dev.example.com
      test: https://api.test.example.com

deployments:
  - name: WebApp
    modules:
      - path: .
        type: static
        environments:
          dev: true
          test: true
        options:
          build_steps:
            - npm ci
            - npm run build
          build_output: dist/web
          extra_files:
            - name: assets/config.json
              content:
                endpoint: ${var website.api_endpoint.${env DEPLOY_ENVIRONMENT}}
        parameters:
          namespace: my-app-namespace
          staticsite_cf_disable: true
    regions:
      - us-east-1

Angular Development Workflow

While developing an Angular application, a local live environment is typically used and Runway is not. This means that assets/config.json does not exist and your application would likely fail. Take the following steps to get your development environment running.

  1. Create a stub src/assets/config.json that defines all the configuration attributes. The values can be empty strings.

  2. Create a ‘dev’ config file: src/assets/config-dev.json. Populate the configuration values with appropriate values for your local dev environment.

  3. Edit angular.json

    • Add a fileReplacements option to projects.<app>.architect.build.options.

      {
        "fileReplacements": [{
          "replace": "src/assets/config.json",
          "with": "src/assets/config-dev.json"
        }]
      }
      
  4. Run npx ng serve

    Note

    It would be a better practice to define a new ‘local’ configuration target instead of adding fileReplacements to the default configuration target.

    “build” Configuration
      {
        "configurations": {
          "local": {
            "fileReplacements": [{
              "replace": "src/assets/config.json",
              "with": "src/assets/config-local.json"
            }]
          }
        }
      }
    
    “serve” Configuration
      {
        "configurations": {
          "local": {
            "browserTarget": "<app>:build:local"
          }
        }
      }
    
    $ npx ng serve --configuration=local
    

React SPA

To view an example deployment of a React single page application, run runway gen-sample static-react in any directory. This will create a new static-react/ directory in your current working directory containing a runway.yml and a sample-app module that can be deployed.

Extra Files in React

React by itself is not concerned with different environments or how a developer initializes the application with different backends. This is more of a concern with other layers of your application stack, e.g. Redux. However, the concept is similar to the Angular examples.

Plain React
// Use your favorite http client
import axios from 'axios';

// Make a request to load the config
axios.get('config.json').then(resp => {
  return resp.data.endpoint;
})
.then(endpoint => {
  // Render the react component
  ReactDOM.render(<App message={endpoint} />, document.getElementById('root'));
});

Initialize the redux store with an initial config

React Redux
axios.get('config.json').then(resp => {
  return resp.data;
})
.then(config => {
  // Create a redux store
  return store(config);
})
.then(store => {
  ReactDOM.render(
    <Provider store={store}>
      <App/>
    </Provider>,
    document.getElementById('root')
  );
});
runway.yml
variables:
  website:
    api_endpoint:
      dev: https://api.dev.example.com
      test: https://api.test.example.com

deployments:
  - name: WebApp
    modules:
      - path: .
        type: static
        environments:
          dev: true
          test: true
        options:
          build_output: build
          build_steps:
            - npm ci
            - npm run build
          extra_files:
            - name: config.json
              content:
                endpoint: ${var website.api_endpoint.${env DEPLOY_ENVIRONMENT}}
        parameters:
          namespace: my-app-namespace
          staticsite_cf_disable: true
    regions:
      - us-west-2

React Development Workflow

React doesn’t have an equivalent feature as Angular’s fileReplacements so this solution isn’t as flexible.

  1. Create the file public/config.json.

    Add content that matches the structure defined in extra_files and populate the values needed for local development.

    Example

    {
      "endpoint": "https://api.dev.example.com"
    }
    
  2. (Optional) Add public/config.json to .gitignore

    Note

    If you don’t want to add public/config.json to .gitignore, you should configure Runways source hashing to exclude it.

    source_hashing:
      enabled: true
      directories:
        - path: ./
          exclusions:
            - public/config.json
    
  3. Run npm run start