Compile-time dead code elimination with dart2js

Right before the release of Dart 1.0, the Dart team snuck in a cool new feature that helps you optimize the generated JavaScript from your Dart apps. Configuration values from the environment can be evaluated at compile time and potentially result in dead code elimination. Smaller code is faster code!

As an example, let's consider the common case of logging. Debug logging is a useful tool during development and testing, but often there's no need to ship production code with debug log statements. Wouldn't it be cool if you could remove all the debug log statements before you ship to production, without having to manually delete any lines of code? Now with Dart and fromEnvironment, you can!

Here is a small example of a log function that is useful during development, but unnecessary during production. If a DEBUG is set, the log message is printed. The code gets the compile-time constant value from the String.fromEnvironment() constructor. Notice the const qualifier, instead of new, as the important signal that the environment value is a compile-time constant. Without const here, the compiler doesn't know what the value is during compilation.

log(String msg) {
  if (const String.fromEnvironment('DEBUG') != null) {
    print('debug: $msg');
  }
}

main() {
  log('In production, I do not exist');
}

For dart2js, you can pass values from the environment (not to be confused with "environment variables" that you might set in your shell) via the -D command line arguments.

When compiled with dart2js -DDEBUG=true app.dart, the output includes the logging behavior:

  main: function() {
    H.printString("debug: In the production release, I do not exist");
  }

Notice how dart2js inlined the log function into main, which is cool. Because the DEBUG value was set, dart2js knew that the if statement inside of log() returns true.

However, if -DDEBUG is not set, the logging behavior is not included in the generated JavaScript code:

  main: function() {
  }

Tools like dart2js can understand how expressions that use compile-time constants resolve. Dead code is eliminated from the generated output.

Strings, ints, and booleans can produce values from the environment: int.fromEnvironment, String.fromEnvironment, and bool.fromEnvironment. Use fromEnvironment with const to help control which code blocks make it into the generated JavaScript code.
Post a Comment

Popular posts from this blog