x)
no
With https://github.com/angular/angular-cli/pull/15819# the CLI allows to define multiple configurations that get overlayed. However the merge process of the configs only does a shallow merge, which e.g. for fileReplacements means that all replacements in a previous config get overriden.
I suggest to do a deep merge on the configurations, not a shallow merge.
Example:
with this angular.json:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"proto-sites-next-app": {
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/proto-sites-next-app",
"index": "src/index.html",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"main": "src/main.ts",
"aot": true,
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/bootstrap/dist/css/bootstrap.css",
"./node_modules/sample-sites-next/data/assets/lightTheme/main.css",
"src/styles.scss"
],
"scripts": []
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
},
"edit": {
"outputPath": "dist/proto-sites-next-app-edit",
"fileReplacements": [
{
"replace": "src/app/app.bootstrap.module.ts",
"with": "src/app/app.bootstrap.edit.module.ts"
}
]
},
"view": {
"outputPath": "dist/proto-sites-next-app-view",
"fileReplacements": [
{
"replace": "src/app/app.bootstrap.module.ts",
"with": "src/app/app.bootstrap.view.module.ts"
}
]
}
}
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "proto-sites-next-app:build"
},
"configurations": {
"production": {
"browserTarget": "proto-sites-next-app:build:production"
},
"edit": {
"browserTarget": "proto-sites-next-app:build:edit-mode"
},
"view": {
"browserTarget": "proto-sites-next-app:build:view-mode"
}
}
},
"extract-i18n": {
"builder": "@angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "proto-sites-next-app:build"
}
},
"test": {
"builder": "@angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "proto-sites-next-app:serve"
},
"configurations": {
"production": {
"devServerTarget": "proto-sites-next-app:serve:production"
}
}
}
}
}},
"defaultProject": "proto-sites-next-app"
}
I specify two new configs edit and view. These configs are logically orthogonal to production vs normal mode, so I would like to be able to build the application e.g. like this:
ng build --configuration=edit
and
ng build --configuration=production,edit
However the later does not work as expected because the file replacements for the environment as defined in the production config are overridden.
Angular CLI: 9.0.0-rc.9
Node: 10.17.0
OS: win32 x64
Angular: 9.0.0-rc.9
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.900.0-rc.9
@angular-devkit/build-angular 0.900.0-rc.9
@angular-devkit/build-optimizer 0.900.0-rc.9
@angular-devkit/build-webpack 0.900.0-rc.9
@angular-devkit/core 9.0.0-rc.9
@angular-devkit/schematics 9.0.0-rc.9
@ngtools/webpack 9.0.0-rc.9
@schematics/angular 9.0.0-rc.9
@schematics/update 0.900.0-rc.9
rxjs 6.5.4
typescript 3.6.4
webpack 4.41.2
Anything else relevant?
It is indeed intentional that multiple configurations are not deeply merged. We opted for that approach for now because deep merging doesn't allow for wholly replacing objects easily, while shallow merging does.
So while there is repetition, the mental model is straightforward and isn't missing capabilities. We might provide more merge strategies in the future, but it just didn't make a lot of sense to start with the least flexible one.
@filipesilva thanks. How would you suggest to address the usecase I am depicting? Would I have to create the permutations "production-edit", "production-view", "normal-edit", "normal-view" to capture the correct replacements?
There's no great way of doing it that doesn't involve repetition at the moment. So something like that would be the best approach currently.
I'd love a feature where I'd be able to merge the fileReplacements-Array for example. If I have to copy/paste the build config permutations, the angular.json file gets quite big for me...
Best approach for me would be to merge the fileReplacements-Arrays together, like:
config a:
"fileReplacements": [
{
"replace": "a",
"with": "x"
},
{
"replace": "c",
"with": "z_A"
}
]
config b:
"fileReplacements": [
{
"replace": "b",
"with": "y"
},
{
"replace": "c",
"with": "z_B"
}
]
So when ng build --configuration a,b is run it uses:
configs merged:
"fileReplacements": [
{
"replace": "a",
"with": "x"
},
{
"replace": "b",
"with": "y"
},
{
"replace": "c",
"with": "z_B"
}
]
Instead of only using fileReplacements for config b:
"fileReplacements": [
{
"replace": "b",
"with": "y"
},
{
"replace": "c",
"with": "z_B"
}
]
I am also interested in having a way to extend configurations (fileReplacements) instead of overriding it. will save us a lot of repetition in Angular.js file.
Hi,
"You can also pass in more than one configuration name as a comma-separated list. For example, to apply both stage and fr build configurations, use the command ng build --configuration stage,fr. In this case, the command parses the named configurations from left to right. If multiple configurations change the same setting, the last-set value is the final one."
I had read this feature enhancement as each subsequent configuration in the comma delimited list being merged into the target, thus overwriting any properties along the way. We're talking about shallow vs deep copies here, but I've got a set of shallow object graphs with simple properties that aren't being merged at all - just taking the last item and overwriting environment.ts wholesale. Looking at the PR that made the change it looks like we're just applying the last iteration of configurations instead of merging, right? I'm missing something I think.
What version of the CLI is in this in? I'm using 9; and it's in the docs there, but I don't see any tags or anything indicating where the change went upon merge to master.
Duplicate of https://github.com/angular/angular-cli/issues/11149
Most helpful comment
I'd love a feature where I'd be able to merge the fileReplacements-Array for example. If I have to copy/paste the build config permutations, the angular.json file gets quite big for me...
Best approach for me would be to merge the fileReplacements-Arrays together, like:
config a:
"fileReplacements": [ { "replace": "a", "with": "x" }, { "replace": "c", "with": "z_A" } ]config b:
"fileReplacements": [ { "replace": "b", "with": "y" }, { "replace": "c", "with": "z_B" } ]So when ng build --configuration a,b is run it uses:
configs merged:
"fileReplacements": [ { "replace": "a", "with": "x" }, { "replace": "b", "with": "y" }, { "replace": "c", "with": "z_B" } ]Instead of only using fileReplacements for config b:
"fileReplacements": [ { "replace": "b", "with": "y" }, { "replace": "c", "with": "z_B" } ]