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

Accept loading multiple files with precedence #90

Open
lucasoares opened this issue Jul 26, 2023 · 25 comments
Open

Accept loading multiple files with precedence #90

lucasoares opened this issue Jul 26, 2023 · 25 comments

Comments

@lucasoares
Copy link

Hello.

I would like this library to accept multiple files.

Use case scenario: to have both .env.local and .env files, where my .env can be committed to the source control (usually constants, etc) but with a .env.local where I can have these constants changed only locally and ignored by git. This will let developers change the environment without changing the main file.

@lucasoares lucasoares changed the title Accept loading multiple files Accept loading multiple files with precedence Jul 26, 2023
@BernardinD
Copy link

I also wanted to know if this is possible, if not already implemented.

@LassazVegaz
Copy link

I upvote this feature request. In total, I expect the following files,

.env                # loaded in all cases
.env.local          # loaded in all cases, usually ignored by git
.env.[mode]         # only loaded in specified mode
.env.[mode].local   # only loaded in the specified mode, usually ignored by git

mode is production or development.
An env file for a specific mode (e.g. .env.production) will take higher priority than a generic one (e.g. .env)

This behavior is beautifully explained in the Vite build tool and I copied most of this from there.

Vite also includes test as one of the modes but I am not sure if the dart code can detect if the current running mode is test. Anyway production and development and their locals would be enough for now.

For this feature implementation, most of the existing functions can be used. The only extra code needed is to check if these files exist and merge them in the relevant order depending on the current mode. By checking if the file exists, I mean checking if the files are included in the project through pubspec.yaml.

@lucasoares
Copy link
Author

I upvote this feature request. In total, I expect the following files,

.env                # loaded in all cases
.env.local          # loaded in all cases, usually ignored by git
.env.[mode]         # only loaded in specified mode
.env.[mode].local   # only loaded in the specified mode, usually ignored by git

mode is production or development. An env file for a specific mode (e.g. .env.production) will take higher priority than a generic one (e.g. .env)

This behavior is beautifully explained in the Vite build tool and I copied most of this from there.

Vite also includes test as one of the modes but I am not sure if the dart code can detect if the current running mode is test. Anyway production and development and their locals would be enough for now.

For this feature implementation, most of the existing functions can be used. The only extra code needed is to check if these files exist and merge them in the relevant order depending on the current mode. By checking if the file exists, I mean checking if the files are included in the project through pubspec.yaml.

Why not let users manually set the files they want to load in the order they want to load it? Simple and effective.

@LassazVegaz
Copy link

Why not let users manually set the files they want to load in the order they want to load it? Simple and effective.

But this is the usual way. I am saying, merge these files only if they exist. Most of the times these are the requirements. If those files don't exist, they won't be merged. Assume, a developer has most of these files. It won't be simple for that developer to merge those .ENVs by checking the current mode. That is why most of the build tools (Vite, CRA, Nest etc.) support this behavior out of the box. The explained feature wouldn't break any existing code and it will make development much easier when there is a lot of configuration. Anyway, I am planning to fork and develop the feature I mentioned.

@pimvanderheijden
Copy link

I agree with @lucasoares that this is standard. One question though, how and where does .env.production or production.env get created? And how do these variables (and thus not the .env file) get baked into the code that gets shipped to the user's device?

@LassazVegaz
Copy link

LassazVegaz commented Mar 19, 2024

One question though, how and where does .env.production or production.env get created?

created by the developer

how do these variables (and thus not the .env file) get baked into the code that gets shipped to the user's device?

That depends on the platform you are building for. Flutter decides how the files mentioned in pubspec.yml are embedded into the application.

@pimvanderheijden
Copy link

pimvanderheijden commented Mar 21, 2024

created by the developer

Not necessarily, think CI/CD

That depends....

Think CI/CD

In other words, the production.env or .env.production file is not checked in. It may be created during some kind of CI/CD job in Gitlab in Github or whatever. However, on these CI/CD platforms it is common to inject env vars directly, for example from the repository settings. In that case, there is no production file...

And thus I'm starting to wonder if one ever would create / generate a production env file...

@LassazVegaz
Copy link

And thus I'm starting to wonder if one ever would create / generate a production env file...

When doing local development, the developer has to. Plus, can you confirm if the Flutter apps built process can be automated?

@pimvanderheijden
Copy link

Yes it can.

https://docs.flutter.dev/deployment/cd

@LassazVegaz
Copy link

@pimvanderheijden Oh wow didn't see that!

However, on these CI/CD platforms it is common to inject env vars directly, for example from the repository settings. In that case, there is no production file...

And thus I'm starting to wonder if one ever would create / generate a production env file...

You said, "it is common to". So you know in some cases, developers put the .env file instead of the commands because it is easy to manage env vars that way. When env vars change, just replace the file instead of changing commands. To do that the developer needs to keep a production level .env somewhere.

@pimvanderheijden
Copy link

pimvanderheijden commented Mar 26, 2024 via email

@LassazVegaz
Copy link

Exactly, but where do you keep that file (surely not in Git) and decide to
activate it yes/no?

It can be kept locally in the repository. Even the production .env files need to be Git ignored.

so how to create precedence?

In Flutter, you can check if the current environment is development or production. According to that, the library can give priority to the specific .env file types.

I think this repository deals with these challenges, but I don’t know how:

The package you mentioned does that. It is the goto package for .envs in NodeJS. And this Flutter package can do the same. It replaces the values of existing keys from the next .env file. The source code is very simple, have a look.

@pimvanderheijden
Copy link

pimvanderheijden commented Mar 29, 2024

It can be kept locally in the repository. Even the production .env files need to be Git ignored.

I get that you can use production .env files when deploying from a local machine. However, the consequence of CI/CD is that local files (not checked in with Git) are irrelevant. I really don't know yet if I'm going to do CI/CD for my app anytime soon so won't really be able to tell you more. I do expect it's going to be a lot different than "just" an .env file.

In Flutter, you can check if the current environment is development or production.

So, load production .env file depending on kDebugMode and/or kReleaseMode booleans? Sounds great to me 😃

@LassazVegaz
Copy link

Good luck with that. But I still don't understand how a pipeline can build and publish Android and iOS apps to relevant stores. Sounds very impossible with all the restrictions they have. Specially Apple ones.

So, load production .env file depending on kDebugMode and/or kReleaseMode booleans?

Oh yeah!

@pimvanderheijden
Copy link

There is CI/CD for iOS with the help of fastlane: https://docs.fastlane.tools
I don't know how it works for production releases but I'm sure it will be relevant at some point.

@LassazVegaz
Copy link

Looks like they have spent a lot of money to get those permissions

@pimvanderheijden
Copy link

And hence the user of flutter_dotenv will have to spend a lot of money too?

@LassazVegaz
Copy link

If you use this service to build a CD pipeline, disregardless of using this library, you will have to spend money.

@pimvanderheijden
Copy link

Hahah yes, clear. But I get a sense you're suggesting it's not worth the effort for fluttter_dotenv to create support for CI/CD 😄

@LassazVegaz
Copy link

No! 😕

@pimvanderheijden
Copy link

I found another part of the docs describing CI/CD for Flutter: https://docs.flutter.dev/deployment/ios#create-a-build-archive-with-codemagic-cli-tools

Doesn't sound like it's paid...

@lucasoares
Copy link
Author

lucasoares commented Apr 12, 2024

Guys, what CI/CD have to do with having precedent .env files, lol hahaha

.env (except .env.local) files are always present on git, there is no "CI/CD generating it". It should be used to toggle between public variables in the resulting build.

But it can be simplified if this library lets users load multiple .env files as they want:

await dotenv.load(".env", ".env.prod", ".env.local");

How the .env file will be shipped with the application, the priority of the loading, and anything go to the dev to decide.

What I need and what is the main point of this issue are documented here: https://vitejs.dev/guide/env-and-mode.html#env-files

Anything else doesn't belong to this issue. Discuss it elsewhere, not in here! Thanks!

@LassazVegaz
Copy link

@pimvanderheijden sounds cool.

@lucasoares

Guys, what CI/CD have to do with having precedent .env files, lol hahaha

Adding production .envs while building

.env (except .env.local) files are always present on git

Not always. Only in projects where inexperienced developers make decisions.

@roman910dev
Copy link

roman910dev commented Jul 28, 2024

Future<void> loadEnvs(List<String> envs, {Map<String, String> merge = const {}}) async {
  if (envs.isEmpty) return;
  if (envs.length == 1) return dotenv.load(fileName: envs[0], mergeWith: merge);
  final de = DotEnv();
  await de.load(fileName: envs[0], mergeWith: merge);
  await _loadEnvs(envs.skip(1).toList(), merge: de.env);
}

This loads any number of dotenv files serially. The firstmost have priority, later dotenvs do not override them. After the function ends, all are loaded in the dotenv variable.

@Ahmed-gubara
Copy link

Future<void> loadEnv() async {
  const isProduction = 'production' == String.fromEnvironment('ENVIRONMENT');

  // priority: environment > .env
  if (isProduction) {
    await dotenv.load(fileName: '.env', mergeWith: Platform.environment);
  }

  // priority: environment > .env.local > .env
  await dotenv.load(fileName: '.env.local', mergeWith: Platform.environment);
  await dotenv.load(fileName: '.env', mergeWith: {...dotenv.env});
}

In production builds, .env.local is ignored.
Just pass it as a dart define, for example: flutter build apk --dart-define=ENVIRONMENT=production


{...dotenv.env} must be used to copy the map; because dotenv.load() will clear the its internal .env map, and values will be lost of not copied.

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

No branches or pull requests

6 participants