add web compiler option to pubspec.yaml, change --compiler to --web-compiler (#1624)


diff --git a/lib/src/cached_package.dart b/lib/src/cached_package.dart
index 5452ca7..1dd68d6 100644
--- a/lib/src/cached_package.dart
+++ b/lib/src/cached_package.dart
@@ -7,6 +7,7 @@
 import 'package:yaml/yaml.dart';
 
 import 'barback/transformer_config.dart';
+import 'compiler.dart';
 import 'io.dart';
 import 'package.dart';
 import 'pubspec.dart';
@@ -89,6 +90,7 @@
   bool get isPrivate => _inner.isPrivate;
   bool get isEmpty => _inner.isEmpty;
   List<PubspecException> get allErrors => _inner.allErrors;
+  Map<String, Compiler> get webCompiler => _inner.webCompiler;
 
   List<Set<TransformerConfig>> get transformers => const [];
 
diff --git a/lib/src/command/barback.dart b/lib/src/command/barback.dart
index 862fca0..c02ff53 100644
--- a/lib/src/command/barback.dart
+++ b/lib/src/command/barback.dart
@@ -27,23 +27,28 @@
 
   /// The current compiler mode.
   Compiler get compiler {
-    if (argResults.options.contains('dart2js') &&
-        argResults.wasParsed('dart2js')) {
-      if (argResults.options.contains("compiler") &&
-          argResults.wasParsed("compiler")) {
+    if (argResults.options.contains("dart2js") &&
+        argResults.wasParsed("dart2js")) {
+      if (argResults.options.contains("web-compiler") &&
+          argResults.wasParsed("web-compiler")) {
         usageException(
-            "The --dart2js flag can't be used with the --compiler arg. "
-            "Prefer using the --compiler arg as --[no]-dart2js is deprecated.");
+            "The --dart2js flag can't be used with the --web-compiler arg. "
+            "Prefer using the --web-compiler arg as --[no]-dart2js is "
+            "deprecated.");
+      } else {
+        log.warning("The --dart2js flag is deprecated, please use "
+            "--web-compiler=dart2js option instead.");
       }
-      if (argResults['dart2js']) {
+      if (argResults["dart2js"]) {
         return Compiler.dart2JS;
       } else {
         return Compiler.none;
       }
-    } else if (argResults.options.contains("compiler")) {
-      return Compiler.byName(argResults["compiler"]);
+    } else if (argResults.options.contains("web-compiler")) {
+      return Compiler.byName(argResults["web-compiler"]);
     } else {
-      return Compiler.dart2JS;
+      var compiler = entrypoint.root.pubspec.webCompiler[mode.name];
+      return compiler ?? Compiler.dart2JS;
     }
   }
 
@@ -68,9 +73,8 @@
         defaultsTo: false,
         negatable: false);
 
-    argParser.addOption("compiler",
+    argParser.addOption("web-compiler",
         allowed: Compiler.names,
-        defaultsTo: 'dart2js',
         help: 'The JavaScript compiler to use to build the app.');
   }
 
diff --git a/lib/src/pubspec.dart b/lib/src/pubspec.dart
index 3e830ea..18d0b5c 100644
--- a/lib/src/pubspec.dart
+++ b/lib/src/pubspec.dart
@@ -8,6 +8,7 @@
 import 'package:yaml/yaml.dart';
 
 import 'barback/transformer_config.dart';
+import 'compiler.dart';
 import 'exceptions.dart';
 import 'io.dart';
 import 'package.dart';
@@ -354,6 +355,49 @@
 
   Map<String, String> _executables;
 
+  /// The settings for which web compiler to use in which mode.
+  ///
+  /// It is a map of [String] to [Compiler]. Each key is the name of a mode, and
+  /// the value is the web compiler to use in that mode.
+  ///
+  /// Valid compiler values are all of [Compiler.names].
+  Map<String, Compiler> get webCompiler {
+    if (_webCompiler != null) return _webCompiler;
+
+    _webCompiler = <String, Compiler>{};
+    var webYaml = fields.nodes['web'];
+    if (webYaml?.value == null) return _webCompiler;
+
+    if (webYaml is! Map) {
+      _error('"web" field must be a map.', webYaml.span);
+    }
+
+    var compilerYaml = (webYaml as YamlMap)['compiler'];
+    if (compilerYaml == null) return _webCompiler;
+
+    if (compilerYaml is! Map) {
+      _error('"compiler" field must be a map.',
+          (webYaml as YamlMap).nodes['compiler'].span);
+    }
+
+    compilerYaml.nodes.forEach((key, value) {
+      if (key.value is! String) {
+        _error('"compiler" keys must be strings.', key.span);
+      }
+
+      if (!Compiler.names.contains(value.value)) {
+        _error(
+            '"compiler" values must be one of ${Compiler.names}.', value.span);
+      }
+
+      _webCompiler[key.value] = Compiler.byName(value.value);
+    });
+
+    return _webCompiler;
+  }
+
+  Map<String, Compiler> _webCompiler;
+
   /// Whether the package is private and cannot be published.
   ///
   /// This is specified in the pubspec by setting "publish_to" to "none".
diff --git a/test/compiler/compiler_flag_test.dart b/test/compiler/compiler_flag_test.dart
deleted file mode 100644
index 68c9ed1..0000000
--- a/test/compiler/compiler_flag_test.dart
+++ /dev/null
@@ -1,98 +0,0 @@
-// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS d.file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'package:scheduled_test/scheduled_stream.dart';
-import 'package:scheduled_test/scheduled_test.dart';
-
-import 'package:pub/src/dartdevc/module_reader.dart';
-import 'package:pub/src/exit_codes.dart';
-
-import '../descriptor.dart' as d;
-import '../test_pub.dart';
-import '../serve/utils.dart';
-import 'utils.dart';
-
-main() {
-  integrationWithCompiler("compiler flag switches compilers", (compiler) {
-    d.dir(appPath, [
-      d.appPubspec(),
-      d.dir("lib", [
-        d.file("hello.dart", "hello() => print('hello');"),
-      ]),
-      d.dir("web", [
-        d.file(
-            "main.dart",
-            '''
-          import 'package:myapp/hello.dart';
-
-          void main() => hello();
-        '''),
-      ]),
-    ]).create();
-
-    pubGet();
-    pubServe(compiler: compiler);
-    switch (compiler) {
-      case Compiler.dartDevc:
-        requestShouldSucceed(
-            'packages/$appPath/$moduleConfigName', contains('lib__hello'));
-        requestShouldSucceed(moduleConfigName, contains('web__main'));
-        requestShouldSucceed('packages/$appPath/lib__hello.unlinked.sum', null);
-        requestShouldSucceed('web__main.unlinked.sum', null);
-        requestShouldSucceed('packages/$appPath/lib__hello.linked.sum', null);
-        requestShouldSucceed('web__main.linked.sum', null);
-        requestShouldSucceed(
-            'packages/$appPath/lib__hello.js', contains('hello'));
-        requestShouldSucceed(
-            'packages/$appPath/lib__hello.js.map', contains('lib__hello.js'));
-        requestShouldSucceed('web__main.js', contains('hello'));
-        requestShouldSucceed('web__main.js.map', contains('web__main.js'));
-        requestShouldSucceed('dart_sdk.js', null);
-        requestShouldSucceed('require.js', null);
-        requestShouldSucceed('main.dart.js', null);
-        break;
-      case Compiler.dart2JS:
-        requestShouldSucceed('main.dart.js', null);
-        requestShould404('web__main.js');
-        break;
-      case Compiler.none:
-        requestShould404('main.dart.js');
-        break;
-    }
-    endPubServe();
-  }, compilers: Compiler.all);
-
-  integration("invalid compiler flag gives an error", () {
-    d.dir(appPath, [
-      d.appPubspec(),
-    ]).create();
-
-    pubGet();
-    var process = startPubServe(args: ['--compiler', 'invalid']);
-    process.shouldExit(USAGE);
-    process.stderr.expect(consumeThrough(
-        '"invalid" is not an allowed value for option "compiler".'));
-  });
-
-  integration("--dart2js with --compiler is invalid", () {
-    d.dir(appPath, [
-      d.appPubspec(),
-    ]).create();
-
-    pubGet();
-    var argCombos = [
-      ['--dart2js', '--compiler=dartdevc'],
-      ['--no-dart2js', '--compiler=dartdevc'],
-      ['--dart2js', '--compiler=dart2js'],
-      ['--no-dart2js', '--compiler=dart2js'],
-    ];
-    for (var args in argCombos) {
-      var process = startPubServe(args: args);
-      process.shouldExit(USAGE);
-      process.stderr.expect(consumeThrough(
-          "The --dart2js flag can't be used with the --compiler arg. Prefer "
-          "using the --compiler arg as --[no]-dart2js is deprecated."));
-    }
-  });
-}
diff --git a/test/compiler/compiler_selection_test.dart b/test/compiler/compiler_selection_test.dart
new file mode 100644
index 0000000..517ffe2
--- /dev/null
+++ b/test/compiler/compiler_selection_test.dart
@@ -0,0 +1,164 @@
+// Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS d.file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:scheduled_test/scheduled_stream.dart';
+import 'package:scheduled_test/scheduled_test.dart';
+
+import 'package:pub/src/dartdevc/module_reader.dart';
+import 'package:pub/src/exit_codes.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import '../serve/utils.dart';
+import 'utils.dart';
+
+main() {
+  integrationWithCompiler("--web-compiler option switches compilers",
+      (compiler) {
+    d.dir(appPath, [
+      d.appPubspec(),
+      d.dir("lib", [
+        d.file("hello.dart", "hello() => print('hello');"),
+      ]),
+      d.dir("web", [
+        d.file(
+            "main.dart",
+            '''
+          import 'package:myapp/hello.dart';
+
+          void main() => hello();
+        '''),
+      ]),
+    ]).create();
+
+    pubGet();
+    pubServe(compiler: compiler);
+    switch (compiler) {
+      case Compiler.dartDevc:
+        requestShouldSucceed(
+            'packages/$appPath/$moduleConfigName', contains('lib__hello'));
+        requestShouldSucceed(moduleConfigName, contains('web__main'));
+        requestShouldSucceed('packages/$appPath/lib__hello.unlinked.sum', null);
+        requestShouldSucceed('web__main.unlinked.sum', null);
+        requestShouldSucceed('packages/$appPath/lib__hello.linked.sum', null);
+        requestShouldSucceed('web__main.linked.sum', null);
+        requestShouldSucceed(
+            'packages/$appPath/lib__hello.js', contains('hello'));
+        requestShouldSucceed(
+            'packages/$appPath/lib__hello.js.map', contains('lib__hello.js'));
+        requestShouldSucceed('web__main.js', contains('hello'));
+        requestShouldSucceed('web__main.js.map', contains('web__main.js'));
+        requestShouldSucceed('dart_sdk.js', null);
+        requestShouldSucceed('require.js', null);
+        requestShouldSucceed('main.dart.js', null);
+        break;
+      case Compiler.dart2JS:
+        requestShouldSucceed('main.dart.js', null);
+        requestShould404('web__main.js');
+        break;
+      case Compiler.none:
+        requestShould404('main.dart.js');
+        break;
+    }
+    endPubServe();
+  }, compilers: Compiler.all);
+
+  integration("invalid --web-compiler option gives an error", () {
+    d.dir(appPath, [
+      d.appPubspec(),
+    ]).create();
+
+    pubGet();
+    var process = startPubServe(args: ['--web-compiler', 'invalid']);
+    process.shouldExit(USAGE);
+    process.stderr.expect(consumeThrough(
+        '"invalid" is not an allowed value for option "web-compiler".'));
+  });
+
+  integration("--dart2js with --web-compiler is invalid", () {
+    d.dir(appPath, [
+      d.appPubspec(),
+    ]).create();
+
+    pubGet();
+    var argCombos = [
+      ['--dart2js', '--web-compiler=dartdevc'],
+      ['--no-dart2js', '--web-compiler=dartdevc'],
+      ['--dart2js', '--web-compiler=dart2js'],
+      ['--no-dart2js', '--web-compiler=dart2js'],
+    ];
+    for (var args in argCombos) {
+      var process = startPubServe(args: args);
+      process.shouldExit(USAGE);
+      process.stderr.expect(consumeThrough(
+          "The --dart2js flag can't be used with the --web-compiler arg. Prefer "
+          "using the --web-compiler arg as --[no]-dart2js is deprecated."));
+    }
+  });
+
+  integrationWithCompiler("web compiler can be set in the pubspec", (compiler) {
+    d.dir(appPath, [
+      d.pubspec({
+        'name': 'myapp',
+        'web': {
+          'compiler': {'debug': compiler.name}
+        },
+      }),
+      d.dir('web', [
+        d.file(
+            'main.dart',
+            '''
+          void main() => print('hello');
+        '''),
+      ]),
+    ]).create();
+
+    pubGet();
+    pubServe(args: ['--mode', 'debug']);
+    switch (compiler) {
+      case Compiler.dartDevc:
+        requestShouldSucceed(moduleConfigName, contains('web__main'));
+        requestShouldSucceed('web__main.js', contains('hello'));
+        break;
+      case Compiler.dart2JS:
+        requestShouldSucceed('main.dart.js', contains('hello'));
+        requestShould404('web__main.js');
+        break;
+    }
+    endPubServe();
+  });
+
+  integrationWithCompiler("--web-compiler flag overrides pubspec config",
+      (compiler) {
+    d.dir(appPath, [
+      d.pubspec({
+        'name': 'myapp',
+        'web': {
+          'compiler': {'debug': Compiler.none.name}
+        },
+      }),
+      d.dir('web', [
+        d.file(
+            'main.dart',
+            '''
+          void main() => print('hello');
+        '''),
+      ]),
+    ]).create();
+
+    pubGet();
+    pubServe(compiler: compiler, args: ['--mode', 'debug']);
+    switch (compiler) {
+      case Compiler.dartDevc:
+        requestShouldSucceed(moduleConfigName, contains('web__main'));
+        requestShouldSucceed('web__main.js', contains('hello'));
+        break;
+      case Compiler.dart2JS:
+        requestShouldSucceed('main.dart.js', contains('hello'));
+        requestShould404('web__main.js');
+        break;
+    }
+    endPubServe();
+  });
+}
diff --git a/test/compiler/compiles_entrypoints_in_root_package_test.dart b/test/compiler/compiles_entrypoints_in_root_package_test.dart
index 5321c3a..ccd79b0 100644
--- a/test/compiler/compiles_entrypoints_in_root_package_test.dart
+++ b/test/compiler/compiles_entrypoints_in_root_package_test.dart
@@ -42,7 +42,7 @@
       "benchmark",
       "foo",
       "web",
-      "--compiler=${compiler.name}"
+      "--web-compiler=${compiler.name}"
     ], output: new RegExp(r'Built [\d]+ files to "build".'));
 
     d.dir(appPath, [
diff --git a/test/compiler/environment_constant_test.dart b/test/compiler/environment_constant_test.dart
index 8e2853e..a70bfe1 100644
--- a/test/compiler/environment_constant_test.dart
+++ b/test/compiler/environment_constant_test.dart
@@ -30,7 +30,7 @@
         "build",
         "--define",
         "name=fblthp",
-        "--compiler=${compiler.name}"
+        "--web-compiler=${compiler.name}"
       ], output: new RegExp(r'Built [\d]+ file[s]? to "build".'));
 
       var expectedFile;
diff --git a/test/compiler/ignores_entrypoints_in_lib_test.dart b/test/compiler/ignores_entrypoints_in_lib_test.dart
index c5f36d3..6a92844 100644
--- a/test/compiler/ignores_entrypoints_in_lib_test.dart
+++ b/test/compiler/ignores_entrypoints_in_lib_test.dart
@@ -25,7 +25,7 @@
   integrationWithCompiler("build ignores Dart entrypoints in lib", (compiler) {
     pubGet();
     schedulePub(
-        args: ["build", "--all", "--compiler=${compiler.name}"],
+        args: ["build", "--all", "--web-compiler=${compiler.name}"],
         output: new RegExp(r'Built [\d]+ files? to "build".'));
 
     d.dir(appPath, [
diff --git a/test/compiler/ignores_non_entrypoint_dart_files_test.dart b/test/compiler/ignores_non_entrypoint_dart_files_test.dart
index 555a338..4a98de4 100644
--- a/test/compiler/ignores_non_entrypoint_dart_files_test.dart
+++ b/test/compiler/ignores_non_entrypoint_dart_files_test.dart
@@ -26,7 +26,7 @@
       (compiler) {
     pubGet();
     schedulePub(
-        args: ["build", "--compiler=${compiler.name}"],
+        args: ["build", "--web-compiler=${compiler.name}"],
         output: new RegExp(r'Built [\d]+ files? to "build".'));
 
     d.dir(appPath, [
diff --git a/test/compiler/includes_source_maps_in_debug_test.dart b/test/compiler/includes_source_maps_in_debug_test.dart
index c048748..61c5506 100644
--- a/test/compiler/includes_source_maps_in_debug_test.dart
+++ b/test/compiler/includes_source_maps_in_debug_test.dart
@@ -26,7 +26,7 @@
 
     pubGet();
     schedulePub(
-        args: ["build", "--mode", "debug", "--compiler=${compiler.name}"],
+        args: ["build", "--mode", "debug", "--web-compiler=${compiler.name}"],
         output: new RegExp(r'Built \d+ files to "build".'),
         exitCode: 0);
 
diff --git a/test/compiler/omits_source_map_in_release_test.dart b/test/compiler/omits_source_map_in_release_test.dart
index df4b1c5..b7f4e89 100644
--- a/test/compiler/omits_source_map_in_release_test.dart
+++ b/test/compiler/omits_source_map_in_release_test.dart
@@ -25,7 +25,7 @@
 
     pubGet();
     schedulePub(
-        args: ["build", "--compiler=${compiler.name}"],
+        args: ["build", "--web-compiler=${compiler.name}"],
         output: new RegExp(r'Built \d+ files? to "build".'),
         exitCode: 0);
 
diff --git a/test/compiler/reports_dart_parse_errors_test.dart b/test/compiler/reports_dart_parse_errors_test.dart
index 5bf2360..3a91178 100644
--- a/test/compiler/reports_dart_parse_errors_test.dart
+++ b/test/compiler/reports_dart_parse_errors_test.dart
@@ -30,7 +30,7 @@
   });
 
   integrationWithCompiler("Pub build reports Dart parse errors", (compiler) {
-    var pub = startPub(args: ["build", "--compiler", compiler.name]);
+    var pub = startPub(args: ["build", "--web-compiler", compiler.name]);
     _expectErrors(pub, compiler);
 
     pub.shouldExit(exit_codes.DATA);
@@ -42,7 +42,7 @@
   });
 
   integrationWithCompiler("Pub serve reports Dart parse errors", (compiler) {
-    var pub = pubServe(args: ["--compiler", compiler.name]);
+    var pub = pubServe(args: ["--web-compiler", compiler.name]);
 
     switch (compiler) {
       case Compiler.dartDevc:
diff --git a/test/compiler/source_maps_are_self_contained_test.dart b/test/compiler/source_maps_are_self_contained_test.dart
index 0a22711..9241714 100644
--- a/test/compiler/source_maps_are_self_contained_test.dart
+++ b/test/compiler/source_maps_are_self_contained_test.dart
@@ -55,7 +55,7 @@
 
     pubGet();
     schedulePub(
-        args: ["build", "--mode", "debug", "--compiler", compiler.name],
+        args: ["build", "--mode", "debug", "--web-compiler", compiler.name],
         output: new RegExp(r'Built \d+ files to "build".'),
         exitCode: 0);
 
diff --git a/test/compiler/supports_configuration_with_build_test.dart b/test/compiler/supports_configuration_with_build_test.dart
index 5f993a0..0a95565 100644
--- a/test/compiler/supports_configuration_with_build_test.dart
+++ b/test/compiler/supports_configuration_with_build_test.dart
@@ -71,7 +71,7 @@
     pubGet();
 
     schedulePub(
-        args: ["build", "--compiler", compiler.name],
+        args: ["build", "--web-compiler", compiler.name],
         output: new RegExp(r'Built \d+ files? to "build".'),
         exitCode: 0);
 
diff --git a/test/compiler/utils.dart b/test/compiler/utils.dart
index ffefe03..e9f1c21 100644
--- a/test/compiler/utils.dart
+++ b/test/compiler/utils.dart
@@ -15,6 +15,6 @@
     {List<Compiler> compilers}) {
   compilers ??= [Compiler.dart2JS, Compiler.dartDevc];
   for (var compiler in compilers) {
-    integration('--compiler=${compiler.name} $name', () => testFn(compiler));
+    integration('--web-compiler=${compiler.name} $name', () => testFn(compiler));
   }
 }
diff --git a/test/dartdevc/build_test.dart b/test/dartdevc/build_test.dart
index f249a50..eeb0c48 100644
--- a/test/dartdevc/build_test.dart
+++ b/test/dartdevc/build_test.dart
@@ -9,7 +9,7 @@
 import '../test_pub.dart';
 
 main() {
-  integration("pub build --compiler=dartdevc creates all required sources", () {
+  integration("pub build --web-compiler=dartdevc creates all required sources", () {
     d.dir("foo", [
       d.libPubspec("foo", "1.0.0"),
       d.dir("lib", [
@@ -58,7 +58,7 @@
 
     pubGet();
     schedulePub(
-        args: ["build", "web", "--compiler=${Compiler.dartDevc.name}"],
+        args: ["build", "web", "--web-compiler=${Compiler.dartDevc.name}"],
         output: new RegExp(r'Built [\d]+ files to "build".'));
 
     d.dir(appPath, [
diff --git a/test/dartdevc/dartdevc_test.dart b/test/dartdevc/dartdevc_test.dart
index 20c39bc..24b62fe 100644
--- a/test/dartdevc/dartdevc_test.dart
+++ b/test/dartdevc/dartdevc_test.dart
@@ -48,7 +48,7 @@
     ]).create();
 
     pubGet();
-    pubServe(args: ['--compiler', 'dartdevc']);
+    pubServe(args: ['--web-compiler', 'dartdevc']);
     // Just confirm some basic things are present indicating that the module
     // was compiled. The goal here is not to test dartdevc itself.
     requestShouldSucceed('web__main.js', contains('main'));
@@ -79,7 +79,7 @@
     ]).create();
 
     pubGet();
-    pubServe(args: ['--compiler', 'dartdevc']);
+    pubServe(args: ['--web-compiler', 'dartdevc']);
     requestShouldSucceed('dart_sdk.js', null);
     requestShouldSucceed('require.js', null);
     requestShouldSucceed('dart_stack_trace_mapper.js', null);
diff --git a/test/dartdevc/module_config_test.dart b/test/dartdevc/module_config_test.dart
index bda919b..f0e615d 100644
--- a/test/dartdevc/module_config_test.dart
+++ b/test/dartdevc/module_config_test.dart
@@ -51,7 +51,7 @@
     ]).create();
 
     pubGet();
-    pubServe(args: ['--compiler', 'dartdevc']);
+    pubServe(args: ['--web-compiler', 'dartdevc']);
 
     moduleRequestShouldSucceed(moduleConfigName, [
       makeModule(
diff --git a/test/dartdevc/summaries_test.dart b/test/dartdevc/summaries_test.dart
index c1f93d2..ebf6009 100644
--- a/test/dartdevc/summaries_test.dart
+++ b/test/dartdevc/summaries_test.dart
@@ -50,7 +50,7 @@
     ]).create();
 
     pubGet();
-    pubServe(args: ['--compiler', 'dartdevc']);
+    pubServe(args: ['--web-compiler', 'dartdevc']);
 
     linkedSummaryRequestShouldSucceed('web__main$linkedSummaryExtension', [
       endsWith('web/main.dart'),
@@ -119,7 +119,7 @@
     ]).create();
 
     pubGet();
-    pubServe(args: ['--compiler', 'dartdevc']);
+    pubServe(args: ['--web-compiler', 'dartdevc']);
 
     unlinkedSummaryRequestShouldSucceed(
         'web__main$unlinkedSummaryExtension', [endsWith('web/main.dart')]);
diff --git a/test/pubspec_test.dart b/test/pubspec_test.dart
index 92b35df..00aaa82 100644
--- a/test/pubspec_test.dart
+++ b/test/pubspec_test.dart
@@ -2,6 +2,7 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+import 'package:pub/src/compiler.dart';
 import 'package:pub/src/package.dart';
 import 'package:pub/src/pubspec.dart';
 import 'package:pub/src/source.dart';
@@ -592,5 +593,66 @@
         expect(pubspec.executables['command'], equals('command'));
       });
     });
+
+    group("web", () {
+      test("can be empty", () {
+        var pubspec = new Pubspec.parse('web: {}', sources);
+        expect(pubspec.webCompiler, isEmpty);
+      });
+
+      group("compiler", () {
+        test("defaults to an empty map if omitted", () {
+          var pubspec = new Pubspec.parse('', sources);
+          expect(pubspec.webCompiler, isEmpty);
+        });
+
+        test("defaults to an empty map if web is null", () {
+          var pubspec = new Pubspec.parse('web:', sources);
+          expect(pubspec.webCompiler, isEmpty);
+        });
+
+        test("defaults to an empty map if compiler is null", () {
+          var pubspec = new Pubspec.parse('web: {compiler:}', sources);
+          expect(pubspec.webCompiler, isEmpty);
+        });
+
+        test("allows simple names for keys and valid compilers in values", () {
+          var pubspec = new Pubspec.parse(
+              '''
+web:
+  compiler:
+    abcDEF-123_: none
+    debug: dartdevc
+    release: dart2js
+''',
+              sources);
+          expect(pubspec.webCompiler['abcDEF-123_'], equals(Compiler.none));
+          expect(pubspec.webCompiler['debug'], equals(Compiler.dartDevc));
+          expect(pubspec.webCompiler['release'], equals(Compiler.dart2JS));
+        });
+
+        test("throws if not a map", () {
+          expectPubspecException(
+              'web: {compiler: dartdevc}', (pubspec) => pubspec.webCompiler);
+          expectPubspecException(
+              'web: {compiler: [dartdevc]}', (pubspec) => pubspec.webCompiler);
+        });
+
+        test("throws if key is not a string", () {
+          expectPubspecException('web: {compiler: {123: dartdevc}}',
+              (pubspec) => pubspec.webCompiler);
+        });
+
+        test("throws if a value is not a supported compiler", () {
+          expectPubspecException('web: {compiler: {debug: frog}}',
+              (pubspec) => pubspec.webCompiler);
+        });
+
+        test("throws if the value is null", () {
+          expectPubspecException(
+              'web: {compiler: {debug: }}', (pubspec) => pubspec.webCompiler);
+        });
+      });
+    });
   });
 }
diff --git a/test/serve/utils.dart b/test/serve/utils.dart
index add6e50..2e62ee4 100644
--- a/test/serve/utils.dart
+++ b/test/serve/utils.dart
@@ -157,7 +157,7 @@
     "--log-admin-url",
   ];
   if (compiler != null) {
-    pubArgs.add("--compiler=${compiler.name}");
+    pubArgs.add("--web-compiler=${compiler.name}");
   }
 
   if (args != null) pubArgs.addAll(args);