Open lucasoares opened 1 year ago
I also wanted to know if this is possible, if not already implemented.
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
.
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
ordevelopment
. 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 istest
. Anywayproduction
anddevelopment
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.
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.
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?
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.
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...
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?
Yes it can.
@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.
Exactly, but where do you keep that file (surely not in Git) and decide to activate it yes/no? That’s an important question I think.
Additionally, assuming it is common to inject env vars from the platform (as opposed to only from an .env file), you need some mechanism that allows them to have precedence. For example, ‘API_KEY’ can be defined in both the development .env ánd in the CI/CD platform. Both get injected independently, so how to create precedence?
I think this repository deals with these challenges, but I don’t know how: https://www.npmjs.com/package/dotenv
On Mon, 25 Mar 2024 at 05:42, Lasindu Weerasinghe @.***> wrote:
@pimvanderheijden https://github.com/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.
— Reply to this email directly, view it on GitHub https://github.com/java-james/flutter_dotenv/issues/90#issuecomment-2017199241, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFL2SSUPY5BPBZY5SPW57HLYZ6TMZAVCNFSM6AAAAAA2ZJCV52VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDAMJXGE4TSMRUGE . You are receiving this because you were mentioned.Message ID: @.***>
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 .env
s 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.
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 😃
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!
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.
Looks like they have spent a lot of money to get those permissions
And hence the user of flutter_dotenv
will have to spend a lot of money too?
If you use this service to build a CD pipeline, disregardless of using this library, you will have to spend money.
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 😄
No! 😕
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...
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!
@pimvanderheijden sounds cool.
@lucasoares
Guys, what CI/CD have to do with having precedent .env files, lol hahaha
Adding production .env
s while building
.env (except .env.local) files are always present on git
Not always. Only in projects where inexperienced developers make decisions.
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.
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.
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.