Skip to content

Pass values from command line, environment and CLI config to code when build\serve #10521

@Flybbit

Description

@Flybbit

Requirement
I have three app in project. They use shared code. AppA uses part A from shared code, AppB uses part B and third AppC uses both A and B parts. So I need something like conditional compilation to reduce bundle size for AppA and AppB.
Another requirement is to pass some parameters like connection address or build number to code.
Third one feature which could be nice to have is ability to define environment variable on computer and use it when build\serve. So on dev machine you can get only dev build - "safety barrier".

Possible solution
Webpack has DefinePlugin and it can help to implement all three features. We should just change CLI config schema

"defines": {
  "type": "array",
  "description": "defines",
  "items": {                             
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Name of the def"
          },
          "value": {
            "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}],
            "description": "Value of the def for all targets"
          },
           "targets": {
            "type": "object",
            "properties": {
              "development": {
                "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}],
                "description": "Value of the def for development target"
              },
              "production": {
                "oneOf": [{"type": "string"}, {"type": "number"}, {"type": "boolean"}],
                "description": "Value of the def for production target"
              }
            }
          }
        }
  },
  "default": []
}

and add plugin in common webpack config

new webpack.DefinePlugin(
  appConfig.defines.reduce(
    (defines, item) => {
      if (item && item.name){
        let name = item.name;
        let value = item.targets ? item.targets[buildOptions.target] : item.value;
        if (typeof value === 'string') {
          value = JSON.stringify(eval(value));                      
        }
        defines[name] = value;
      }                  
      return defines;
    }, {}
  )
)

How to use:

  1. config your app
  "defines": [
    {
      "name": "DEFINE_OPTION",
      "value": true
    },
    {
      "name": "ENV_OPTION",
      "value": "process.env.ENV_OPTION"
    },
    {
      "name": "COMMAND_LINE_OPTION",
      "value": "buildOptions.command_line_option"
    },
    {
      "name": "CALC_OPTION",
      "value": "2 + 2"
    }
  ]
  1. Run
ENV_OPTION="my value"
ng serve --command_line_option=42

somewhere in your code

declare var DEFINE_OPTION: boolean;
declare var ENV_OPTION: string;
declare var COMMAND_LINE_OPTION: string;
declare var CALC_OPTION: number;


if (DEFINE_OPTION){
  //this code will be excluded by optimizer if !DEFINE_OPTION  
}

As bonus (?) you can define some logic (see CALC_OPTION). Another thing - access to buildOptions. It allows to get command line args fast and easy, but looks a bit dirty

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions