New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: Ionic 2 (dev/prod) environment variables configuration #1205

Closed
jgw96 opened this Issue Jul 25, 2016 · 120 comments

Comments

Projects
None yet
@jgw96
Contributor

jgw96 commented Jul 25, 2016

From @amreladawy on July 24, 2016 6:58

Short description of the problem:

It is a feature request.
Just like Angular2, I hope that Ionic can provide 2 files (environment.dev.ts and environment.prod.ts) that would contain variables with different values corresponding to production and development environment.
During the build, the appropriate file to be copied and bundled within the app artifact.

Which Ionic Version? 2.x

https://forum.ionicframework.com/t/ionic-2-environment-variables-config-setup/58147/1

https://stackoverflow.com/questions/36004810/how-to-config-different-development-environment-in-angular-2-app

Copied from original issue: ionic-team/ionic#7413

@itrethan

This comment has been minimized.

Show comment
Hide comment
@itrethan

itrethan Oct 22, 2016

Can we raise the priority for this issue? This is actually very important. Our app has different configs for prod and devel. Without this, it requires ugly hand rolled variable updates... Just make the release really cumbersome.

itrethan commented Oct 22, 2016

Can we raise the priority for this issue? This is actually very important. Our app has different configs for prod and devel. Without this, it requires ugly hand rolled variable updates... Just make the release really cumbersome.

@dnmd

This comment has been minimized.

Show comment
Hide comment
@dnmd

dnmd Oct 24, 2016

Currently our implementation uses the rollup-plugin-replace, and a slightly modified rollup config.

Basically what happens is that the import paths are replaced based on the process.env.IONIC_ENV variable during compile time. This will use the environment.dev.ts during development and environment.prod.ts when in production.

Implementation steps

  1. install the rollup-plugin-replace
    npm install --save-dev rollup-plugin-replace

  2. create two files; environment.dev.ts and environment.prod.ts within e.g. the src/config directory.

├── src/config/environment.dev.ts

export const ENV = {  
  PRODUCTION : false,
  API_URL    : 'dev.local'
};
├── src/config/environment.prod.ts

export const ENV = {  
  PRODUCTION : true,
  API_URL    : 'prod.local'
};
  1. import the environment-dev as the default within your pages / services etc.
// use the 'environment-dev' as the default import(!)
import { ENV } from '../../config/environment-dev';

@Component({
  templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
   console.log( ENV.API_URL );
}
  1. update your /package.json
├── /package.json

"config": {
    "ionic_rollup": "./config/rollup.config.js"
}
  1. create your rollup.config.js within the /config directory. Require the plugin, and add the replace snippet below to your plugins section. One can use node_modules\@ionic\app-scripts\config\rollup.config.js as a template.
├── /config/rollup.config.js

var replace = require('rollup-plugin-replace');
var isProd  = (process.env.IONIC_ENV === 'prod');
...
plugins: [
    replace({
      exclude: 'node_modules/**',
      // use the /config/environment-dev as the default import(!), no stub needed.
      // note we only replace the "last" part of the import statement so relative paths are maintained
      '/config/environment-dev' : ( isProd ? '/config/environment-prod' : '/config/environment-dev'),
    })
   ...
]

Hope this helps someone! Of course in an ideal situation a file replacement would take place, similar to the Angular CLI

dnmd commented Oct 24, 2016

Currently our implementation uses the rollup-plugin-replace, and a slightly modified rollup config.

Basically what happens is that the import paths are replaced based on the process.env.IONIC_ENV variable during compile time. This will use the environment.dev.ts during development and environment.prod.ts when in production.

Implementation steps

  1. install the rollup-plugin-replace
    npm install --save-dev rollup-plugin-replace

  2. create two files; environment.dev.ts and environment.prod.ts within e.g. the src/config directory.

├── src/config/environment.dev.ts

export const ENV = {  
  PRODUCTION : false,
  API_URL    : 'dev.local'
};
├── src/config/environment.prod.ts

export const ENV = {  
  PRODUCTION : true,
  API_URL    : 'prod.local'
};
  1. import the environment-dev as the default within your pages / services etc.
// use the 'environment-dev' as the default import(!)
import { ENV } from '../../config/environment-dev';

@Component({
  templateUrl: 'hello-ionic.html'
})
export class HelloIonicPage {
   console.log( ENV.API_URL );
}
  1. update your /package.json
├── /package.json

"config": {
    "ionic_rollup": "./config/rollup.config.js"
}
  1. create your rollup.config.js within the /config directory. Require the plugin, and add the replace snippet below to your plugins section. One can use node_modules\@ionic\app-scripts\config\rollup.config.js as a template.
├── /config/rollup.config.js

var replace = require('rollup-plugin-replace');
var isProd  = (process.env.IONIC_ENV === 'prod');
...
plugins: [
    replace({
      exclude: 'node_modules/**',
      // use the /config/environment-dev as the default import(!), no stub needed.
      // note we only replace the "last" part of the import statement so relative paths are maintained
      '/config/environment-dev' : ( isProd ? '/config/environment-prod' : '/config/environment-dev'),
    })
   ...
]

Hope this helps someone! Of course in an ideal situation a file replacement would take place, similar to the Angular CLI

@Maziar-Fotouhi

This comment has been minimized.

Show comment
Hide comment
@Maziar-Fotouhi

Maziar-Fotouhi Oct 26, 2016

Is there any plans to actually implement this?

Maziar-Fotouhi commented Oct 26, 2016

Is there any plans to actually implement this?

@tabirkeland

This comment has been minimized.

Show comment
Hide comment
@tabirkeland

tabirkeland Nov 1, 2016

With "@ionic/app-scripts": "0.0.39" now defaulting to webpack for bundling, I am doing something like this.

Steps to implement:

  1. Make sure you have installed the latest app-scripts npm install @ionic/app-scripts@latest and have the latest tsconfig.json.

  2. Install dotenv.

  3. Create .env file with env variables defined in the root directory of your app. Recommended:
    add .env to .gitignore.

  4. Create and modify webpack.config.js from original found here:

├── /config/webpack.config.js

require('dotenv').config();

...
function getPlugins() {
  var plugins = [
    new webpack.DefinePlugin({
      'API_URL': JSON.stringify(process.env.API_URL)
      // Add any more variables here that you wish to define
    })
  ];

  if (process.env.IONIC_ENV === 'prod') {
      // This helps ensure the builds are consistent if source hasn't changed:
    plugins.push(new webpack.optimize.OccurrenceOrderPlugin());
  }
  return plugins;
}
...
  1. Define custom webpack config file in package.json.
├── /package.json

"config": {
    "ionic_webpack": "./config/webpack.config.js"
}
  1. Create custom typings file defining the constants that are in your .env file so that webpack can populate them and you are able to reference them in your application.
├── /src/customTypings/customTypings.d.ts

declare var API_URL: string;
// Add any more variables here that you wish to define

You should now be able to reference the global variable(s) in your app.

Furthermore, you can create multiple .env files for different environments and require them in webpack.config.js like so:

require('dotenv').config({path: '/custom/path/to/your/env/vars'})

tabirkeland commented Nov 1, 2016

With "@ionic/app-scripts": "0.0.39" now defaulting to webpack for bundling, I am doing something like this.

Steps to implement:

  1. Make sure you have installed the latest app-scripts npm install @ionic/app-scripts@latest and have the latest tsconfig.json.

  2. Install dotenv.

  3. Create .env file with env variables defined in the root directory of your app. Recommended:
    add .env to .gitignore.

  4. Create and modify webpack.config.js from original found here:

├── /config/webpack.config.js

require('dotenv').config();

...
function getPlugins() {
  var plugins = [
    new webpack.DefinePlugin({
      'API_URL': JSON.stringify(process.env.API_URL)
      // Add any more variables here that you wish to define
    })
  ];

  if (process.env.IONIC_ENV === 'prod') {
      // This helps ensure the builds are consistent if source hasn't changed:
    plugins.push(new webpack.optimize.OccurrenceOrderPlugin());
  }
  return plugins;
}
...
  1. Define custom webpack config file in package.json.
├── /package.json

"config": {
    "ionic_webpack": "./config/webpack.config.js"
}
  1. Create custom typings file defining the constants that are in your .env file so that webpack can populate them and you are able to reference them in your application.
├── /src/customTypings/customTypings.d.ts

declare var API_URL: string;
// Add any more variables here that you wish to define

You should now be able to reference the global variable(s) in your app.

Furthermore, you can create multiple .env files for different environments and require them in webpack.config.js like so:

require('dotenv').config({path: '/custom/path/to/your/env/vars'})
@slinto

This comment has been minimized.

Show comment
Hide comment
@slinto

slinto Nov 8, 2016

This solution is working, but I think, rewriting all webpack.config is not good, becase updates... Is there any idea from ionic team?

slinto commented Nov 8, 2016

This solution is working, but I think, rewriting all webpack.config is not good, becase updates... Is there any idea from ionic team?

@rossholdway

This comment has been minimized.

Show comment
Hide comment
@rossholdway

rossholdway Nov 11, 2016

@jgw96 Can we get this added to a milestone? We should be able to specify different environment configuration e.g. different API endpoints for dev and production. As @slinto mentioned creating a modified webpack.config is not ideal as updates will cause issues :/

rossholdway commented Nov 11, 2016

@jgw96 Can we get this added to a milestone? We should be able to specify different environment configuration e.g. different API endpoints for dev and production. As @slinto mentioned creating a modified webpack.config is not ideal as updates will cause issues :/

@locnguyen

This comment has been minimized.

Show comment
Hide comment
@locnguyen

locnguyen Nov 11, 2016

I'd really like to see this functionality supported. Is a custom webpack config the only way?

locnguyen commented Nov 11, 2016

I'd really like to see this functionality supported. Is a custom webpack config the only way?

@Maziar-Fotouhi

This comment has been minimized.

Show comment
Hide comment
@Maziar-Fotouhi

Maziar-Fotouhi Nov 11, 2016

Okay... After a lot of coffee and head bumping, I've realized that the best way (at least for me) is to change the environments manually and not rely on ionic to change it. That was mainly because ionic-cli does not let you runionic serve with production environment.
I have set an environment.ts in the root folder of the app that contains all the variables.

environment.ts

export class ENV {

    public static currentEnvironment: string = "development";
    // public static currentEnvironment: string = "production";

    public static development: any = {
         key1: "value1",
         key2: "value2",
        ......
        ......
    };
    public static production: any = {
        key1: "value1",
        key2: "value2",
        ......
        ......
    };
}

Then I added an environment.service among my services.

environment.service.ts

import {Injectable} from '@angular/core';
import {ENV} from '../../environments/environment';

@Injectable()
export class EnvironmentService {


    public getKey1() : string{
        if(ENV.currentEnvironment === "development"){
            return ENV.development.key1;
        } else if(ENV.currentEnvironment === "production") {
            return ENV.production.key1;
        }
    }

    public getKey2() : string{
        if(ENV.currentEnvironment === "development"){
            return ENV.development.key2;
        } else if(ENV.currentEnvironment === "production") {
            return ENV.production.key2;
        }
    }

     ......
     ......

}

Then I added the service to the providers of the app.module and used it like any other service.
E.g. in any component you can access the values like this:

any.component.ts

...
...
...

import {EnvironmentService} from '../../services/environment.service';

...
...
...

constructor(
                      ...
                      ...
                      ...
                      private environmentService: EnvironmentService
                      ...
                      ...
                      ...) {
    }

...
...
...

let baseUrl = this.environmentService.getKey1();

...
...
...

And finally, in order to change the environment, you have to toggle (comment and uncomment) the first two line of environment.ts.

This is a good workaround for now, if you need different values (URLs, API keys, etc.) to be used in development and production. But, I think eventually, ionic and ionic-cli teams will have to work together to integrate something like this internally, that lets us use different sets of environment variables based on a flag that we pass to the command that is running the app.
E.g. :
ionic (serve/run) (--prod/--dev)

Maziar-Fotouhi commented Nov 11, 2016

Okay... After a lot of coffee and head bumping, I've realized that the best way (at least for me) is to change the environments manually and not rely on ionic to change it. That was mainly because ionic-cli does not let you runionic serve with production environment.
I have set an environment.ts in the root folder of the app that contains all the variables.

environment.ts

export class ENV {

    public static currentEnvironment: string = "development";
    // public static currentEnvironment: string = "production";

    public static development: any = {
         key1: "value1",
         key2: "value2",
        ......
        ......
    };
    public static production: any = {
        key1: "value1",
        key2: "value2",
        ......
        ......
    };
}

Then I added an environment.service among my services.

environment.service.ts

import {Injectable} from '@angular/core';
import {ENV} from '../../environments/environment';

@Injectable()
export class EnvironmentService {


    public getKey1() : string{
        if(ENV.currentEnvironment === "development"){
            return ENV.development.key1;
        } else if(ENV.currentEnvironment === "production") {
            return ENV.production.key1;
        }
    }

    public getKey2() : string{
        if(ENV.currentEnvironment === "development"){
            return ENV.development.key2;
        } else if(ENV.currentEnvironment === "production") {
            return ENV.production.key2;
        }
    }

     ......
     ......

}

Then I added the service to the providers of the app.module and used it like any other service.
E.g. in any component you can access the values like this:

any.component.ts

...
...
...

import {EnvironmentService} from '../../services/environment.service';

...
...
...

constructor(
                      ...
                      ...
                      ...
                      private environmentService: EnvironmentService
                      ...
                      ...
                      ...) {
    }

...
...
...

let baseUrl = this.environmentService.getKey1();

...
...
...

And finally, in order to change the environment, you have to toggle (comment and uncomment) the first two line of environment.ts.

This is a good workaround for now, if you need different values (URLs, API keys, etc.) to be used in development and production. But, I think eventually, ionic and ionic-cli teams will have to work together to integrate something like this internally, that lets us use different sets of environment variables based on a flag that we pass to the command that is running the app.
E.g. :
ionic (serve/run) (--prod/--dev)

@slinto

This comment has been minimized.

Show comment
Hide comment
@slinto

slinto Nov 11, 2016

hmm, the manual comment/uncomment of right ENV is dangerous, because is there a big risk with publishing application with development environment to store, especially if your team is about 1+ people :) I think about right way as:

ionic serve / DEVELOPMENT ENV (DEFAULT):
$ ionic serve

ionic serve / PRODUCTION or CUSTOM ENV:
$ ionic serve --env=prod,
$ ionic serve --env=test,
$ ionic serve --prod

ionic build / PRODUCTION ENV (DEFAULT):
$ ionic build

ionic build / DEVELOPMENT or CUSTOM ENV:
$ ionic build --dev
$ ionic build --env=test
$ ionic build --env=dev

eg. http://jonnyreeves.co.uk/2016/simple-webpack-prod-and-dev-config/

slinto commented Nov 11, 2016

hmm, the manual comment/uncomment of right ENV is dangerous, because is there a big risk with publishing application with development environment to store, especially if your team is about 1+ people :) I think about right way as:

ionic serve / DEVELOPMENT ENV (DEFAULT):
$ ionic serve

ionic serve / PRODUCTION or CUSTOM ENV:
$ ionic serve --env=prod,
$ ionic serve --env=test,
$ ionic serve --prod

ionic build / PRODUCTION ENV (DEFAULT):
$ ionic build

ionic build / DEVELOPMENT or CUSTOM ENV:
$ ionic build --dev
$ ionic build --env=test
$ ionic build --env=dev

eg. http://jonnyreeves.co.uk/2016/simple-webpack-prod-and-dev-config/

@Maziar-Fotouhi

This comment has been minimized.

Show comment
Hide comment
@Maziar-Fotouhi

Maziar-Fotouhi Nov 11, 2016

@slinto You are absolutely correct, there is the possibility of publishing the app with dev variables. But, it is only as dangerous as any other solution. You may build the prod app with the wrong command as well.
I'm actually using this in a corporate project with a big number of people on the team. I think nowadays every team uses version control systems like git or svn. So, this would be just a matter of team functionality and team members being coordinated with each other. And furthermore, there is usually only one person in team who is in charge of deploying the app.
But, again, you're right. With manual toggle of environments, there is a slightly higher chance of making the mistake. So, as I said, this is only a temporary fix. Ideally, this should be internal to ionic, using the commands you mentioned.

Maziar-Fotouhi commented Nov 11, 2016

@slinto You are absolutely correct, there is the possibility of publishing the app with dev variables. But, it is only as dangerous as any other solution. You may build the prod app with the wrong command as well.
I'm actually using this in a corporate project with a big number of people on the team. I think nowadays every team uses version control systems like git or svn. So, this would be just a matter of team functionality and team members being coordinated with each other. And furthermore, there is usually only one person in team who is in charge of deploying the app.
But, again, you're right. With manual toggle of environments, there is a slightly higher chance of making the mistake. So, as I said, this is only a temporary fix. Ideally, this should be internal to ionic, using the commands you mentioned.

@allaanz

This comment has been minimized.

Show comment
Hide comment
@allaanz

allaanz commented Nov 14, 2016

+1

@jthoms1 jthoms1 self-assigned this Nov 15, 2016

@jthoms1 jthoms1 added the enhancement label Nov 15, 2016

@zjhiphop

This comment has been minimized.

Show comment
Hide comment
@zjhiphop

zjhiphop Nov 20, 2016

Hey, guys, any progress of official implements?

zjhiphop commented Nov 20, 2016

Hey, guys, any progress of official implements?

@rolandjitsu

This comment has been minimized.

Show comment
Hide comment
@rolandjitsu

rolandjitsu Nov 21, 2016

@dnmd can you confirm that your solution works with a production build?

rolandjitsu commented Nov 21, 2016

@dnmd can you confirm that your solution works with a production build?

@Yimiprod

This comment has been minimized.

Show comment
Hide comment
@Yimiprod

Yimiprod Nov 25, 2016

with 0.0.46 adding anything at config in package.json trigger rollup warnings (and the script freeze after that)

[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'NgContentAst' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.
[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'PropertyBindingType' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.
[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'templateVisitAll' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.

By the way, isn't it better to listen for the argument --release ?
Another thing, why with 0.0.46 it's rollup and not webpack by default?

Yimiprod commented Nov 25, 2016

with 0.0.46 adding anything at config in package.json trigger rollup warnings (and the script freeze after that)

[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'NgContentAst' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.
[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'PropertyBindingType' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.
[18:58:40]  rollup: Conflicting namespaces: /space/www/applications/wav/node_modules/@angular/compiler/index.js
            re-exports 'templateVisitAll' from both
            /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js (will be
            ignored) and /space/www/applications/wav/node_modules/@angular/compiler/src/template_parser/template_ast.js.

By the way, isn't it better to listen for the argument --release ?
Another thing, why with 0.0.46 it's rollup and not webpack by default?

@movrack

This comment has been minimized.

Show comment
Hide comment
@movrack

movrack Nov 26, 2016

I like the idea of @slinto
In our case, we have actually 5 environments...

  • dev
  • test (unit test)
  • iat (human first line test => developer tester)
  • uat (human second line test => business client tester)
  • prod

And we have to copy config file at build time to choose the environment.
To chose the environment at build time, we run it like :
TARGET=xxx ionic run yyy for mac or set TARGET=xxx&& ionic run yyy for windows developer.

This is managed by a hook based on this post : http://www.kdmooreconsulting.com/blogs/build-a-cordova-hook-to-setup-environment-specific-constants/

But since we do that, we lost the live reload feature! (ionic-app-script watch doesn't copy our right config.js file and we don't know how to do that).

If we can set a parameter like @slinto told -- to choose the environment with something like "--env=xxx", and make it available for live reload ... -- it will be really cool!

movrack commented Nov 26, 2016

I like the idea of @slinto
In our case, we have actually 5 environments...

  • dev
  • test (unit test)
  • iat (human first line test => developer tester)
  • uat (human second line test => business client tester)
  • prod

And we have to copy config file at build time to choose the environment.
To chose the environment at build time, we run it like :
TARGET=xxx ionic run yyy for mac or set TARGET=xxx&& ionic run yyy for windows developer.

This is managed by a hook based on this post : http://www.kdmooreconsulting.com/blogs/build-a-cordova-hook-to-setup-environment-specific-constants/

But since we do that, we lost the live reload feature! (ionic-app-script watch doesn't copy our right config.js file and we don't know how to do that).

If we can set a parameter like @slinto told -- to choose the environment with something like "--env=xxx", and make it available for live reload ... -- it will be really cool!

@schaergeek

This comment has been minimized.

Show comment
Hide comment
@schaergeek

schaergeek Nov 28, 2016

Definitely a must. So +1

schaergeek commented Nov 28, 2016

Definitely a must. So +1

@iacomus

This comment has been minimized.

Show comment
Hide comment
@iacomus

iacomus Nov 30, 2016

So how would this tie in with the Live Deploy to channel feature currently available https://docs.ionic.io/services/deploy/ ?

iacomus commented Nov 30, 2016

So how would this tie in with the Live Deploy to channel feature currently available https://docs.ionic.io/services/deploy/ ?

@mvidailhet

This comment has been minimized.

Show comment
Hide comment
@mvidailhet

mvidailhet Dec 21, 2016

OK, so I needed this kind of feature to be able to have different parameters (api endpoints, google analytics ID etc...) with different environments (dev, preprod, prod...).

So I made my first module (feedbacks more than welcome, and please be gentle :p) to be able to do that: gl-ionic2-env-configuration

Basically, it loads a env-configuration.json located in the www folder before anything else (so that your api url will be set even in your apiService constructor, for example).

In the package documentation, I linked a simple node executable to easily copy the configuration file for a specific environment.

Advantages

  • You don't need to override the Ionic webpack.config (which could break things when Ionic updates).
  • You can have as much environments as you want and name it as you like.
  • You can dynamically change the configuration file without having to recompile the app (which will be very useful for continous integration systems).

Hope this will help.

mvidailhet commented Dec 21, 2016

OK, so I needed this kind of feature to be able to have different parameters (api endpoints, google analytics ID etc...) with different environments (dev, preprod, prod...).

So I made my first module (feedbacks more than welcome, and please be gentle :p) to be able to do that: gl-ionic2-env-configuration

Basically, it loads a env-configuration.json located in the www folder before anything else (so that your api url will be set even in your apiService constructor, for example).

In the package documentation, I linked a simple node executable to easily copy the configuration file for a specific environment.

Advantages

  • You don't need to override the Ionic webpack.config (which could break things when Ionic updates).
  • You can have as much environments as you want and name it as you like.
  • You can dynamically change the configuration file without having to recompile the app (which will be very useful for continous integration systems).

Hope this will help.

@sean-hill

This comment has been minimized.

Show comment
Hide comment
@sean-hill

sean-hill Jan 2, 2017

Any updates to this Ionic team? I would love to see this baked into the ionic-app-scripts repo.

sean-hill commented Jan 2, 2017

Any updates to this Ionic team? I would love to see this baked into the ionic-app-scripts repo.

@fiznool

This comment has been minimized.

Show comment
Hide comment
@fiznool

fiznool Feb 2, 2017

Inspired by the solution from @tabirkeland I thought I'd post my own version of this. The differences with the script below vs the original solution:

  • The Ionic webpack.config script is built upon, not replaced, meaning that any updates to @ionic/app-scripts should be merged in.
  • The script is aware of Ionic's --prod flag, allowing you to provide separate configuration for dev and prod builds.
  • There is no dependency on dotenv.

Here's the steps to get it all working:

  1. Create a file at config/webpack.config.js and paste the following content:
// Set the `ENV` global variable to be used in the app.
var path = require('path');
var webpack = require('webpack');

var projectRootDir = process.env.IONIC_ROOT_DIR;
var appScriptsDir = process.env.IONIC_APP_SCRIPTS_DIR;

var config = require(path.join(appScriptsDir, 'config', 'webpack.config.js'));

var env = process.env.IONIC_ENV || 'dev';
var envVars;
try {
  envVars = require(path.join(projectRootDir, 'env', env + '.json'));
} catch(e) {
  envVars = {};
}

config.plugins = config.plugins || [];
config.plugins.push(
  new webpack.DefinePlugin({
    ENV: Object.assign(envVars, {
      environment: JSON.stringify(env)
    })
  })
);

if(env === 'prod') {
  // This helps ensure the builds are consistent if source hasn't changed:
  config.plugins.push(new webpack.optimize.OccurrenceOrderPlugin());
}

module.exports = config;
  1. Add the following entry to your package.json:
  "config": {
    "ionic_webpack": "./config/webpack.config.js"
  }
  1. If you need additional configuration, create two files env/dev.json and env/prod.json. In here, put any configuration you need for that environment. Your json should be an object of key-value pairs, which will be made available for use in your application.
{
  "enableLogging": true,
  "apiServerUrl": "\"http://example.com/api\""
}

Now, you can use the ENV global constant anywhere in your .ts files:

declare const ENV;

if(ENV.environment === 'dev') {
  // Run without the `--prod` flag.
  // Any keys defined in `dev.json` will be available on the `ENV` object.
} else if (ENV.environment === 'prod') {
  // Run with the `--prod` flag.
  // Any keys defined in `prod.json` will be available on the `ENV` object.
}

The script creates an ENV object with a single key, environment, which is set to prod if you run your ionic command with the --prod flag. Otherwise, this will be dev.

The env/dev.json and env/prod.json files are optional. If present, the script will merge the appropriate object into ENV. The script above uses webpack's DefinePlugin, so remember to 'stringify' any string values, otherwise webpack will assume you want to insert a code fragment. For example:

{
  "apiServerUrl": "\"http://example.com/api\""
}

It would be great to see this baked into the core webpack.config.js file in the app-scripts repo.

fiznool commented Feb 2, 2017

Inspired by the solution from @tabirkeland I thought I'd post my own version of this. The differences with the script below vs the original solution:

  • The Ionic webpack.config script is built upon, not replaced, meaning that any updates to @ionic/app-scripts should be merged in.
  • The script is aware of Ionic's --prod flag, allowing you to provide separate configuration for dev and prod builds.
  • There is no dependency on dotenv.

Here's the steps to get it all working:

  1. Create a file at config/webpack.config.js and paste the following content:
// Set the `ENV` global variable to be used in the app.
var path = require('path');
var webpack = require('webpack');

var projectRootDir = process.env.IONIC_ROOT_DIR;
var appScriptsDir = process.env.IONIC_APP_SCRIPTS_DIR;

var config = require(path.join(appScriptsDir, 'config', 'webpack.config.js'));

var env = process.env.IONIC_ENV || 'dev';
var envVars;
try {
  envVars = require(path.join(projectRootDir, 'env', env + '.json'));
} catch(e) {
  envVars = {};
}

config.plugins = config.plugins || [];
config.plugins.push(
  new webpack.DefinePlugin({
    ENV: Object.assign(envVars, {
      environment: JSON.stringify(env)
    })
  })
);

if(env === 'prod') {
  // This helps ensure the builds are consistent if source hasn't changed:
  config.plugins.push(new webpack.optimize.OccurrenceOrderPlugin());
}

module.exports = config;
  1. Add the following entry to your package.json:
  "config": {
    "ionic_webpack": "./config/webpack.config.js"
  }
  1. If you need additional configuration, create two files env/dev.json and env/prod.json. In here, put any configuration you need for that environment. Your json should be an object of key-value pairs, which will be made available for use in your application.
{
  "enableLogging": true,
  "apiServerUrl": "\"http://example.com/api\""
}

Now, you can use the ENV global constant anywhere in your .ts files:

declare const ENV;

if(ENV.environment === 'dev') {
  // Run without the `--prod` flag.
  // Any keys defined in `dev.json` will be available on the `ENV` object.
} else if (ENV.environment === 'prod') {
  // Run with the `--prod` flag.
  // Any keys defined in `prod.json` will be available on the `ENV` object.
}

The script creates an ENV object with a single key, environment, which is set to prod if you run your ionic command with the --prod flag. Otherwise, this will be dev.

The env/dev.json and env/prod.json files are optional. If present, the script will merge the appropriate object into ENV. The script above uses webpack's DefinePlugin, so remember to 'stringify' any string values, otherwise webpack will assume you want to insert a code fragment. For example:

{
  "apiServerUrl": "\"http://example.com/api\""
}

It would be great to see this baked into the core webpack.config.js file in the app-scripts repo.

@NightOnFire

This comment has been minimized.

Show comment
Hide comment
@NightOnFire

NightOnFire Feb 2, 2017

I implemented the solution from @fiznool the webpack script does not look for env/dev.json but env/dev and when it does have .json it auto converts to an object so no need for the JSON.parse. I changed envVars = JSON.parse(require(path.join(projectRootDir, 'env', env))); to envVars = require(path.join(projectRootDir, 'env', env + '.json'));.

My very limited knowlege of webpack stumped me for a bit and I had to add extra quotes in my json so I ended up with {"foo": "\"bar\""}. There is probably a better way to deal with this though.

NightOnFire commented Feb 2, 2017

I implemented the solution from @fiznool the webpack script does not look for env/dev.json but env/dev and when it does have .json it auto converts to an object so no need for the JSON.parse. I changed envVars = JSON.parse(require(path.join(projectRootDir, 'env', env))); to envVars = require(path.join(projectRootDir, 'env', env + '.json'));.

My very limited knowlege of webpack stumped me for a bit and I had to add extra quotes in my json so I ended up with {"foo": "\"bar\""}. There is probably a better way to deal with this though.

@yerboogieman

This comment has been minimized.

Show comment
Hide comment
@yerboogieman

yerboogieman Jan 20, 2018

Well, fair enough @dwieeb and thank you very much for the detailed explanation!

yerboogieman commented Jan 20, 2018

Well, fair enough @dwieeb and thank you very much for the detailed explanation!

@zaarheed

This comment has been minimized.

Show comment
Hide comment
@zaarheed

zaarheed Feb 17, 2018

+1 (what's the correct way to vote on a feature request?)

zaarheed commented Feb 17, 2018

+1 (what's the correct way to vote on a feature request?)

@iamjoyce

This comment has been minimized.

Show comment
Hide comment
@iamjoyce

iamjoyce Feb 21, 2018

@zuperm4n Use the thumbs up emoji on the first post

iamjoyce commented Feb 21, 2018

@zuperm4n Use the thumbs up emoji on the first post

@GFoley83

This comment has been minimized.

Show comment
Hide comment
@GFoley83

GFoley83 Feb 21, 2018

@dwieeb can we get an ETA for Ionic Angular 4 please? Weeks, months?
Be nice to get a ballpark so we can figure out whether to implement one of the many workarounds or hold out.

GFoley83 commented Feb 21, 2018

@dwieeb can we get an ETA for Ionic Angular 4 please? Weeks, months?
Be nice to get a ballpark so we can figure out whether to implement one of the many workarounds or hold out.

@renweibo

This comment has been minimized.

Show comment
Hide comment
@renweibo

renweibo Feb 22, 2018

+1 for this feature request

renweibo commented Feb 22, 2018

+1 for this feature request

@GFoley83

This comment has been minimized.

Show comment
Hide comment
@GFoley83

GFoley83 Feb 25, 2018

For those looking for a solution that supports ngc, karma & protractor tests, multiple configurations e.g test, uat etc. and works exactly like Angular CLI's environment setup
import { environment } from '@env/environment';,
I've posted my setup here:
ionic-team/ionic-app-scripts#762 (comment)

Works by extending webpack's configuration so should be pretty easy to refactor out later whenever Ionic 4 drops with native Angular CLI support.

GFoley83 commented Feb 25, 2018

For those looking for a solution that supports ngc, karma & protractor tests, multiple configurations e.g test, uat etc. and works exactly like Angular CLI's environment setup
import { environment } from '@env/environment';,
I've posted my setup here:
ionic-team/ionic-app-scripts#762 (comment)

Works by extending webpack's configuration so should be pretty easy to refactor out later whenever Ionic 4 drops with native Angular CLI support.

@wilfredonoyola

This comment has been minimized.

Show comment
Hide comment
@wilfredonoyola

wilfredonoyola Feb 27, 2018

Hi All,
I have integrated this (https://github.com/gshigeto/ionic-environment-variables), It works very nice!

Thanks!

wilfredonoyola commented Feb 27, 2018

Hi All,
I have integrated this (https://github.com/gshigeto/ionic-environment-variables), It works very nice!

Thanks!

@TivonChen

This comment has been minimized.

Show comment
Hide comment
@TivonChen

TivonChen Mar 16, 2018

@wilfredonoyola I use this too, thanks!

TivonChen commented Mar 16, 2018

@wilfredonoyola I use this too, thanks!

@tabirkeland

This comment has been minimized.

Show comment
Hide comment
@tabirkeland

tabirkeland Mar 16, 2018

All, with Ionic 4 release approaching, I know that ENV vars will be handled. If you are using Ionic 3.9.2, here is what I have been using for months to handle ENV vars. It's been pieced together from this and a few other threads.

https://gist.github.com/tabirkeland/a17c67b2f1ea3331d94db34ed7191c34

tabirkeland commented Mar 16, 2018

All, with Ionic 4 release approaching, I know that ENV vars will be handled. If you are using Ionic 3.9.2, here is what I have been using for months to handle ENV vars. It's been pieced together from this and a few other threads.

https://gist.github.com/tabirkeland/a17c67b2f1ea3331d94db34ed7191c34

@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Mar 20, 2018

Contributor

Changing the milestone to Ionic Angular 4. CLI 4.0.0 will likely be released before the upcoming Framework release.

CLI 4.0.0 Milestone: https://github.com/ionic-team/ionic-cli/milestone/36
Ionic Angular 4 Milestone for CLI: https://github.com/ionic-team/ionic-cli/milestone/38

See this issue to learn how to test Ionic Angular 4 in the alpha CLI today: #3019 (warning: it's likely a bit early yet)

Contributor

dwieeb commented Mar 20, 2018

Changing the milestone to Ionic Angular 4. CLI 4.0.0 will likely be released before the upcoming Framework release.

CLI 4.0.0 Milestone: https://github.com/ionic-team/ionic-cli/milestone/36
Ionic Angular 4 Milestone for CLI: https://github.com/ionic-team/ionic-cli/milestone/38

See this issue to learn how to test Ionic Angular 4 in the alpha CLI today: #3019 (warning: it's likely a bit early yet)

@dwieeb dwieeb modified the milestones: CLI 4.0.0, Ionic Angular 4 Mar 20, 2018

@timmyomahony

This comment has been minimized.

Show comment
Hide comment
@timmyomahony

timmyomahony Jul 4, 2018

I'm really not sure why this has gotten so complicated. As an example, in Ember.js (ember-cli), there is a config/environment.js file that imports the system environment variables process.env (including custom .env environment variables imported via dotenv) at build-time and allows you to configure what variables should be exposed to your app bundle.

Basically:

// config/environment.ts
module.exports = function(environment) {
  let ENV = {
     foo: environment == 'prod' ? process.env.FOO : 'baz';
  }
  return ENV;
}

This gives you the flexibility of making use of existing system environment variables as being able to easily declare extra project-specific env variables via the .env file

In other solutions I've seen above env variables are being declared as JS modules in the source code, which isn't a great idea, and not particularly flexible.

Maybe I'm missing something with the added complexity of building via cordova as well as the web, but this seems to me to be already solved elsewhere.

EDIT: I see that this is an upcoming feature of Ionic 4 so I'm looking forward to seeing it implemented as part of core 👍

timmyomahony commented Jul 4, 2018

I'm really not sure why this has gotten so complicated. As an example, in Ember.js (ember-cli), there is a config/environment.js file that imports the system environment variables process.env (including custom .env environment variables imported via dotenv) at build-time and allows you to configure what variables should be exposed to your app bundle.

Basically:

// config/environment.ts
module.exports = function(environment) {
  let ENV = {
     foo: environment == 'prod' ? process.env.FOO : 'baz';
  }
  return ENV;
}

This gives you the flexibility of making use of existing system environment variables as being able to easily declare extra project-specific env variables via the .env file

In other solutions I've seen above env variables are being declared as JS modules in the source code, which isn't a great idea, and not particularly flexible.

Maybe I'm missing something with the added complexity of building via cordova as well as the web, but this seems to me to be already solved elsewhere.

EDIT: I see that this is an upcoming feature of Ionic 4 so I'm looking forward to seeing it implemented as part of core 👍

@HoverBaum

This comment has been minimized.

Show comment
Hide comment
@HoverBaum

HoverBaum Jul 19, 2018

Recently tried the solution proposed by @fiznool but failed. When I used the DefinePlugin inside the webpack config in my node_modules everything worked fine. But as soon as I extended the config the build broke with webpack service a 404 for all compiled resources.

This error also persisted when I simply copied the entire webpack config out of the node_modules folder.

We wanted to use the DefinPlugin to enable feature flags from the console when running ionic serve but sadly for now we are stuck with config files.

HoverBaum commented Jul 19, 2018

Recently tried the solution proposed by @fiznool but failed. When I used the DefinePlugin inside the webpack config in my node_modules everything worked fine. But as soon as I extended the config the build broke with webpack service a 404 for all compiled resources.

This error also persisted when I simply copied the entire webpack config out of the node_modules folder.

We wanted to use the DefinPlugin to enable feature flags from the console when running ionic serve but sadly for now we are stuck with config files.

@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Jul 30, 2018

Contributor

Hi all! 👋 As many of you may have seen, we announced Ionic 4 beta on our blog! 🎉

I'm closing this issue as it has been addressed with Ionic 4. If I'm mistaken, please let me know.

Here is some documentation on the Angular CLI's concept of application environments: https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/application-environments.md

Contributor

dwieeb commented Jul 30, 2018

Hi all! 👋 As many of you may have seen, we announced Ionic 4 beta on our blog! 🎉

I'm closing this issue as it has been addressed with Ionic 4. If I'm mistaken, please let me know.

Here is some documentation on the Angular CLI's concept of application environments: https://github.com/angular/angular-cli/blob/master/docs/documentation/stories/application-environments.md

@dwieeb dwieeb closed this Jul 30, 2018

@amreladawy

This comment has been minimized.

Show comment
Hide comment
@amreladawy

amreladawy Jul 31, 2018

Great! As the requestor of this feature, I am so happy it is finally resolved.

amreladawy commented Jul 31, 2018

Great! As the requestor of this feature, I am so happy it is finally resolved.

@joefeser

This comment has been minimized.

Show comment
Hide comment
@joefeser

joefeser Jul 31, 2018

joefeser commented Jul 31, 2018

@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Aug 24, 2018

Contributor

For all those still subscribed to this issue, @nphyatt has put in support for this in @ionic/app-scripts to support environments for Ionic 3!

It runs a Webpack plugin which replaces usages of process.env.VAR with string literals, using actual environment variables during the build to do so. See https://github.com/ionic-team/ionic-app-scripts#environments for docs and ionic-team/ionic-app-scripts#1471 for the PR. 🎉

Let us know what you think!

Contributor

dwieeb commented Aug 24, 2018

For all those still subscribed to this issue, @nphyatt has put in support for this in @ionic/app-scripts to support environments for Ionic 3!

It runs a Webpack plugin which replaces usages of process.env.VAR with string literals, using actual environment variables during the build to do so. See https://github.com/ionic-team/ionic-app-scripts#environments for docs and ionic-team/ionic-app-scripts#1471 for the PR. 🎉

Let us know what you think!

@granttink

This comment has been minimized.

Show comment
Hide comment
@granttink

granttink Sep 5, 2018

This is great news that this has arrived!
However:

  1. The docs link provided on the app-scripts readme.md is extremely ambiguous and not very helpful whatsoever to someone wanting to implement in their existing/new projects.
  2. Is there an example/starter project where this is being used correctly?
  3. How does one specify the environment (prod/dev/etc) to the CLI?

granttink commented Sep 5, 2018

This is great news that this has arrived!
However:

  1. The docs link provided on the app-scripts readme.md is extremely ambiguous and not very helpful whatsoever to someone wanting to implement in their existing/new projects.
  2. Is there an example/starter project where this is being used correctly?
  3. How does one specify the environment (prod/dev/etc) to the CLI?
@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Sep 5, 2018

Contributor

Could you elaborate on how the documentation is ambiguous?

I do think the documentation assumes some knowledge about: environment variables, NodeJS's process.env, dev builds vs prod builds. But I also think this is fine. I suspect people who understand the concept of environments have likely come across the aforementioned concepts as well, but maybe I'm mistaken. In any case, I will look at PRs to app-scripts for improvements. 🙂

There's no example/starter, but if someone makes one I'd be happy to link to it.

The environment is either dev (default) or prod via --prod.

Contributor

dwieeb commented Sep 5, 2018

Could you elaborate on how the documentation is ambiguous?

I do think the documentation assumes some knowledge about: environment variables, NodeJS's process.env, dev builds vs prod builds. But I also think this is fine. I suspect people who understand the concept of environments have likely come across the aforementioned concepts as well, but maybe I'm mistaken. In any case, I will look at PRs to app-scripts for improvements. 🙂

There's no example/starter, but if someone makes one I'd be happy to link to it.

The environment is either dev (default) or prod via --prod.

@granttink

This comment has been minimized.

Show comment
Hide comment
@granttink

granttink Sep 5, 2018

@dwieeb Thank you for your response.

  1. No matter whether --prod or --dev is used when running ionic serve/build the process.env.IONIC_ENV always specifies "dev" for me.
  2. The doc mentions ".env.dev" and ".env.prod" files in root of application.
    a. What is the full filename? anything.env.dev.ts? or did you mean env.dev.ts?
    b. What is the root of the application? ./src (where index.html resides) or ./ (where package.json resides)?
    c. is there an example what should the contents of these files should contain in order to alter environment variables?

Thank you in advance!

granttink commented Sep 5, 2018

@dwieeb Thank you for your response.

  1. No matter whether --prod or --dev is used when running ionic serve/build the process.env.IONIC_ENV always specifies "dev" for me.
  2. The doc mentions ".env.dev" and ".env.prod" files in root of application.
    a. What is the full filename? anything.env.dev.ts? or did you mean env.dev.ts?
    b. What is the root of the application? ./src (where index.html resides) or ./ (where package.json resides)?
    c. is there an example what should the contents of these files should contain in order to alter environment variables?

Thank you in advance!

@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Sep 5, 2018

Contributor

Thanks @granttink! Good feedback.

IONIC_ENV not being set is a bug, probably something that was overlooked. I believe both it and NODE_ENV should be set to prod/production respectively if --prod is used.

Yeah, the files are actually optional, which I think should also be stated. Also, the documentation assumes some knowledge about the format of .env files. Also, we can make it clear that this is the webpack plugin we're using.

I added an issue to revise the documentation: ionic-team/ionic-app-scripts#1474. Thank you 👍

Contributor

dwieeb commented Sep 5, 2018

Thanks @granttink! Good feedback.

IONIC_ENV not being set is a bug, probably something that was overlooked. I believe both it and NODE_ENV should be set to prod/production respectively if --prod is used.

Yeah, the files are actually optional, which I think should also be stated. Also, the documentation assumes some knowledge about the format of .env files. Also, we can make it clear that this is the webpack plugin we're using.

I added an issue to revise the documentation: ionic-team/ionic-app-scripts#1474. Thank you 👍

@granttink

This comment has been minimized.

Show comment
Hide comment
@granttink

granttink Sep 5, 2018

Thank you @dwieeb, that clarifies things quite a lot.

granttink commented Sep 5, 2018

Thank you @dwieeb, that clarifies things quite a lot.

@granttink

This comment has been minimized.

Show comment
Hide comment
@granttink

granttink Sep 12, 2018

Should this issue be closed? Considering the feature is not working correctly?

granttink commented Sep 12, 2018

Should this issue be closed? Considering the feature is not working correctly?

@granttink

This comment has been minimized.

Show comment
Hide comment
@granttink

granttink Sep 12, 2018

To clarify:

  1. --prod or --dev does not load the relevant .env.prod/.env.dev file during pack. It always loads the .env file.
  2. Custom Environment variables specified in the .env file do not get loaded into process.env
  3. IONIC_ENV variable is always dev no matter what cli commands are used.

granttink commented Sep 12, 2018

To clarify:

  1. --prod or --dev does not load the relevant .env.prod/.env.dev file during pack. It always loads the .env file.
  2. Custom Environment variables specified in the .env file do not get loaded into process.env
  3. IONIC_ENV variable is always dev no matter what cli commands are used.
@dwieeb

This comment has been minimized.

Show comment
Hide comment
@dwieeb

dwieeb Sep 12, 2018

Contributor

This issue will remain closed as it is now an available feature. There are minor issues with it, which should be tracked separately. I would prefer new issues for them. I will update this issue when they are fixed.

Contributor

dwieeb commented Sep 12, 2018

This issue will remain closed as it is now an available feature. There are minor issues with it, which should be tracked separately. I would prefer new issues for them. I will update this issue when they are fixed.

@kyleabens

This comment has been minimized.

Show comment
Hide comment
@kyleabens

kyleabens Oct 4, 2018

Any update or work around on this issue? I’m trying to build my app with the —prod flag now and it’s still not switching out the variables properly

kyleabens commented Oct 4, 2018

Any update or work around on this issue? I’m trying to build my app with the —prod flag now and it’s still not switching out the variables properly

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment