Skip to content
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 · 121 comments
Closed

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

jgw96 opened this issue Jul 25, 2016 · 121 comments
Assignees

Comments

@jgw96
Copy link
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-framework#7413

@itrethan
Copy link

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
Copy link

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

@ghost
Copy link

ghost commented Oct 26, 2016

Is there any plans to actually implement this?

@tabirkeland
Copy link

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'})

@tomasstankovic
Copy link

tomasstankovic 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
Copy link

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
Copy link

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

@ghost
Copy link

ghost 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)

@tomasstankovic
Copy link

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/

@ghost
Copy link

ghost 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
Copy link

allaanz commented Nov 14, 2016

+1

@jthoms1 jthoms1 self-assigned this Nov 15, 2016
@zjhiphop
Copy link

Hey, guys, any progress of official implements?

@rolandjitsu
Copy link

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

@Yimiprod
Copy link

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
Copy link

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
Copy link

Definitely a must. So +1

@iacomus
Copy link

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
Copy link

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
Copy link

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

@fiznool
Copy link

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
Copy link

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.

@zaarheed
Copy link

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

@iamjoyce
Copy link

@zuperm4n Use the thumbs up emoji on the first post

@GFoley83
Copy link

@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
Copy link

+1 for this feature request

@GFoley83
Copy link

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
Copy link

wilfredonoyola commented Feb 27, 2018

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

Thanks!

@TivonChen
Copy link

@wilfredonoyola I use this too, thanks!

@tabirkeland
Copy link

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

@imhoffd
Copy link
Contributor

imhoffd 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)

@imhoffd imhoffd modified the milestones: CLI 4.0.0, Ionic Angular 4 Mar 20, 2018
@timmyomahony
Copy link

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
Copy link

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.

@imhoffd
Copy link
Contributor

imhoffd 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

@imhoffd imhoffd closed this as completed Jul 30, 2018
@amreladawy
Copy link

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

@joefeser
Copy link

joefeser commented Jul 31, 2018 via email

@imhoffd
Copy link
Contributor

imhoffd 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
Copy link

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?

@imhoffd
Copy link
Contributor

imhoffd 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
Copy link

@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!

@imhoffd
Copy link
Contributor

imhoffd 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
Copy link

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

@granttink
Copy link

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

@granttink
Copy link

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.

@imhoffd
Copy link
Contributor

imhoffd 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
Copy link

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

@md-hamed
Copy link

For anyone who is still stuck on this; I simply needed to have different configurations for different environments. Check the following gist for my implementation: https://gist.github.com/md-hamed/9212a32b37e72b1f8fd51136b1e1dfdc

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

No branches or pull requests