Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to extend configurations in angular.json?

While building my Angular 6 application, I need to specify 2 things at once:

  • If it's production or development build
  • The locale I'm using

In my angular.json I have:

"build": {
  ...
  "configurations": {
    "production": {
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        }
      ],
      "optimization": true,
      "outputHashing": "all",
      "sourceMap": false,
      "extractCss": true,
      "namedChunks": false,
      "aot": true,
      "extractLicenses": true,
      "vendorChunk": false,
      "buildOptimizer": true
    },
    "pl": {
      "fileReplacements": [
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/pl.json"
        }
      ]
    },
    "en": {
      "fileReplacements": [
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/en.json"
        }
      ]
    }
  }
}

But when I'm doing ng build --configuration=en --configuration=production I'm getting an error Configuration 'en,production' could not be found. I understand it means you can specify only 1 configuration at a time.

This means I need to create separate en, pl, productionEn, productionPl configurations. Though not the cleanest pattern, I can live with that.

"build": {
  ...
  "configurations": {
    "production": {
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        }
      ],
      "optimization": true,
      "outputHashing": "all",
      "sourceMap": false,
      "extractCss": true,
      "namedChunks": false,
      "aot": true,
      "extractLicenses": true,
      "vendorChunk": false,
      "buildOptimizer": true
    },
    "pl": {
      "fileReplacements": [
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/pl.json"
        }
      ]
    },
    "en": {
      "fileReplacements": [
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/en.json"
        }
      ]
    },
    "productionPl": {
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        },
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/pl.json"
        }
      ],
      "optimization": true,
      "outputHashing": "all",
      "sourceMap": false,
      "extractCss": true,
      "namedChunks": false,
      "aot": true,
      "extractLicenses": true,
      "vendorChunk": false,
      "buildOptimizer": true
    },
    "productionEn": {
      "fileReplacements": [
        {
          "replace": "src/environments/environment.ts",
          "with": "src/environments/environment.prod.ts"
        },
        {
          "replace": "src/assets/i18n/translations.json",
          "with": "src/assets/i18n/en.json"
        }
      ],
      "optimization": true,
      "outputHashing": "all",
      "sourceMap": false,
      "extractCss": true,
      "namedChunks": false,
      "aot": true,
      "extractLicenses": true,
      "vendorChunk": false,
      "buildOptimizer": true
    }
  }
}

But what I can't live with is copying and pasting the whole production configuration contents into productionEn and productionPl. If I add even more locales, or some third separate aspect that I'd like to specify during build, this pattern would become a total nightmare to maintain. Unfortunately it seem it's the pattern that Angular team recommends in their documentation.

Is there a way to tell Angular CLI that productionEn extends production, so to not duplicate the same configuration code multiple times? Something like the code below:

"build": {
  ...
  "configurations": {
    "production": {
      (...)
    },
    "pl": {
      "extends": "production",
      (...)
    },
    "en": {
      "extends": "production",
      (...)
    }
  }
}
like image 601
Robert Kusznier Avatar asked Aug 28 '18 15:08

Robert Kusznier


People also ask

Can I update JSON file in Angular?

You can't change the content of JSON file directly through angular, you need the Backend in order to reflect the change on that JSON file.

Is Angular CLI json and Angular json same?

angular-cli. json file has been replaced by angular. json since Angular CLI v6-RC2. An Angular Workspace is a project which is produced by the ng new command.

What is Angular config json?

A file named angular. json at the root level of an Angular workspace provides workspace-wide and project-specific configuration defaults for build and development tools provided by the Angular CLI. Path values given in the configuration are relative to the root workspace folder.

What is the use of Angular json and package json?

json file among the newly created files and folders. package. json file locates in project root and contains information about your web application. The main purpose of the file comes from its name package, so it'll contain the information about npm packages installed for the project.


3 Answers

There finally is a way to do it, specifying multiple configurations in the command line:

ng build --configuration=en,production

Relevant issue in Angular repo

Note that --prod flag is ignored when you use --configuration (so you need to add production to the configuration list explicitly).

Angular docs for --configuration=configuration:

A named build target, as specified in the "configurations" section of angular.json. Each named target is accompanied by a configuration of option defaults for that target. Setting this explicitly overrides the "--prod" flag

Aliases: -c

like image 195
Robert Kusznier Avatar answered Sep 27 '22 22:09

Robert Kusznier


Update: see accepted answer for building with multiple configurations. The details below are now outdated


Reading through some issues and angular.json documentation, it appears that the options act as the defaults for the project

"architect": {
        "build": {          
          "options": {...}

These are overridden with partial options set in the configurations. From the Angular CLI workspace wiki:

configurations (object): A map of alternative target options.
configurationName (object): Partial options override for this builder.

This issue comment also mentions using configurations as an override

This sounds like all of the defaults for the project can be added to the options object e.g. move any duplicates from production, productionPl to the options: {}, and then add the fileReplacements, and the few other overrides that you require

Note: I have not tested this yet, it's just a suggestion based on the docs and issues

like image 29
Drenai Avatar answered Sep 27 '22 21:09

Drenai


But this doesn't work for ng serve you say?

Here's what probably happened:

First, here's my configuration for angular12/architect/build/configurations:

"development": {

    "customWebpackConfig": {
       "path": "custom-webpack.dev.config.js",
       "replaceDuplicatePlugins": true
    },

    "buildOptimizer": false,
    "optimization": false,
    "vendorChunk": true,
    "extractLicenses": false,
    "sourceMap": false,
    "namedChunks": true,
    "aot": true
},

"quick": {

    "fileReplacements": [
        {
            "replace": "src/app/app-routing.module.ts",
            "with": "src/app/app-routing.module.quick.ts"
        }
    ]
}

I have a standard development config, with an added configuration called quick which is what I want to set in addition to the options from development.

(So my quick is the same as OP's en and pl.)

Sorry this isn't a magic new 'quick Angular build' feature (!) - I simply made a copy of my app-routing file, commented out every lazy module except the one I'm currently working with and configured the fileReplacements option to override the standard file. The build is significant faster for a large project. Clearly though I didn't want to accidentally deploy this which is why I needed a separate configuration.

What happens when you run ng serve --configuration development,quick is it looks in the serve part of the configuration (below). As you can see I added quick here as a browser target, referencing what I have above.

"serve": 
{
    "builder": "@angular-builders/custom-webpack:dev-server",

    "options": {
       "browserTarget": "angular12:build"
    },

    "configurations": 
    {
       "production": {
          "browserTarget": "angular12:build:production"
       },
       "development": {
          "browserTarget": "angular12:build:development"
       },
       "quick": {
          "browserTarget": "angular12:build:quick"
       }
    },
    "defaultConfiguration": "development"
},

What's actually happening when you ask for --configuration development,quick is it merges these two nodes:

"development": {
   "browserTarget": "angular12:build:development"
}

"quick": {
   "browserTarget": "angular12:build:quick"
}

Which results in:

"development": {
   "browserTarget": "angular12:build:development"
}

Makes sense why it didn't work now :-)

Solution:

The solution is fortunately as simple as updating serve/quick to:

"quick": {
     "browserTarget": "angular12:build:development,quick"
}

Then simply run:

ng-serve --configuration quick

This will in turn will merge your development and quick configurations under architect/build as if you were running ng build.


PS. You may see I'm using customWebpackConfig. That is the @angular-builders/custom-webpack package that allows for customization. It's irrelevant to my answer, but allowed me to prove to myself that it was indeed working as I was able to observe both my customWebpack plugins running and only the single lazy chunk I wanted was built.

like image 30
Simon_Weaver Avatar answered Sep 27 '22 21:09

Simon_Weaver