TL;DR: Nothing!
Angular 15 simply doesn't ship anymore environment files by default.
You can still create them and configure their replacement based on build target as it was done automatically at project creation in previous versions.
A misunderstood purpose
The origin of the confusion, arising lately about the missing of these files in new project created with ng-cli
at version 15, has its roots in the misconception that src/environments/environment.ts
and src/environments/environment.prod.ts
were some kind of sacred paths hardcoded in the deepest guts of Angular framework.
Reality is that they were just a convenience default choice, with no reference in codebase, and that could have been substituted by different paths and names with no harm to the application.
Original role
The only place in code where you could find them referenced at project creation was main.ts
, generated with something like this:
...
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
...
Their environment.production
property was used to check if the build just booted had to enable ProdMode
or not.
This function was turning off a flag (yes, the flag is indeed isDevMode
, and not isProdMode
like one could expect) actually checked in Angular codebase to toggle some "debugging" features, most evident of which is the familiar message logged in console
Angular is running in development mode.
Call enableProdMode() to enable production mode.
When the flag is true
, it means we are running a development stage of our app, so we want the framework to be more verbose in warnings and errors, and even to be a bit more "pedantic" checking situations that are not an error per-se, but that could lead to undesired and often erroneous behaviour in production.
Famous one is surely NG0100: Expression has changed after it was checked, responsible of verifying our data-binding follows a unidirectional flow, something that could bring problems during execution, but that will not throw errors on its own at runtime.
Originally Angular had no way to switch this flag other than putting the function in a file parsed at bootstrap.
Black magic of file replacement
People tended to accept the interpretation of the
correct file to load as faith, without questioning how the framework was capable of reading environment.ts
or environment.prod.ts
accordingly to the build target of choice.
The answer was nothing involving deep understanding of Angular inner mechanisms, but just the use of a nice feature offered by its builder, that while parsing configuration for chosen target, was instructed to take in account fileReplacements
array, issuing the substitution defined in its objects.
This was default config for production build some versions ago:
"configurations": {
...
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
...
Nothing was preventing us to add new replacements or change default one but, if the latter, we should have considered to modify our main.ts
to check in the right file for the environment.production
property it used to toggle production flag.
What changed in version 15
Last major release of Angular leverages a different system to toggle production flag: it lets optimization
builder option, by default passed to production
build target, set global NgDevMode
to false, without having to parse any env file.
This change took off the only reason to have any environment file in the beginning, leading devs to get rid of them completely and obviously removing default fileReplacements
occurrences in build targets configuration.
Why people are freaking out
Looking at what we read so far, it looks like this new approach is not something that should affect majority of Angular applications developers, being it more an "internal" of the framework.
Thing is that, being these files already generated at project creation and correctly managed on a build target basis, it became common practice using them to store a bunch of values that need to be switched between production and development build.
Usually these involved address of API servers to contact and Auth providers configurations.
Without finding the files where expected on newly generated projects, people who never had been interested in understanding how they ever worked didn't know where to put these data, unaware of the simplicity of manually reproducing the original setup.
Lazy solution
After the huge amount of complaints about this, Angular devs choose to "restore" on demand something similar to the old behaviour in 15.1 release.
So, from that version onwards, having environment files in place after creating a project is as simple as issuing
ng generate environments
that as explained in docs will create them and configure build
and server
targets to use them.
In short: it will create src/environments/environment.ts
and src/environments/environment.development.ts
adding the latter as replacement of the former for build configuration's development
target
"development": {
...
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.development.ts"
}
]
Why they didn't think of that before
The habit of putting environment variables inside those files is less straightforward than it could seem.
Even if their name and their use could lead to look at them as the ideal spot for such information, in real case scenario they're far from best solution.
Data like domains, endpoints, ports and alike are not bound only to building target, but often more tightly to deployment context.
That's why many people prefer to keep them outside of building process, and let the app evaluating them at runtime as token injected at deploying, maybe as environment variable of the hosting framework or docker bundling, read by a minimal server side process and exposed as API, or even passing them in dedicated configuration file inserted as assets by pipeline, as explained in this awesome article from good ol' @frederikprijck.
Now it should be clear there's been no change in environment variables management by Angular, just an upgrade that made an old easy convenient configuration not needed anymore, leading to reconsider what had always been an habit that often was a suboptimal solution, but that's available as it always has been.
Cheers.
Top comments (14)
Angular needs to get rid of this and add
.env
support out of the box IMHO. Globals are something else.Hi jonathan.
How would you like dotenv to be integrated natively in Angular?
Good question. I'm not sure, but it is in all other frameworks. It works with the Webpack version of Angular, but that is overkill just for env variables. At the very least, it should work natively with Universal.
I got no experience with dotenv or Universal, so maybe I'm missing something basic:
what issue do you face if you try to prepone a script loading the .env, inside build script of your package manager?
It doesn't work. Here is just one article on how to hack it - indepth.dev/tutorials/angular/inje...
Right.
Now I get it.
That really old ticket linked in the article suggests a lot of solutions, but looks like none of them has still been accepted and integrated into cli.
Nice article! Thanks for the mention! β₯οΈ
Thanks to you.
Your post has been really useful.
Really a good articleπ! One stop solution for all the information one might need about the topic.
Thanks.
I'm glad it's been helpful for you.
It's strange how a "highly-opinionated" framework like Angular will suddenly punt on its "highly-opinionated" solution. Their solution provided convenience (as does their whole product). Why use their framework, if not for convenience? God knows it's hard enough to use as it is.
Hi ptletski.
Not sure I get where's the ambiguity.
The choice of environment files in the beginning was forced by circumstances.
Once those were gone, they dropped default use of the files.
In this case, the whole setup was not due to opinion, but to necessity.
why does angular put us in the trouble of replacing environments when they were so easy to use? What a desire to annoy the user!
How do I know, in the application, what build mode I am in?
Hi Julio.
None has been obliged to use a different system.
As explained in the article, old environment files replacement per-build works as usual, and since 15.2 they can be even generated on demand with a schematic.
The reason for them not being default anymore is the point of the whole article. :-)
About the last question, I'm not sure if I get it: why should you care about the build mode you're in?