Skip to content

Request: Method to pass environment variables during build vs file. #4318

Closed

Description

@DennisSmolek

OS?

Any, mostly a build/CI question

Versions.

1.0.0-beta.26

Reasoning

I really like the environment variables setup with the CLI and we have switched to using them. One problem though is we no longer have access to server set ENV variables which is how we pass information to certain things during deployment. Consider:

Bugsnag.releaseStage = environment.releaseStage;
// can't access process.env anymore with the CLI
  const commit = process.env.CI_COMMIT_ID;
  if (commit) Bugsnag.metaData = {
        commits: {
          id: commit
        }
      };

Codeship ENV variables

Being able to add the release stage, branch, and commit ID allows us to segment and track bugs/issues very accurately.
My problem is I know the build takes whatever stage I pass and replaces the environment.ts file so I can't just edit the file with a bash script (well, if I know EXACTLY the build before hand I could) but it would be nice to be able to pass env variables in the build line.

Consider: ng build --prod could be: ng build --prod --envVar:commitId: CI_COMMIT_ID

which would append the variable after the file gets merged

export const environment =  {
    production: true, 
    commitId: 'ca82a6dff817ec66f44342007202690a93763949'
}

something like this would ensure it gets added to the right file and at the right time/place..

Then we could do:

  const commit = environment.commidId;
  if (commit) Bugsnag.metaData = {
        commits: {
          id: commit
        }
      };

Activity

  1. Brocco commented on Feb 1, 2017

    @Brocco
    Contributor

    @hansl we were just discussing this, thought you might have something to add

  2. yuzhva commented on Feb 8, 2017

    @yuzhva

    Why not make ENV variables available in process.env again?

    I'm really feeling comfortable with Heroku Config Vars and Codeship environment variables, I already set up them, moved all my sensitive data like secret keys to angular-cli environment.dev.ts, BUT I can't use them.(

    export const environment = {
      production: false,
      GOOGLE_RECAPTCHA_SITE_KEY: '6Le...Zq'
    };

    Because there is no way to access variables from test env or production like:

    export const environment = {
      production: false,
      GOOGLE_RECAPTCHA_SITE_KEY: process.env.GOOGLE_RECAPTCHA_SITE_KEY
    };

    in my environment.test.ts and environment.prod.ts

    Need to thinking on using third party packages like dotenv or env2

    P.S: Is it hard to implement configuration like this:

    ...
    "scripts": [],
    "environments": {
            "source": "environments/environment.ts",
            "dev": "environments/environment.dev.ts",
            "test": "environments/environment.test.ts",
            "prod": "environments/environment.prod.ts"
          },
    "processEnv": [
             "CUSTOM_ENV_VAR",
             "GOOGLE_RECAPTCHA_SITE_KEY",
             ...
    ]

    So then there will be opportunity access them from process.env.CUSTOM_ENV_VAR, etc.

  3. k10der commented on Apr 13, 2017

    @k10der

    I ran into the same issue a day ago. And for a temporary workaround, that works (just checked it with Codeship), I just added the "prebuild" script, that generates the appropriate environment file using current env variables. ejs is used as a template processor due to it's simplicity.

    scripts/prebuild.js - this is a script with the required logic

    #!/usr/bin/env node
    
    const fs = require('fs');
    const path = require('path');
    
    const ejs = require('ejs');
    
    const environmentFilesDirectory = path.join(__dirname, '../src/environments');
    const targetEnvironmentTemplateFileName = 'environment.prod.ts.template';
    const targetEnvironmentFileName = 'environment.prod.ts';
    
    // Define default values in case there are no defined ones,
    // but you should define only non-crucial values here,
    // because build should fail if you don't provide the correct values
    // for your production environment
    const defaultEnvValues = {
      PREFIX_STORAGE_TYPE: 'localStorage',
      PREFIX_USER_TOKEN_FIELD_NAME: 'userToken',
    };
    
    // Load template file
    const environmentTemplate = fs.readFileSync(
      path.join(environmentFilesDirectory, targetEnvironmentTemplateFileName),
      {encoding: 'utf-8'}
    );
    
    // Generate output data
    const output = ejs.render(environmentTemplate, Object.assign({}, defaultEnvValues, process.env));
    // Write environment file
    fs.writeFileSync(path.join(environmentFilesDirectory, targetEnvironmentFileName), output);
    
    process.exit(0);

    src/environments/environment.prod.ts.template - this is a template file, that generates the required environment file. Notice, that PREFIX_BACKEND_URL isn't provided in scripts/prebuild.js script in defaultEnvValues, because in production it should be defined only by build environment variables.

    export const environment = {
      production: true,
      backendUrl: '<%= PREFIX_BACKEND_URL %>',
      storageType: '<%= PREFIX_STORAGE_TYPE %>',
      userTokenFieldName: '<%= PREFIX_USER_TOKEN_FIELD_NAME %>'
    };

    package.json - there are some changes here. In scripts/prebuild.js shebang (#!) style is used, so "prebuild" is just a pointer to the script file. And to make it work it must be marked as executable, that's why "postinstall" script is added either.

    {
      ...
      "scripts": {
        ...
        "build": "ng build --prod --aot",
        "prebuild": "./scripts/prebuild.js",
        ...
        "postinstall": "chmod +x ./scripts/*.js"
      },
      ...
      "devDependencies": {
        ...
        "ejs": "^2.5.6",
        ...
      }
    }
    
  4. DennisSmolek commented on Apr 14, 2017

    @DennisSmolek
    Author

    @k10der this is great, this is similar to what we did. What we do is actually move the environment scripting out of angular totally. We have a single environment.ts file for all builds and use a custom script to generate the correct values via the env variables.

    I still think this should be something within the CLI but there are of course workarounds.

  5. k10der commented on Apr 14, 2017

    @k10der

    @DennisSmolek, I also think, that handling of process.env variables should be built-in in cli. And your approach to use a single environment file, that is generated by external tool makes sense: my dev environment variables are currently stored in the project repository, which is OK unless I'll start using some 3rd party APIs with private keys. So I guess one-environment-file approach should be used in future angular-cli versions.

  6. AmirSasson commented on Apr 20, 2017

    @AmirSasson

    Injecting environment variables during build seems essential. Any ETA for supporting this in the ng cli?

  7. davidwalter0 commented on May 12, 2017

    @davidwalter0

    Why would common cross platform method for OS configuration support of env variables be excluded?

    Unless there's a strong argument against 12factor that is being proposed for angular?

  8. zpydee commented on May 13, 2017

    @zpydee

    I'd also really like to be able to use process.env variables. I'm deploying to docker swarms and the capability to be able to include variables in a compose file is important to my application.

  9. avatsaev commented on May 15, 2017

    @avatsaev

    very needed for dockerizing the apps indeed

  10. carlosthe19916 commented on May 20, 2017

    @carlosthe19916

    @k10der Do you have any repository on github that is using the solution you proposed? I'd like to check it because I could not find any real solution on the internet.

  11. k10der commented on May 20, 2017

    @k10der

    Hey, @carlosthe19916. I have a sample project, that I use just for practicing in Angular2+. It's not a production ready and you probably won't get any benefit from running it, but I use the proposed solution there. And it's exactly as I described it in this topic.

  12. 127 remaining items

  13. RicardoJBarrios commented on Apr 20, 2023

    @RicardoJBarrios

    Another way to do this is, as mentioned before, requesting the data from a file (maybe created by the HELM that deploy the node) or a property server. For this I created kuoki, with the Environment and the Environment Angular libraries.

    There are many options, but I use to run away from variable injection in code because of race condition problems in the properties load or the dependency from objects like Window, that's an open door to attacks.

  14. motdotla commented on Aug 3, 2023

    @motdotla

    As a new user of Angular I was really surprised environment variables weren't supported. Every other major front-end framework I've so far used has supported them.

    After trying three or four of the recommended approaches here (spent half a day on them all), I personally settled on @chihab's ngx-env builder. It's a safe approach and works with minimal fuss (encouraging separation of secrets from code).

    #4318 (comment)

    Here's the result: https://www.dotenv.org/docs/frameworks/angular/vercel

  15. griest024 commented on May 30, 2024

    @griest024

    vite supports .env files and import.meta env vars out of the box. Why use it in @angular-devkit/build-angular:application and disable this functionality?

  16. muuvmuuv commented on Jul 12, 2024

    @muuvmuuv

    Another idea is opening esbuild-plugins to allow us create plugins like "define" ourselfs. Here an example using @angular-builders/custom-esbuild. It is much more flexible instead of just only dotenv support.

    import { getVersion } from './utils.mjs'
    
    /** @type {import('esbuild').Plugin} */
    export default {
    	name: 'plugin-define',
    	setup: async (build) => {
    		const initialOptions = build.initialOptions
    		initialOptions.define ??= {}
    		initialOptions.define.APP_VERSION = JSON.stringify("x.x.x")
    	},
    }
  17. alan-agius4 commented on Sep 9, 2024

    @alan-agius4
    Collaborator

    Closed via #28362, which will be included in version 19, currently in prerelease.

  18. Lindsor commented on Sep 9, 2024

    @Lindsor

    This is definately a step in the right direction but its still not using environment variables in the bundle so the initial request is not really fulfilled.
    We've just added another cli arg to inject but if i have a .env file or exported variables they still wont be picked up.
    They still need to be buildtime injected into the cli build command which is almost the same as generating an environment.ts file at build time

  19. michaeljota commented on Sep 15, 2024

    @michaeljota

    I think this is a good step forward, but in the end, environment variables and files have been a de facto standard. If with this issue here you don't want to expose the underlying tooling, for example, Webpack in its time, and now Vite, why don't exposing them in your own way? One that doesn't need knowledge about the tooling.

    But the important part here is to be able to load a variable from the environment, and this is not loading from the environment.

    If you want to use a certain prefix to sanitize variables, that's ok, it's also de facto standard, and most tooling does that to prevent exposing variables not related to the app. And if you want to do it a standard future-proof way, using import.meta seems pretty standard and future-proof.

    Again, this is a great start, but I don't feel like this is really fixing the issue here.

  20. griest024 commented on Sep 15, 2024

    @griest024

    I completely agree with @michaeljota. I will not be able to replace my usage of dotenv with the feature that closed this issue. @alan-agius4 Please either reopen or advise us to open a new issue.

  21. muuvmuuv commented on Oct 2, 2024

    @muuvmuuv

    Me neither, and no dev-server support

  22. selangley-wa commented on Oct 17, 2024

    @selangley-wa

    I created a new issue that at least captures my unmet use case:

    Ability to set environment/configuration values at runtime instead of buildtime angular/angular#58433
    angular/angular#58433

  23. removed their assignment
    on Oct 17, 2024
  24. Lindsor commented on Oct 17, 2024

    @Lindsor

    Reopened this ticket as: #28661

  25. angular-automatic-lock-bot commented on Nov 30, 2024

    @angular-automatic-lock-bot

    This issue has been automatically locked due to inactivity.
    Please file a new issue if you are encountering a similar or related problem.

    Read more about our automatic conversation locking policy.

    This action has been performed automatically by a bot.

  26. locked and limited conversation to collaborators on Nov 30, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: @angular-devkit/build-angularfeatureLabel used to distinguish feature request from other issuesfeature: under considerationFeature request for which voting has completed and the request is now under consideration

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions