This short article is about replacing files (e.g. configuration files) for different build configurations/targets (like dev
, qa
and prod
) in Angular. For our projects we used to leverage the Angular file replacements feature to provide different files based on the chosen build target:
{
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
},
{
"replace": "src/configurations/configuration.json",
"with": "src/configurations/configuration.prod.json"
}
]
},
"dev": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
},
{
"replace": "src/configurations/configuration.json",
"with": "src/configurations/configuration.dev.json"
}
]
},
"qa": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.qa.ts"
},
{
"replace": "src/configurations/configuration.json",
"with": "src/configurations/configuration.qa.json"
}
]
}
}
However, file replacements outside of bundles were never officially supported by Angular and has ceased to work since the Angular 9 release as described here.
We have migrated to the proposed workaround in the linked Github issue and it is working fine for us so far. In case someone has the same issue/question (and also to document the approach for myself ;) ), I have created a simple example repository showcasing the approach for a single configuration.json
file.
The following section shows the required steps.
Configuration Folder
In the example, a dedicated folder holding the different configurations has been created. This is not necessarily required but keeps the files organized. Next, each configuration target has an associated folder containing the configuration.json
. The additional folder is indeed required as otherwise it is not possible to select and copy the correct file (described in the next section).
At the end it looks something like the following:
Angular CLI configuration file (angular.json)
As shown in the snippet below, for each of the deployment configurations the associated configuration.json
is copied as part of the assets
section:
{
"production": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"input": "src/configurations/prod",
"output": "configuration/",
"glob": "*.json"
},
{
"input": "src/configurations",
"output": "configuration/",
"glob": "README.md"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
]
},
"dev": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"input": "src/configurations/dev",
"output": "configuration/",
"glob": "*.json"
},
{
"input": "src/configurations",
"output": "configuration/",
"glob": "README.md"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.dev.ts"
}
]
},
"qa": {
"assets": [
"src/favicon.ico",
"src/assets",
{
"input": "src/configurations/qa",
"output": "configuration/",
"glob": "*.json"
},
{
"input": "src/configurations",
"output": "configuration/",
"glob": "README.md"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.qa.ts"
}
]
}
}
By means of the created subfolders in the configuration folder, the correct configuration.json
file can be selected and copied. With help of the output
property the path within the dist
folder is defined. For the example, it is copied to a configuration folder in the root path. In addition a README.md
is put next to the configuration.json
to describe its properties and their effect on the application. Creating the dedicated folder helps to keep the two files next to each other.
What I don't like about the approach is, that we now have to duplicate the assets
properties for all build configurations as otherwise e.g. the assets
folder (images, fonts, translations and the like) does not get copied. Also, having to create a dedicated subfolder is also not as convenient as it was with the file replacement (although this is more a nuisance than a major drawback).
In case you have a better idea (or a solution) for solving the duplication, I'd love to hear about it. Otherwise I hope it can be beneficial for someone.
Top comments (2)
Do you think this will work for ng e2e? Apparently, I could not find any solution for replacing files when executing e2e tests.
Have not tested/used it for the e2e target to be honest (e2e is done with Selenium in the project the approach is in use).
So do I get you right that the file is not copied/replaced at all for the e2e target?
If that is the case the approach will unfortunately not work as it relies on the
configuration.json
being copied to the destination.