Build: Option to add env variable

Created on 25 Feb 2018  路  24Comments  路  Source: dart-lang/build

in the old pub serve/build we can pass env variable with -D.
the same kind of option would be really cool and simplify everything

build_web_compilers enhancement

All 24 comments

Thanks for filing! I imagine we can support this as a web compiler options.

Some questions:

  1. This is simple enough for Dart2JS, but how would it work for DDC (modular)?
  2. Should we support it via the command-line _and_ build.yaml?

/cc @natebosch @jakemac53

right now i can do like this
in build.dev.yaml i have

targets:
  runny:
    sources:
      exclude: ["lib/builder.dart"]
    builders:
      sass_builder|sass_builder:
        enabled: False
      angular_components|scss_builder:
        enabled: True
      build_web_compilers|entrypoint:
        generate_for:
        - web/main.dart
        options:
          compiler: dartdevc
          dart2js_args:
          - --define env=dev

and for the release i have

targets:
  runny:
    sources:
      exclude: ["lib/builder.dart"]
    builders:
      sass_builder|sass_builder:
        enabled: False
      angular_components|scss_builder:
        enabled: True
      build_web_compilers|entrypoint:
        generate_for:
        - web/main.dart
        options:
          compiler: dart2js
          dart2js_args:
          - -Denv=prod
          - --fast-startup
          - --minify
          - --trust-type-annotations
          - --trust-primitives

Does the above cover what you need? Do you need a corresponding option like dartdevc_args to supply it there as well?

Fwiw, you could technically supply environment args to the build script itself but the build system does not today track environment variables so doing so would not be advised. Changing environment variables will not cause actions that read that variable to be rebuilt.

Supplying environment args via options in build.yaml will invalidate all corresponding actions though.

The code above cover my need :)

Ok, closing for now then! Feel free to re-open if you think we need some deeper level of support.

I'm a bit confused by your example. In your first one you have compiler: dartdevc and then also use dart2js_args - those are getting ignored.

If you need to pass environment args to DDC we'd have to add dartdevc_args and this would be a little tricky since there are 2 separate builders that invoke DDC. Let us know if this would help you.

dev is the default so i dont have problem with dartdevc 馃槈

In fact it will be really great if we can pass args from build.yaml for the dartdevc compiler

either passing arguments via dartdevc_args or pub run build_runner serve -D...` would be great

/cc @natebosch @jakemac53

@lejard-h what arguments would you want to pass to dartdevc?

Note that supporting pub run build_runner serve -D would require invalidating the entire world whenever you pass different values. We have no way of knowing what builders may be affected by that.

Our usecases is to be able to switch environment for development/debuging purpose.

pub serve -Dhost=https://staging......
pub serve -Dhost=http://localhost -Denv=prod`

I also tried to have multiple main, main.dev.dart, main.staging.dart, main.dart
but I also need to have multiple index.html and multiple build.yaml that reference the right main which is harder to maintain.

So to clarify - do you use these values at build time or runtime?

For build time things we now have a way of doing something similar so you can pass options to your builder based on the built-in release/dev modes (--release).

If you only wanted the variables available in the running application but not the build process then I misunderstood and that is something that would not affect the build process in a negative way.

馃憤 to this. I was just trying to use two different API urls, and I couldn't find a simple way..

Having something like what @lejard-h suggests, passing arguments/variables like pub serve -Dhost=http://localhost -Denv=prod in order to retrieve them by something like String.fromEnvironment('host') at runtime, is a pretty basic feature that's available in all web development platforms I can think of (e.g. NodeJS, via process.env). In my opinion, this feature is very much needed.

/cc @natebosch @jakemac53

How attached are people to the specifics here (using *.fromEnvironment)? The problem with these is that for existing modular compilers those values would have to be available at build time, but we don't have any way of knowing if/when a builder accesses them, so we would have to invalidate the entire build whenever the environment changes (which doesn't seem like the right tradeoff for simply switching your api server host for instance).

I do have an alternate proposal, which I think would solve the same problem but in a way that is less detrimental to build times. My proposal is as follows:

Create a basic Builder (ConstantBuilder?), which creates a dart file that contains some specified constants. It would support only basic dart types which can be represented via json (int, String, bool, Map, List). This builder would create constants in a dart file, described by the options you pass it, allowing you to configure different options per mode or configuration. It would never be applied by default, you would have to explicitly enable it.

An example of configuring it would look something like this:

targets:
  $default:
    builders:
      constants_builder:
        enabled: true
        options:
          host: "http://localhost"
          env: "dev"
        release_options:
          host: "https://staging"
          env: "prod"

The main complication here would be determining where the output should go. It could either be hardcoded into the builder to some specific file (lib/constants.dart?) or we would need to come up with something smarter.

So, assuming a hardcoded output path for now, the above builder would create a file like this, if dev mode:

const host = "http://localhost";
const env = "dev";

The advantage here is that then only the modules which import that file get invalidated when you switch modes. If you use dependency injection to pass these values down into your app, then you could easily set it up such that the only module importing this file was the root app module, and edit refresh times would not be significantly affected when switching modes (for existing modular compilers). Dart2js would still have to recompile from scratch though.

Note that this would make the variables available at both build time and runtime, and on all platforms as well in a uniform manner.

Another potential option here would be to make a package, called environment, which contains only a single file (environment.dart) which is generated in the same way as I outlined above.

You could then use the existing --define flag to add constants to that file (--define=environment=foo=bar), or you could use https://github.com/dart-lang/build/issues/1370 once implemented to set defaults for dev/release mode.

Then you just import package:environment/environment.dart and you get access to the constants you specified (note that the same invalidation rules apply as my other option, I think this just cleans things up by having a canonical import for all the constants).

cc @natebosch @kevmoo @grouma for thoughts

So one consideration I realized talking with @grouma about this approach is actual Builder code itself would not be able to use these constants - because the build script itself can't transitively import generated code.

You would still have access to its value via the Resolver though.

Hi Jacob,

I'm not particularly attached to the way the constants/arguments/variables are retrieved (just mentioned .fromEnvironment, as I believe that's the way it worked on previous versions - correct me if I'm wrong). But I'm happy with other alternatives.

A bit of background about my initial comment above: I wouldn't commit my production credentials (API keys, or any other sensible data) into my VCS, being it environment variables or a constants file like you suggest above, but I believe environment variables are more standard and could be supported by CI/CD solutions where you can provide keys in a more secure way. I understand though that there might be implications in the way the build system works (which I know very little about), so I'm just explaining my point of view about using environment variables, not saying it's the best solution given how things work in Dart.

I like the solutions you propose, specially the environment.dart that could take flags with the environment-specific values, as it wouldn't need an existing constants file. But there might be people who prefer the later.

@srodrigo That use case definitely makes sense - I think the only alternative today is to read some configuration file which you add to your .gitignore.

There is actually an existing solution for this problem, see the JsonLiteral annotation in the json_annotation package.

You would need to add a dev_dependency on json_serializable which will actually process that annotation and create a generated file that gives you access to the values in the map.

Then you would create a json file with your configuration, and add it to your .gitignore (or equivalent).

That sounds interesting and something that could fit my use case. I'll definitely have a look.

Many thanks :)

Is there any working solution with something like ConstantBuilder as @jakemac53 mentioned?

I am searching for a way how to switch url router provider (hash on develop, normal on production) in AngularDart, could be a build-time solution, but dunno how to do it.

@tenhobi I just has the same problem and went with the ConstantBuilder solution @jakemac53 mentioned, I posted my implementation here: https://gist.github.com/pschiffmann/9a9453ae5447394f74f6d3047d46e531

Note that I am actually adding a general ddc-args option to the build_web_compilers|ddc builder.

This will enable the use of -D defines, but with all the problems highlighted here. You cannot mix values within a build, its an entirely global option for all applications. Changing the value will cause all ddc actions to rebuild.

https://github.com/dart-lang/build/pull/2507

Was this page helpful?
0 / 5 - 0 ratings

Related issues

natebosch picture natebosch  路  5Comments

smaifullerton-wk picture smaifullerton-wk  路  5Comments

atreeon picture atreeon  路  3Comments

zgramming picture zgramming  路  6Comments

kentcb picture kentcb  路  7Comments