Idiomatic install & karma fixes, rules_nodejs 0.14.1 & bazel 0.17.1

Closes #288

PiperOrigin-RevId: 214834503
diff --git a/.circleci/bazel.rc b/.circleci/bazel.rc
index 93dad23..56cdacc 100644
--- a/.circleci/bazel.rc
+++ b/.circleci/bazel.rc
@@ -28,7 +28,7 @@
 # Limit Bazel to consuming 2560K of RAM
 build --local_resources=2560,1.0,1.0
 # Also limit Bazel's own JVM heap to stay within our 4G container limit
-startup --host_jvm_args=-Xmx2g
+startup --host_jvm_args=-Xmx3g
 # Since the default CircleCI container has only 4G, limiting the memory
 # is required to keep Bazel from exhausting the memory. These values
 # are determined experimentally. If the Bazel process crashes without
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9e5cc15..83d2cd0 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -9,8 +9,8 @@
 
 ## IMPORTANT
 # If you change the `docker_image` version, also change the `cache_key` suffix
-var_1: &docker_image angular/ngcontainer:0.4.0
-var_2: &cache_key rules_typescript-{{ checksum "yarn.lock" }}-0.4.0
+var_1: &docker_image angular/ngcontainer:0.6.0
+var_2: &cache_key rules_typescript-{{ checksum "yarn.lock" }}-0.6.0
 var_3: &setup-bazel-remote-cache
   run:
     name: Start up bazel remote cache proxy
@@ -72,8 +72,11 @@
       - restore_cache:
           key: *cache_key
       - run: bazel --bazelrc=/dev/null info release
-      - run: bazel --bazelrc=/dev/null build ...
-      - run: bazel --bazelrc=/dev/null test ...
+      # We cherry pick the memory utilization options from .circleci/bazel.rc here.
+      # Since the default CircleCI container has only 4G, limiting the memory
+      # is required to keep Bazel from exhausting the memory.
+      - run: bazel --bazelrc=/dev/null --host_jvm_args=-Xmx3g build ... --local_resources=2560,1.0,1.0
+      - run: bazel --bazelrc=/dev/null --host_jvm_args=-Xmx3g test ... --local_resources=2560,1.0,1.0
 
       - save_cache:
           key: *cache_key
@@ -109,7 +112,10 @@
       - run: .circleci/setup_cache.sh
       - run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc
       - *setup-bazel-remote-cache
-      - run: yarn skylint
+      # Disable skylint for now as we're on an older version that is not
+      # compatible with Bazel 0.17.1 and the newer version has deprecated checks
+      # that fail in this repo that can't be turned off
+      # - run: yarn skylint
 
 workflows:
   version: 2
diff --git a/.gitignore b/.gitignore
index f48f047..b19e31d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,7 +2,7 @@
 node_modules
 /bazel-*
 /internal/e2e/package_karma/bazel-*
-/internal/e2e/package_typescript/bazel-*
+/internal/e2e/package_typescript_*/bazel-*
 /internal/e2e/ts_auto_deps/bazel-*
 
 internal/e2e/ts_auto_deps/simple/BUILD
diff --git a/BUILD.bazel b/BUILD.bazel
index 1b27e94..7ef857b 100644
--- a/BUILD.bazel
+++ b/BUILD.bazel
@@ -55,20 +55,6 @@
 
 load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
 
-# A nodejs_binary for karma/karma to use by default in ts_web_test &
-# ts_web_test_suite that depends on @npm//:@bazel/karma instead of the
-# output of the //internal/karma/karma_concat_js ts_library rule. This
-# default is for downstream users that depend on the @bazel/karma npm
-# package. The generated @npm//:karma/karma target does not work
-# as it does not have the additional data dependencies required.
-nodejs_binary(
-    name = "karma/karma",
-    data = ["@npm//:@bazel/karma"],
-    entry_point = "karma/bin/karma",
-    install_source_map_support = False,
-    visibility = ["//visibility:public"],
-)
-
 # A nodejs_binary for @bazel/typescript/tsc_wrapped to use by default in
 # ts_library that depends on @npm//:@bazel/typescript instead of the
 # output of the //internal/tsc_wrapped ts_library rule. This
diff --git a/examples/protocol_buffers/BUILD.bazel b/examples/protocol_buffers/BUILD.bazel
index c9da1ed..63e3289 100644
--- a/examples/protocol_buffers/BUILD.bazel
+++ b/examples/protocol_buffers/BUILD.bazel
@@ -43,7 +43,7 @@
     bootstrap = ["@build_bazel_rules_typescript//:protobufjs_bootstrap_scripts"],
     browsers = [
         "@io_bazel_rules_webtesting//browsers:chromium-local",
-        # TODO(gregmagolan): re-enable once `target_wrapped_test.conf.js does not exist!` issue resolved
+        # TODO(gregmagolan): re-enable once `Cannot find module 'Firefox.app/Contents/MacOS/firefox'` issue resolved
         # "@io_bazel_rules_webtesting//browsers:firefox-local",
     ],
     deps = ["test_lib"],
diff --git a/examples/testing/BUILD.bazel b/examples/testing/BUILD.bazel
index d732577..ba21a1b 100644
--- a/examples/testing/BUILD.bazel
+++ b/examples/testing/BUILD.bazel
@@ -21,7 +21,7 @@
     name = "testing",
     browsers = [
         "@io_bazel_rules_webtesting//browsers:chromium-local",
-        # TODO(gregmagolan): re-enable once `target_wrapped_test.conf.js does not exist!` issue resolved
+        # TODO(gregmagolan): re-enable once `Cannot find module 'Firefox.app/Contents/MacOS/firefox'` issue resolved
         # "@io_bazel_rules_webtesting//browsers:firefox-local",
     ],
     static_files = [
diff --git a/internal/common/tsconfig.bzl b/internal/common/tsconfig.bzl
index ed4fd37..fc9467f 100644
--- a/internal/common/tsconfig.bzl
+++ b/internal/common/tsconfig.bzl
@@ -50,6 +50,7 @@
       extra_root_dirs: Extra root dirs to be passed to tsc_wrapped.
       module_path_prefixes: additional locations to resolve modules
       module_roots: standard locations to resolve modules
+      node_modules_root: the node_modules root path
       skip_goog_scheme_deps_checking: whether imports from 'goog:*' should be strict deps checked
 
     Returns:
diff --git a/internal/e2e/default_tsconfig_test.js b/internal/e2e/default_tsconfig_test.js
index def6e2e..76af246 100644
--- a/internal/e2e/default_tsconfig_test.js
+++ b/internal/e2e/default_tsconfig_test.js
@@ -24,9 +24,9 @@
 const WORKSPACE_BOILERPLATE = `
 http_archive(
     name = "build_bazel_rules_nodejs",
-    urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.14.0.zip"],
-    strip_prefix = "rules_nodejs-0.14.0",
-    sha256 = "0e39999df9bf8c6fce46629457edb8c0073ad68244483339af578d83bf4fb794",
+    urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.14.1.zip"],
+    strip_prefix = "rules_nodejs-0.14.1",
+    sha256 = "813eb51733d3632f456f3bb581d940ed64e80dab417595c93bf5ad19079898e2",
 )
 http_archive(
     name = "bazel_skylib",
diff --git a/internal/e2e/package_karma/BUILD.bazel b/internal/e2e/package_karma/BUILD.bazel
index 392f177..db0937d 100644
--- a/internal/e2e/package_karma/BUILD.bazel
+++ b/internal/e2e/package_karma/BUILD.bazel
@@ -19,7 +19,7 @@
     srcs = glob(["*.js"]),
     browsers = [
         "@io_bazel_rules_webtesting//browsers:chromium-local",
-        # TODO(gregmagolan): re-enable once `target_wrapped_test.conf.js does not exist!` issue resolved
+        # TODO(gregmagolan): re-enable once `Cannot find module 'Firefox.app/Contents/MacOS/firefox'` issue resolved
         # "@io_bazel_rules_webtesting//browsers:firefox-local",
     ],
 )
diff --git a/internal/e2e/package_karma/README.md b/internal/e2e/package_karma/README.md
new file mode 100644
index 0000000..2dfa4e2
--- /dev/null
+++ b/internal/e2e/package_karma/README.md
@@ -0,0 +1,5 @@
+# Testing karma dependency
+
+A karma 3.0.0 dependency is here to verify that a user's karma dependency doesn't interfere with
+the ts_web_test_suite rule which depends on a transitive dependency in @bazel/karma on a fork
+of karma.
diff --git a/internal/e2e/package_karma/package.json b/internal/e2e/package_karma/package.json
index 24037ae..f91e5bb 100644
--- a/internal/e2e/package_karma/package.json
+++ b/internal/e2e/package_karma/package.json
@@ -1,5 +1,6 @@
 {
   "dependencies": {
-    "@bazel/karma": "file:../build_bazel_rules_typescript/bazel-bin/internal/karma/npm_package"
+    "@bazel/karma": "file:../build_bazel_rules_typescript/bazel-bin/internal/karma/npm_package",
+    "karma": "3.0.0"
   }
 }
diff --git a/internal/e2e/package_karma/yarn.lock b/internal/e2e/package_karma/yarn.lock
index 9700aff..e02c99f 100644
--- a/internal/e2e/package_karma/yarn.lock
+++ b/internal/e2e/package_karma/yarn.lock
@@ -3,7 +3,7 @@
 
 
 "@bazel/karma@file:../build_bazel_rules_typescript/bazel-bin/internal/karma/npm_package":
-  version "0.17.0-7-g5bd7ccc"
+  version "0.18.0-2-ga9643ab"
   dependencies:
     jasmine-core "2.8.0"
     karma alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a
@@ -83,6 +83,13 @@
     micromatch "^2.1.5"
     normalize-path "^2.0.0"
 
+anymatch@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+  dependencies:
+    micromatch "^3.1.4"
+    normalize-path "^2.1.1"
+
 aproba@^1.0.3:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
@@ -349,7 +356,7 @@
     preserve "^0.2.0"
     repeat-element "^1.1.2"
 
-braces@^2.3.1:
+braces@^2.3.0, braces@^2.3.1:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
   dependencies:
@@ -461,11 +468,30 @@
   optionalDependencies:
     fsevents "^1.0.0"
 
+chokidar@^2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26"
+  dependencies:
+    anymatch "^2.0.0"
+    async-each "^1.0.0"
+    braces "^2.3.0"
+    glob-parent "^3.1.0"
+    inherits "^2.0.1"
+    is-binary-path "^1.0.0"
+    is-glob "^4.0.0"
+    lodash.debounce "^4.0.8"
+    normalize-path "^2.1.1"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.0.0"
+    upath "^1.0.5"
+  optionalDependencies:
+    fsevents "^1.2.2"
+
 chownr@^1.0.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494"
 
-circular-json@^0.5.4:
+circular-json@^0.5.4, circular-json@^0.5.5:
   version "0.5.7"
   resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.7.tgz#b8be478d72ea58c7eeda26bf1cf1fba43d188842"
 
@@ -747,6 +773,22 @@
     xmlhttprequest-ssl "~1.5.4"
     yeast "0.1.2"
 
+engine.io-client@~3.2.0:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.2.1.tgz#6f54c0475de487158a1a7c77d10178708b6add36"
+  dependencies:
+    component-emitter "1.2.1"
+    component-inherit "0.0.3"
+    debug "~3.1.0"
+    engine.io-parser "~2.1.1"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    ws "~3.3.1"
+    xmlhttprequest-ssl "~1.5.4"
+    yeast "0.1.2"
+
 engine.io-parser@~2.1.0, engine.io-parser@~2.1.1:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.2.tgz#4c0f4cff79aaeecbbdcfdea66a823c6085409196"
@@ -770,6 +812,17 @@
   optionalDependencies:
     uws "~9.14.0"
 
+engine.io@~3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.2.0.tgz#54332506f42f2edc71690d2f2a42349359f3bf7d"
+  dependencies:
+    accepts "~1.3.4"
+    base64id "1.0.0"
+    cookie "0.3.1"
+    debug "~3.1.0"
+    engine.io-parser "~2.1.0"
+    ws "~3.3.1"
+
 ent@~2.2.0:
   version "2.2.0"
   resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d"
@@ -1021,7 +1074,7 @@
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
 
-fsevents@^1.0.0:
+fsevents@^1.0.0, fsevents@^1.2.2:
   version "1.2.4"
   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.4.tgz#f41dcb1af2582af3692da36fc55cbd8e1041c426"
   dependencies:
@@ -1094,6 +1147,13 @@
   dependencies:
     is-glob "^2.0.0"
 
+glob-parent@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+  dependencies:
+    is-glob "^3.1.0"
+    path-dirname "^1.0.0"
+
 glob@^7.0.0, glob@^7.0.5, glob@^7.1.1:
   version "7.1.3"
   resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1"
@@ -1405,6 +1465,10 @@
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
 
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+
 is-fullwidth-code-point@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb"
@@ -1421,6 +1485,18 @@
   dependencies:
     is-extglob "^1.0.0"
 
+is-glob@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+  dependencies:
+    is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
+  dependencies:
+    is-extglob "^2.1.1"
+
 is-my-ip-valid@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz#7b351b8e8edd4d3995d4d066680e664d94696824"
@@ -1588,6 +1664,38 @@
   dependencies:
     graceful-fs "^4.1.2"
 
+karma@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/karma/-/karma-3.0.0.tgz#6da83461a8a28d8224575c3b5b874e271b4730c3"
+  dependencies:
+    bluebird "^3.3.0"
+    body-parser "^1.16.1"
+    chokidar "^2.0.3"
+    colors "^1.1.0"
+    combine-lists "^1.0.0"
+    connect "^3.6.0"
+    core-js "^2.2.0"
+    di "^0.0.1"
+    dom-serialize "^2.2.0"
+    expand-braces "^0.1.1"
+    glob "^7.1.1"
+    graceful-fs "^4.1.2"
+    http-proxy "^1.13.0"
+    isbinaryfile "^3.0.0"
+    lodash "^4.17.4"
+    log4js "^3.0.0"
+    mime "^2.3.1"
+    minimatch "^3.0.2"
+    optimist "^0.6.1"
+    qjobs "^1.1.4"
+    range-parser "^1.2.0"
+    rimraf "^2.6.0"
+    safe-buffer "^5.0.1"
+    socket.io "2.1.1"
+    source-map "^0.6.1"
+    tmp "0.0.33"
+    useragent "2.2.1"
+
 karma@alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a:
   version "1.7.1"
   resolved "https://codeload.github.com/alexeagle/karma/tar.gz/fa1a84ac881485b5657cb669e9b4e5da77b79f0a"
@@ -1669,6 +1777,10 @@
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/libqp/-/libqp-1.1.0.tgz#f5e6e06ad74b794fb5b5b66988bf728ef1dedbe8"
 
+lodash.debounce@^4.0.8:
+  version "4.0.8"
+  resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
+
 lodash@4.17.10:
   version "4.17.10"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@@ -1696,6 +1808,16 @@
     redis "^2.7.1"
     slack-node "~0.2.0"
 
+log4js@^3.0.0:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/log4js/-/log4js-3.0.5.tgz#b80146bfebad68b430d4f3569556d8a6edfef303"
+  dependencies:
+    circular-json "^0.5.5"
+    date-format "^1.2.0"
+    debug "^3.1.0"
+    rfdc "^1.1.2"
+    streamroller "0.7.0"
+
 loggly@^1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/loggly/-/loggly-1.1.1.tgz#0a0fc1d3fa3a5ec44fdc7b897beba2a4695cebee"
@@ -1704,6 +1826,10 @@
     request "2.75.x"
     timespan "2.3.x"
 
+lru-cache@2.2.x:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d"
+
 lru-cache@4.1.x, lru-cache@^4.1.2:
   version "4.1.3"
   resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.3.tgz#a1175cf3496dfc8436c156c334b4955992bce69c"
@@ -1768,7 +1894,7 @@
     parse-glob "^3.0.4"
     regex-cache "^0.4.2"
 
-micromatch@^3.1.10:
+micromatch@^3.1.10, micromatch@^3.1.4:
   version "3.1.10"
   resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
   dependencies:
@@ -1800,6 +1926,10 @@
   version "1.6.0"
   resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
 
+mime@^2.3.1:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.3.1.tgz#b1621c54d63b97c47d3cfe7f7215f7d64517c369"
+
 minimatch@^3.0.2, minimatch@^3.0.4:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -1963,7 +2093,7 @@
     abbrev "1"
     osenv "^0.1.4"
 
-normalize-path@^2.0.0, normalize-path@^2.0.1:
+normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1:
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
   dependencies:
@@ -2137,6 +2267,10 @@
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
 
+path-dirname@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+
 path-is-absolute@^1.0.0:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
@@ -2454,6 +2588,10 @@
   version "0.1.15"
   resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
 
+rfdc@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.1.2.tgz#e6e72d74f5dc39de8f538f65e00c36c18018e349"
+
 rimraf@^2.5.4, rimraf@^2.6.0, rimraf@^2.6.1:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
@@ -2610,6 +2748,25 @@
     socket.io-parser "~3.1.1"
     to-array "0.1.4"
 
+socket.io-client@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.1.1.tgz#dcb38103436ab4578ddb026638ae2f21b623671f"
+  dependencies:
+    backo2 "1.0.2"
+    base64-arraybuffer "0.1.5"
+    component-bind "1.0.0"
+    component-emitter "1.2.1"
+    debug "~3.1.0"
+    engine.io-client "~3.2.0"
+    has-binary2 "~1.0.2"
+    has-cors "1.1.0"
+    indexof "0.0.1"
+    object-component "0.0.3"
+    parseqs "0.0.5"
+    parseuri "0.0.5"
+    socket.io-parser "~3.2.0"
+    to-array "0.1.4"
+
 socket.io-parser@~3.1.1:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.1.3.tgz#ed2da5ee79f10955036e3da413bfd7f1e4d86c8e"
@@ -2619,6 +2776,14 @@
     has-binary2 "~1.0.2"
     isarray "2.0.1"
 
+socket.io-parser@~3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.2.0.tgz#e7c6228b6aa1f814e6148aea325b51aa9499e077"
+  dependencies:
+    component-emitter "1.2.1"
+    debug "~3.1.0"
+    isarray "2.0.1"
+
 socket.io@2.0.4:
   version "2.0.4"
   resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.0.4.tgz#c1a4590ceff87ecf13c72652f046f716b29e6014"
@@ -2629,6 +2794,17 @@
     socket.io-client "2.0.4"
     socket.io-parser "~3.1.1"
 
+socket.io@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.1.1.tgz#a069c5feabee3e6b214a75b40ce0652e1cfb9980"
+  dependencies:
+    debug "~3.1.0"
+    engine.io "~3.2.0"
+    has-binary2 "~1.0.2"
+    socket.io-adapter "~1.1.0"
+    socket.io-client "2.1.1"
+    socket.io-parser "~3.2.0"
+
 socks-proxy-agent@^4.0.1:
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.1.tgz#5936bf8b707a993079c6f37db2091821bffa6473"
@@ -2906,6 +3082,10 @@
     has-value "^0.3.1"
     isobject "^3.0.0"
 
+upath@^1.0.5:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.0.tgz#35256597e46a581db4793d0ce47fa9aebfc9fabd"
+
 urix@^0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
@@ -2914,6 +3094,13 @@
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
 
+useragent@2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.2.1.tgz#cf593ef4f2d175875e8bb658ea92e18a4fd06d8e"
+  dependencies:
+    lru-cache "2.2.x"
+    tmp "0.0.x"
+
 useragent@^2.1.12:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972"
diff --git a/internal/e2e/package_typescript_2.7/BUILD.bazel b/internal/e2e/package_typescript_2.7/BUILD.bazel
index 6c6528d..ebf2da6 100644
--- a/internal/e2e/package_typescript_2.7/BUILD.bazel
+++ b/internal/e2e/package_typescript_2.7/BUILD.bazel
@@ -18,9 +18,6 @@
 ts_library(
     name = "main",
     srcs = ["main.ts"],
-    deps = [
-        "@npm//:@types/node",
-    ],
 )
 
 ts_library(
@@ -30,6 +27,8 @@
     deps = [
         ":main",
         "@npm//:@types/jasmine",
+        "@npm//:@types/node",
+        "@npm//:@bazel/typescript",
     ],
 )
 
diff --git a/internal/e2e/package_typescript_2.7/main.spec.ts b/internal/e2e/package_typescript_2.7/main.spec.ts
index 534605a..790b562 100644
--- a/internal/e2e/package_typescript_2.7/main.spec.ts
+++ b/internal/e2e/package_typescript_2.7/main.spec.ts
@@ -4,4 +4,23 @@
   it('should compile and run with @bazel/typescript npm package', () => {
     expect(main.test()).toEqual('test');
   });
+
+  it('should successfully require @bazel/typescript', () => {
+    try {
+      const {debug} = require('@bazel/typescript');
+      debug('test');
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
+
+  it('should successfully require built-in node module \'os\'', () => {
+    try {
+      const os = require('os');
+      console.log('Platform: ' + os.platform());
+      console.log('Architecture: ' + os.arch());
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
 });
diff --git a/internal/e2e/package_typescript_2.7/main.ts b/internal/e2e/package_typescript_2.7/main.ts
index 684bee0..36f3fab 100644
--- a/internal/e2e/package_typescript_2.7/main.ts
+++ b/internal/e2e/package_typescript_2.7/main.ts
@@ -1,8 +1,3 @@
-import * as os from 'os';
-
-console.log('Platform: ' + os.platform());
-console.log('Architecture: ' + os.arch());
-
 export function test() {
   return 'test';
 }
\ No newline at end of file
diff --git a/internal/e2e/package_typescript_2.7/tsconfig.json.oss b/internal/e2e/package_typescript_2.7/tsconfig.json
similarity index 100%
rename from internal/e2e/package_typescript_2.7/tsconfig.json.oss
rename to internal/e2e/package_typescript_2.7/tsconfig.json
diff --git a/internal/e2e/package_typescript_2.8/BUILD.bazel b/internal/e2e/package_typescript_2.8/BUILD.bazel
index 6c6528d..ebf2da6 100644
--- a/internal/e2e/package_typescript_2.8/BUILD.bazel
+++ b/internal/e2e/package_typescript_2.8/BUILD.bazel
@@ -18,9 +18,6 @@
 ts_library(
     name = "main",
     srcs = ["main.ts"],
-    deps = [
-        "@npm//:@types/node",
-    ],
 )
 
 ts_library(
@@ -30,6 +27,8 @@
     deps = [
         ":main",
         "@npm//:@types/jasmine",
+        "@npm//:@types/node",
+        "@npm//:@bazel/typescript",
     ],
 )
 
diff --git a/internal/e2e/package_typescript_2.8/main.spec.ts b/internal/e2e/package_typescript_2.8/main.spec.ts
index 534605a..790b562 100644
--- a/internal/e2e/package_typescript_2.8/main.spec.ts
+++ b/internal/e2e/package_typescript_2.8/main.spec.ts
@@ -4,4 +4,23 @@
   it('should compile and run with @bazel/typescript npm package', () => {
     expect(main.test()).toEqual('test');
   });
+
+  it('should successfully require @bazel/typescript', () => {
+    try {
+      const {debug} = require('@bazel/typescript');
+      debug('test');
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
+
+  it('should successfully require built-in node module \'os\'', () => {
+    try {
+      const os = require('os');
+      console.log('Platform: ' + os.platform());
+      console.log('Architecture: ' + os.arch());
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
 });
diff --git a/internal/e2e/package_typescript_2.8/main.ts b/internal/e2e/package_typescript_2.8/main.ts
index 684bee0..36f3fab 100644
--- a/internal/e2e/package_typescript_2.8/main.ts
+++ b/internal/e2e/package_typescript_2.8/main.ts
@@ -1,8 +1,3 @@
-import * as os from 'os';
-
-console.log('Platform: ' + os.platform());
-console.log('Architecture: ' + os.arch());
-
 export function test() {
   return 'test';
 }
\ No newline at end of file
diff --git a/internal/e2e/package_typescript_2.8/tsconfig.json.oss b/internal/e2e/package_typescript_2.8/tsconfig.json
similarity index 100%
rename from internal/e2e/package_typescript_2.8/tsconfig.json.oss
rename to internal/e2e/package_typescript_2.8/tsconfig.json
diff --git a/internal/e2e/package_typescript_2.9/BUILD.bazel b/internal/e2e/package_typescript_2.9/BUILD.bazel
index 6c6528d..ebf2da6 100644
--- a/internal/e2e/package_typescript_2.9/BUILD.bazel
+++ b/internal/e2e/package_typescript_2.9/BUILD.bazel
@@ -18,9 +18,6 @@
 ts_library(
     name = "main",
     srcs = ["main.ts"],
-    deps = [
-        "@npm//:@types/node",
-    ],
 )
 
 ts_library(
@@ -30,6 +27,8 @@
     deps = [
         ":main",
         "@npm//:@types/jasmine",
+        "@npm//:@types/node",
+        "@npm//:@bazel/typescript",
     ],
 )
 
diff --git a/internal/e2e/package_typescript_2.9/main.spec.ts b/internal/e2e/package_typescript_2.9/main.spec.ts
index 534605a..790b562 100644
--- a/internal/e2e/package_typescript_2.9/main.spec.ts
+++ b/internal/e2e/package_typescript_2.9/main.spec.ts
@@ -4,4 +4,23 @@
   it('should compile and run with @bazel/typescript npm package', () => {
     expect(main.test()).toEqual('test');
   });
+
+  it('should successfully require @bazel/typescript', () => {
+    try {
+      const {debug} = require('@bazel/typescript');
+      debug('test');
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
+
+  it('should successfully require built-in node module \'os\'', () => {
+    try {
+      const os = require('os');
+      console.log('Platform: ' + os.platform());
+      console.log('Architecture: ' + os.arch());
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
 });
diff --git a/internal/e2e/package_typescript_2.9/main.ts b/internal/e2e/package_typescript_2.9/main.ts
index 684bee0..36f3fab 100644
--- a/internal/e2e/package_typescript_2.9/main.ts
+++ b/internal/e2e/package_typescript_2.9/main.ts
@@ -1,8 +1,3 @@
-import * as os from 'os';
-
-console.log('Platform: ' + os.platform());
-console.log('Architecture: ' + os.arch());
-
 export function test() {
   return 'test';
 }
\ No newline at end of file
diff --git a/internal/e2e/package_typescript_2.9/tsconfig.json.oss b/internal/e2e/package_typescript_2.9/tsconfig.json
similarity index 100%
rename from internal/e2e/package_typescript_2.9/tsconfig.json.oss
rename to internal/e2e/package_typescript_2.9/tsconfig.json
diff --git a/internal/e2e/package_typescript_3.0/BUILD.bazel b/internal/e2e/package_typescript_3.0/BUILD.bazel
index 6c6528d..ebf2da6 100644
--- a/internal/e2e/package_typescript_3.0/BUILD.bazel
+++ b/internal/e2e/package_typescript_3.0/BUILD.bazel
@@ -18,9 +18,6 @@
 ts_library(
     name = "main",
     srcs = ["main.ts"],
-    deps = [
-        "@npm//:@types/node",
-    ],
 )
 
 ts_library(
@@ -30,6 +27,8 @@
     deps = [
         ":main",
         "@npm//:@types/jasmine",
+        "@npm//:@types/node",
+        "@npm//:@bazel/typescript",
     ],
 )
 
diff --git a/internal/e2e/package_typescript_3.0/main.spec.ts b/internal/e2e/package_typescript_3.0/main.spec.ts
index 534605a..790b562 100644
--- a/internal/e2e/package_typescript_3.0/main.spec.ts
+++ b/internal/e2e/package_typescript_3.0/main.spec.ts
@@ -4,4 +4,23 @@
   it('should compile and run with @bazel/typescript npm package', () => {
     expect(main.test()).toEqual('test');
   });
+
+  it('should successfully require @bazel/typescript', () => {
+    try {
+      const {debug} = require('@bazel/typescript');
+      debug('test');
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
+
+  it('should successfully require built-in node module \'os\'', () => {
+    try {
+      const os = require('os');
+      console.log('Platform: ' + os.platform());
+      console.log('Architecture: ' + os.arch());
+    } catch (e) {
+      fail(e.toString())
+    }
+  });
 });
diff --git a/internal/e2e/package_typescript_3.0/main.ts b/internal/e2e/package_typescript_3.0/main.ts
index 684bee0..36f3fab 100644
--- a/internal/e2e/package_typescript_3.0/main.ts
+++ b/internal/e2e/package_typescript_3.0/main.ts
@@ -1,8 +1,3 @@
-import * as os from 'os';
-
-console.log('Platform: ' + os.platform());
-console.log('Architecture: ' + os.arch());
-
 export function test() {
   return 'test';
 }
\ No newline at end of file
diff --git a/internal/e2e/package_typescript_3.0/tsconfig.json.oss b/internal/e2e/package_typescript_3.0/tsconfig.json
similarity index 100%
rename from internal/e2e/package_typescript_3.0/tsconfig.json.oss
rename to internal/e2e/package_typescript_3.0/tsconfig.json
diff --git a/internal/e2e/package_typescript_karma/BUILD.bazel b/internal/e2e/package_typescript_karma/BUILD.bazel
index f823fc4..26eeddb 100644
--- a/internal/e2e/package_typescript_karma/BUILD.bazel
+++ b/internal/e2e/package_typescript_karma/BUILD.bazel
@@ -33,7 +33,7 @@
     name = "testing",
     browsers = [
         "@io_bazel_rules_webtesting//browsers:chromium-local",
-        # TODO(gregmagolan): re-enable once `target_wrapped_test.conf.js does not exist!` issue resolved
+        # TODO(gregmagolan): re-enable once `Cannot find module 'Firefox.app/Contents/MacOS/firefox'` issue resolved
         # "@io_bazel_rules_webtesting//browsers:firefox-local",
     ],
     deps = [
diff --git a/internal/e2e/package_typescript_karma/tsconfig.json.oss b/internal/e2e/package_typescript_karma/tsconfig.json
similarity index 100%
rename from internal/e2e/package_typescript_karma/tsconfig.json.oss
rename to internal/e2e/package_typescript_karma/tsconfig.json
diff --git a/internal/e2e/package_typescript_karma/yarn.lock b/internal/e2e/package_typescript_karma/yarn.lock
index 02d4b5f..95dd936 100644
--- a/internal/e2e/package_typescript_karma/yarn.lock
+++ b/internal/e2e/package_typescript_karma/yarn.lock
@@ -3,7 +3,7 @@
 
 
 "@bazel/karma@file:../build_bazel_rules_typescript/bazel-bin/internal/karma/npm_package":
-  version "0.17.0-7-g5bd7ccc"
+  version "0.18.0-2-ga9643ab"
   dependencies:
     jasmine-core "2.8.0"
     karma alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a
@@ -17,7 +17,7 @@
     tmp "0.0.33"
 
 "@bazel/typescript@file:../build_bazel_rules_typescript/bazel-bin/internal/npm_package":
-  version "0.17.0-7-g5bd7ccc"
+  version "0.18.0-2-ga9643ab"
   dependencies:
     protobufjs "5.0.0"
     source-map-support "0.5.9"
diff --git a/internal/karma/BUILD.bazel b/internal/karma/BUILD.bazel
index 73db765..0bb2b94 100644
--- a/internal/karma/BUILD.bazel
+++ b/internal/karma/BUILD.bazel
@@ -61,6 +61,7 @@
     srcs = [
         "README.md",
         "package.json",
+        "karma.js",
     ],
     deps = [
         ":check_version_copy",
diff --git a/internal/karma/karma.conf.js b/internal/karma/karma.conf.js
index 9edeac0..81db6d0 100644
--- a/internal/karma/karma.conf.js
+++ b/internal/karma/karma.conf.js
@@ -1,80 +1,93 @@
 // Karma configuration
 // GENERATED BY Bazel
-const path = require('path');
-const fs = require('fs');
-const tmp = require('tmp');
+try
+{
+  const fs = require('fs');
+  const tmp = require('tmp');
 
-const browsers = [];
-let customLaunchers = null;
+  const browsers = [];
+  let customLaunchers = null;
 
-// WEB_TEST_METADATA is configured in rules_webtesting based on value
-// of the browsers attribute passed to ts_web_test_suite
-// We setup the karma configuration based on the values in this object
-if (process.env['WEB_TEST_METADATA']) {
-  const webTestMetadata = require(process.env['WEB_TEST_METADATA']);
-  if (webTestMetadata['environment'] === 'sauce') {
-    // If a sauce labs browser is chosen for the test such as
-    // "@io_bazel_rules_webtesting//browsers/sauce:chrome-win10"
-    // than the 'environment' will equal 'sauce'.
-    // We expect that a SAUCE_USERNAME and SAUCE_ACCESS_KEY is available
-    // from the environment for this test to run
-    if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
-      console.error('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
-      process.exit(1);
+  // WEB_TEST_METADATA is configured in rules_webtesting based on value
+  // of the browsers attribute passed to ts_web_test_suite
+  // We setup the karma configuration based on the values in this object
+  if (process.env['WEB_TEST_METADATA']) {
+    const webTestMetadata = require(process.env['WEB_TEST_METADATA']);
+    if (webTestMetadata['environment'] === 'sauce') {
+      // If a sauce labs browser is chosen for the test such as
+      // "@io_bazel_rules_webtesting//browsers/sauce:chrome-win10"
+      // than the 'environment' will equal 'sauce'.
+      // We expect that a SAUCE_USERNAME and SAUCE_ACCESS_KEY is available
+      // from the environment for this test to run
+      if (!process.env.SAUCE_USERNAME || !process.env.SAUCE_ACCESS_KEY) {
+        console.error('Make sure the SAUCE_USERNAME and SAUCE_ACCESS_KEY environment variables are set.');
+        process.exit(1);
+      }
+      // 'capabilities' will specify the sauce labs configuration to use
+      const capabilities = webTestMetadata['capabilities'];
+      customLaunchers = {
+          'sauce': {
+          base: 'SauceLabs',
+          browserName: capabilities['browserName'],
+          platform: capabilities['platform'],
+          version: capabilities['version'],
+        }
+      };
+      browsers.push('sauce');
+    } else if (webTestMetadata['environment'] === 'local') {
+      // When a local chrome or firefox browser is chosen such as
+      // "@io_bazel_rules_webtesting//browsers:chromium-local" or
+      // "@io_bazel_rules_webtesting//browsers:firefox-local"
+      // then the 'environment' will equal 'local' and
+      // 'webTestFiles' will contain the path to the binary to use
+      webTestMetadata['webTestFiles'].forEach(webTestFiles => {
+        const webTestNamedFiles = webTestFiles['namedFiles'];
+        if (webTestNamedFiles['CHROMIUM']) {
+          // When karma is configured to use Chrome it will look for a CHROME_BIN
+          // environment variable.
+          process.env.CHROME_BIN = require.resolve(webTestNamedFiles['CHROMIUM']);
+          browsers.push(process.env['DISPLAY'] ? 'Chrome' : 'ChromeHeadless');
+        }
+        if (webTestNamedFiles['FIREFOX']) {
+          // When karma is configured to use Firefox it will look for a
+          // FIREFOX_BIN environment variable.
+          process.env.FIREFOX_BIN = require.resolve(webTestNamedFiles['FIREFOX']);
+          browsers.push(process.env['DISPLAY'] ? 'Firefox' : 'FirefoxHeadless');
+        }
+      });
+    } else {
+      console.warn(`Unknown WEB_TEST_METADATA environment '${webTestMetadata['environment']}'`);
     }
-    // 'capabilities' will specify the sauce labs configuration to use
-    const capabilities = webTestMetadata['capabilities'];
-    customLaunchers = {
-        'sauce': {
-        base: 'SauceLabs',
-        browserName: capabilities['browserName'],
-        platform: capabilities['platform'],
-        version: capabilities['version'],
-      }
-    };
-    browsers.push('sauce');
-  } else if (webTestMetadata['environment'] === 'local') {
-    // When a local chrome or firefox browser is chosen such as
-    // "@io_bazel_rules_webtesting//browsers:chromium-local" or
-    // "@io_bazel_rules_webtesting//browsers:firefox-local"
-    // then the 'environment' will equal 'local' and
-    // 'webTestFiles' will contain the path to the binary to use
-    webTestMetadata['webTestFiles'].forEach(webTestFiles => {
-      const webTestNamedFiles = webTestFiles['namedFiles'];
-      if (webTestNamedFiles['CHROMIUM']) {
-        // When karma is configured to use Chrome it will look for a CHROME_BIN
-        // environment variable.
-        process.env.CHROME_BIN = require.resolve(webTestNamedFiles['CHROMIUM']);
-        browsers.push(process.env['DISPLAY'] ? 'Chrome' : 'ChromeHeadless');
-      }
-      if (webTestNamedFiles['FIREFOX']) {
-        // When karma is configured to use Firefox it will look for a
-        // FIREFOX_BIN environment variable.
-        process.env.FIREFOX_BIN = require.resolve(webTestNamedFiles['FIREFOX']);
-        browsers.push(process.env['DISPLAY'] ? 'Firefox' : 'FirefoxHeadless');
-      }
-    });
-  } else {
-    console.warn(`Unknown WEB_TEST_METADATA environment '${webTestMetadata['environment']}'`);
   }
-}
 
-// Fallback to using the system local chrome if no valid browsers have been
-// configured above
-if (!browsers.length) {
-  console.warn('No browsers configured. Configuring Karma to use system Chrome.');
-  browsers.push(process.env['DISPLAY'] ? 'Chrome': 'ChromeHeadless');
-}
+  // Fallback to using the system local chrome if no valid browsers have been
+  // configured above
+  if (!browsers.length) {
+    console.warn('No browsers configured. Configuring Karma to use system Chrome.');
+    browsers.push(process.env['DISPLAY'] ? 'Chrome': 'ChromeHeadless');
+  }
 
-const proxies = {};
-const files = [
-  TMPL_bootstrap_files
-  TMPL_user_files
-].map(f => require.resolve(f));
+  const proxies = {};
+  const files = [
+    TMPL_bootstrap_files
+    TMPL_user_files
+  ].map(f => {
+    if (f.startsWith('NODE_MODULES/')) {
+      try {
+        // attempt to resolve in @bazel/karma nested node_modules first
+        return require.resolve(f.replace(/^NODE_MODULES\//, '@bazel/karma/node_modules/'));
+      } catch (e) {
+        // if that failed then attempt to resolve in root node_modules
+        return require.resolve(f.replace(/^NODE_MODULES\//, ''));
+      }
+    } else {
+      return require.resolve(f);
+    }
+  });
 
-// static files are added to the files array but
-// configured to not be included so karma-concat-js does
-// not included them in the bundle
+  // static files are added to the files array but
+  // configured to not be included so karma-concat-js does
+  // not included them in the bundle
   [TMPL_static_files].forEach((f) => {
     // In Windows, the runfile will probably not be symlinked. Se we need to
     // serve the real file through karma, and proxy calls to the expected file
@@ -198,3 +211,7 @@
 
     config.set(configuration);
   }
+} catch (e) {
+  console.error('Error in karma configuration', e.toString());
+  throw e;
+}
diff --git a/internal/karma/karma.js b/internal/karma/karma.js
new file mode 100644
index 0000000..2653ede
--- /dev/null
+++ b/internal/karma/karma.js
@@ -0,0 +1,3 @@
+#!/usr/bin/env node
+
+require('karma/lib/cli').run();
diff --git a/internal/karma/package.json b/internal/karma/package.json
index fdbdd5b..9380ca5 100644
--- a/internal/karma/package.json
+++ b/internal/karma/package.json
@@ -8,7 +8,11 @@
       "karma",
       "bazel"
   ],
+  "main": "./index.js",
   "typings": "./index.d.ts",
+  "bin": {
+    "karma": "./karma.js"
+  },
   "dependencies": {
     "jasmine-core": "2.8.0",
     "karma": "alexeagle/karma#fa1a84ac881485b5657cb669e9b4e5da77b79f0a",
diff --git a/internal/karma/ts_web_test.bzl b/internal/karma/ts_web_test.bzl
index 5c884ab..27df24e 100644
--- a/internal/karma/ts_web_test.bzl
+++ b/internal/karma/ts_web_test.bzl
@@ -23,7 +23,7 @@
 load("@io_bazel_rules_webtesting//web/internal:constants.bzl", "DEFAULT_WRAPPED_TEST_TAGS")
 
 _CONF_TMPL = "//internal/karma:karma.conf.js"
-_DEFAULT_KARMA_BIN = "@build_bazel_rules_typescript//:karma/karma"
+_DEFAULT_KARMA_BIN = "@npm//:@bazel/karma/karma"
 
 def _ts_web_test_impl(ctx):
     conf = ctx.actions.declare_file(
@@ -38,24 +38,25 @@
         elif hasattr(d, "files"):
             files += d.files
 
-    # The files in the bootstrap attribute come before the require.js support.
-    # Note that due to frameworks = ['jasmine'], a few scripts will come before
-    # the bootstrap entries:
-    # npm/node_modules/jasmine-core/lib/jasmine-core/jasmine.js
-    # npm/node_modules/karma-jasmine/lib/boot.js
-    # npm/node_modules/karma-jasmine/lib/adapter.js
-    # This is desired so that the bootstrap entries can patch jasmine, as zone.js does.
-    bootstrap_entries = [
-        expand_path_into_runfiles(ctx, f.short_path)
-        for f in ctx.files.bootstrap
-    ]
-
+    # Write the AMD names shim bootstrap file
     amd_names_shim = ctx.actions.declare_file(
         "_%s.amd_names_shim.js" % ctx.label.name,
         sibling = ctx.outputs.executable,
     )
     write_amd_names_shim(ctx.actions, amd_names_shim, ctx.attr.bootstrap)
 
+    # The files in the bootstrap attribute come before the require.js support.
+    # Note that due to frameworks = ['jasmine'], a few scripts will come before
+    # the bootstrap entries:
+    # jasmine-core/lib/jasmine-core/jasmine.js
+    # karma-jasmine/lib/boot.js
+    # karma-jasmine/lib/adapter.js
+    # This is desired so that the bootstrap entries can patch jasmine, as zone.js does.
+    bootstrap_entries = [
+        expand_path_into_runfiles(ctx, f.short_path)
+        for f in ctx.files.bootstrap
+    ]
+
     # Explicitly list the requirejs library files here, rather than use
     # `frameworks: ['requirejs']`
     # so that we control the script order, and the bootstrap files come before
@@ -63,9 +64,12 @@
     # That allows bootstrap files to have anonymous AMD modules, or to do some
     # polyfilling before test libraries load.
     # See https://github.com/karma-runner/karma/issues/699
+    # `NODE_MODULES/` is a prefix recogized by karma.conf.js to allow
+    # for a priority require of nested `@bazel/karma/node_modules` before
+    # looking in root node_modules.
     bootstrap_entries += [
-        "npm/node_modules/requirejs/require.js",
-        "npm/node_modules/karma-requirejs/lib/adapter.js",
+        "NODE_MODULES/requirejs/require.js",
+        "NODE_MODULES/karma-requirejs/lib/adapter.js",
         "/".join([ctx.workspace_name, amd_names_shim.short_path]),
     ]
 
diff --git a/internal/package.json b/internal/package.json
index 80c9cd2..1ac5e9c 100644
--- a/internal/package.json
+++ b/internal/package.json
@@ -8,6 +8,7 @@
       "typescript",
       "bazel"
   ],
+  "main": "./tsc_wrapped/index.js",
   "typings": "./tsc_wrapped/index.d.ts",
   "peerDependencies": {
     "typescript": ">=2.4.2"
diff --git a/internal/ts_repositories.bzl b/internal/ts_repositories.bzl
index 59042f2..a66a8f1 100644
--- a/internal/ts_repositories.bzl
+++ b/internal/ts_repositories.bzl
@@ -26,7 +26,8 @@
 
     # 0.14.0: @bazel_tools//tools/bash/runfiles is required
     # 0.15.0: "data" attributes don't need 'cfg = "data"'
-    check_bazel_version("0.15.0")
+    # 0.17.1: allow @ in package names is required for fine grained deps
+    check_bazel_version("0.17.1")
 
     go_repository(
         name = "com_github_kylelemons_godebug",
@@ -42,7 +43,8 @@
 
     # 0.11.3: node module resolution fixes & check_rules_nodejs_version
     # 0.14.0: fine grained npm dependencies support for ts_library
-    check_rules_nodejs_version("0.14.0")
+    # 0.14.1: fine grained npm dependencies fix for npm_install
+    check_rules_nodejs_version("0.14.1")
 
     # Included here for backward compatability for downstream repositories
     # that use @build_bazel_rules_typescript_tsc_wrapped_deps such as rxjs.
diff --git a/package.bzl b/package.bzl
index d42f979..066800c 100644
--- a/package.bzl
+++ b/package.bzl
@@ -38,9 +38,9 @@
     _maybe(
         http_archive,
         name = "build_bazel_rules_nodejs",
-        urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.14.0.zip"],
-        strip_prefix = "rules_nodejs-0.14.0",
-        sha256 = "0e39999df9bf8c6fce46629457edb8c0073ad68244483339af578d83bf4fb794",
+        urls = ["https://github.com/bazelbuild/rules_nodejs/archive/0.14.1.zip"],
+        strip_prefix = "rules_nodejs-0.14.1",
+        sha256 = "813eb51733d3632f456f3bb581d940ed64e80dab417595c93bf5ad19079898e2",
     )
 
     # ts_web_test depends on the web testing rules to provision browsers.