chihab / dotenv-run

Seamlessly load environment variables. Supports cli, esbuild, rollup, vite, webpack, angular. ESM and Monorepos.
238 stars 17 forks source link

Replace .env file after build #90

Closed ScorprocS closed 5 months ago

ScorprocS commented 6 months ago

Hello I didn't know where to ask the question so sorry for creating an issue for that. I would like to replace the .env file on runtime to be able to use the same build for all environments (AAT, PROD) but I don't know how to do it. And I didn't found anything in doc about that.

I'm using DotenvRunPlugin and the angular build is directly deployed in /html folder of nginx.

Here's my actual configuration. Angular.json

 "architect": {
        "build": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "./webpack.config.js"
            },

./webpack.config.js

var BrotliPlugin = require('brotli-webpack-plugin');
//const { AngularCompilerPlugin } = require('@ngtools/webpack');
const CompressionPlugin = require('compression-webpack-plugin');
const path = require(`path`);
const { DotenvRunPlugin } =  require("@dotenv-run/webpack");

module.exports = {
    plugins: [
        new BrotliPlugin({
           // ...
        }),
          new CompressionPlugin({
     // ...
    }),
    new DotenvRunPlugin({ 
      prefix: /^APP|NG/, 
      verbose: true, 
      root: "../../src/" ,
      files: ['.env'],
      dotenv: { override: true },
    }),

    ]
}

Thanks in advance for your help

chihab commented 6 months ago

Hello, You cannot achieve what you want. The plugin replaces process.env / import.meta.env notations in your code source with the values in your environment (including those read from you .env) at build time. Let's say you put import.meta.env.API_URL in your code, when you build your app using the plugin, it is replaced by the value in process.env.API_URL let's say localhost:3000, so in your JS chunk there will only be localhost:3000 If you want different values (different environment), you'd have to build the app with that specific environment.

ScorprocS commented 6 months ago

Hello, You cannot achieve what you want. The plugin replaces process.env / import.meta.env notations in your code source with the values in your environment (including those read from you .env) at build time. Let's say you put import.meta.env.API_URL in your code, when you build your app using the plugin, it is replaced by the value in process.env.API_URL let's say localhost:3000, so in your JS chunk there will only be localhost:3000 If you want different values (different environment), you'd have to build the app with that specific environment.

Hello thanks for your reply. ok. But it must be possible for instance I could put the .env file in asset folder or create an env.js file with all constants and replace them when I want to change the environment. But I would like to do it properly and safely. For instance I've found thoses solutions:

Are you sure that I cannot achieve that with the dotenv-run library (which I found awsome and really easy to use) ? I didn't want to do something boilerplate.

chihab commented 5 months ago

I get your point. The current implementation does not permit it for sure. But that could be nice feature indeed. What would be the best developer experience in your opinion?

ScorprocS commented 5 months ago

Thanks. I think the best would be able to use only a .env file which will be injected at build time for default and common values (as it is now) and give a way to override those variables at run time by replacing the .env.runtime file (or custom named file) in the assets folder. And add a provider to replace the overrided env variable. On your side the implementation could be done on angular startup:

 providers: [
    {
      provide: APP_INITIALIZER,
      useFactory: initConfig,
      deps: [AppConfigService],
      multi: true,
    },
  ],

In the configService you could fetch all env vars defined in .env.runtime to replace them. could be done like : const result = dotenv.config({ debug: true,override: true, path: 'custom/path/to/.env' }); I don't know if this approach could be compatible with other framework. In any case thanks a lot for your concern.

chihab commented 5 months ago

I've published a new version of the package in alpha supporting runtime environment variables.

I'd appreciate if you can give it a try.

npx ng add @ngx-env/builder

Set the runtime option to true in angular.json

 "scripts": [],
 "ngxEnv": {
     "runtime": true
  },

Usual way to use environment variables in code

title = import.meta.env.NG_APP_VERSION;
NG_APP_VERSION=10.0.0 npm run build

The application can be served from the dist/\<app-name> folder.

Inside the dist/\<app-name> folder, a new ngx-env.js file is generated:

globalThis._NGX_ENV_ = {
  NG_APP_VERSION: "10.0.0",
};

You can modify it and reload the window.

If you're using SSR, add import '@ngx-env/builder/runtime'; to the top of the main.server.ts file.

chihab commented 5 months ago

Added experimental runtime support in 17.3.0.