Managing environment variables in Ionic 2 / 3

Mobile App Development Ionic2 ionic3 dotenv

The Problem

When developing Ionic 2 apps, very often developers want to store different application configuration values in different environments. For example, the backend API URLs in development and production are different. Or, two different Google Map Api keys are used in QA and production environments.

Our Approach at F5 Works

The Recipe

Step 1: Create .env at project root (the KEY=VALUE store)

API_URL=http://localhost:3000/api/v1  
GOOGLE_MAP_API_KEY=XxxYyyZzz  

NOTE: you should git-ignore the .env file

Step 2: Inject .env content into ENV global variable

var dotenvConfig = require('dotenv').config();  
var _ = require('lodash');  
var path = require('path');  
var webpack = require('webpack');  
var ionicWebpackFactory = require(process.env.IONIC_WEBPACK_FACTORY);

function getPlugins() {  
  var plugins = [
    new webpack.DefinePlugin({
      'process.env': _(process.env)
                      .pick(_.keys(dotenvConfig))
                      .mapValues((v) => (JSON.stringify(v)))
                      .value()
    })
  ];
  // for dev builds, use our custom environment
  return [
    ...plugins,
    ionicWebpackFactory.getIonicEnvironmentPlugin()
  ];
}

module.exports = {  
  entry: process.env.IONIC_APP_ENTRY_POINT,
  output: {
    path: '{{BUILD}}',
    publicPath: 'build/',
    filename: process.env.IONIC_OUTPUT_JS_FILE_NAME,
    devtoolModuleFilenameTemplate: ionicWebpackFactory.getSourceMapperFunction(),
  },
  devtool: process.env.IONIC_SOURCE_MAP_TYPE,

  resolve: {
    extensions: ['.ts', '.js', '.json'],
    modules: [path.resolve('node_modules')]
  },

  module: {
    loaders: [
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        test: /\.ts$/,
        loader: process.env.IONIC_WEBPACK_LOADER
      }
    ]
  },

  plugins: getPlugins(),

  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  node: {
    fs: 'empty',
    net: 'empty',
    tls: 'empty'
  }
};

NOTE: you can find original webpack config from node_modules/@ionic/app-scripts

  "config": {
    "ionic_webpack": "./config/webpack.config.js"
  }
npm install dotenv --save-dev  
npm install lodash --save-dev  

Step 3: Create and inject AppConfig class

import { Injectable } from '@angular/core';

declare var process: any;

@Injectable()
export class AppConfig {  
  public apiBaseUrl: string;
  public googleMapApiKey: string;

  constructor() {
    this.apiBaseUrl = this._readString('API_URL', 'http://localhost:3000/api/v1');
    this.googleMapApiKey = this._readString('GOOGLE_MAP_API_KEY', 'xxxyyy111');

    console.debug('AppConfig', this);
  }

  private _readString(key: string, defaultValue?: string): string {
    const v = process.env[key];
    return v === undefined ? defaultValue : String(v);
  }
}
import { NgModule }     from '@angular/core';  
import { AppConfig }    from '../config/app.config';

@NgModule({
  providers: [
    AppConfig,

    // other injectables
  ]
})
export class AppModule {}  

Step 4: Reading values in AppConfig from other components

import { Component, ViewChild } from '@angular/core';  
import { AppConfig } from '../config/app.config';

@Component({
  templateUrl: 'app.html'
})
export class MyApp {  
  constructor(public appConfig: AppConfig) {
    console.debug('AppConfig', this.appConfig);
  }
}

.env for different environment

Now, you can populate different set values of into .env from the machine that build or run Ionic app. For instance, our CI agent in Jenkins has different set of .env values for building apps of different environments.

Alternative

Instead of having single .env, alternatively we could have json files for each environment.

config/developement.json  
config/production.json  

We used this approach in our Ionic1 projects. However when project grows, it becomes a bit messy as more personal config json files tend to be created. So we choose to experiment the single env approach which Twelve-Factor App suggests.