From 7220fbf6256516b38eee2315b996e900505db860 Mon Sep 17 00:00:00 2001
From: Greg Magolan <gmagolan@gmail.com>
Date: Wed, 22 May 2019 00:52:23 -0700
Subject: [PATCH] Fixes and get all tests passing (#480)

Also updates rollup_bundle entry_point and parcel example entry_point to labels
---
 e2e/jasmine/BUILD.bazel                       | 10 ---
 e2e/ts_library/some_module/BUILD.bazel        |  2 +-
 e2e/typescript_3.1/BUILD.bazel                | 23 +-----
 examples/app/BUILD.bazel                      |  2 +-
 examples/parcel/BUILD.bazel                   |  3 +-
 examples/parcel/parcel.bzl                    |  9 ++-
 examples/protocol_buffers/BUILD.bazel         |  2 +-
 examples/webapp/BUILD.bazel                   |  2 +-
 internal/common/collect_es6_sources.bzl       |  5 ++
 internal/e2e/rollup/BUILD.bazel               |  7 +-
 .../e2e/rollup_code_splitting/BUILD.bazel     |  7 +-
 .../additional_entry.spec.js                  |  3 +-
 .../goldens/bundle.min.es2015.js_             |  1 +
 .../bundle.min.js_}                           |  2 +-
 .../e2e/rollup_fine_grained_deps/BUILD.bazel  | 12 ++--
 internal/node/node.bzl                        | 61 +++++++++++++---
 internal/npm_install/BUILD.bazel              |  2 +-
 internal/rollup/rollup_bundle.bzl             | 72 ++++++++++++++++---
 internal/web_package/test/BUILD.bazel         |  3 +-
 internal/web_package/test2/BUILD.bazel        |  3 +-
 packages/create/BUILD.bazel                   |  2 +-
 packages/jasmine/BUILD.bazel                  |  2 +-
 packages/jasmine/src/jasmine_node_test.bzl    | 17 +++--
 packages/jasmine/test/BUILD.bazel             | 16 ++---
 packages/labs/package.json                    |  3 +
 packages/labs/webpack/BUILD.bazel             | 13 +++-
 packages/labs/webpack/src/BUILD.bazel         | 26 +------
 packages/labs/webpack/src/cli.ts              | 10 ++-
 packages/labs/webpack/src/webpack_bundle.bzl  |  2 +-
 packages/labs/webpack/test/BUILD.bazel        |  5 ++
 packages/typescript/WORKSPACE                 |  6 +-
 scripts/setup_examples_angular.sh             |  3 +-
 .../bazel_workspaces/a/BUILD.bazel            |  2 +-
 .../bazel_workspaces/a/subdir/BUILD.bazel     |  2 +-
 .../bazel_workspaces/b/BUILD.bazel            |  2 +-
 .../bazel_workspaces/b/subdir/BUILD.bazel     |  2 +-
 .../bazel_workspaces/package.json             |  2 +-
 yarn.lock                                     |  2 +-
 38 files changed, 210 insertions(+), 138 deletions(-)
 create mode 100755 internal/e2e/rollup_code_splitting/goldens/bundle.min.es2015.js_
 rename internal/e2e/rollup_code_splitting/{bundle-min_golden.js_ => goldens/bundle.min.js_} (61%)

diff --git a/e2e/jasmine/BUILD.bazel b/e2e/jasmine/BUILD.bazel
index 7bf44e81e0..6910dd20c9 100644
--- a/e2e/jasmine/BUILD.bazel
+++ b/e2e/jasmine/BUILD.bazel
@@ -3,10 +3,6 @@ load("@npm_bazel_jasmine//:index.bzl", "jasmine_node_test")
 jasmine_node_test(
     name = "test",
     srcs = ["test.spec.js"],
-    jasmine = "@npm_bazel_jasmine//:index.js",
-    deps = [
-        "@npm//@bazel/jasmine",
-    ],
 )
 
 jasmine_node_test(
@@ -14,9 +10,7 @@ jasmine_node_test(
     srcs = ["jasmine_shared_env_test.spec.js"],
     bootstrap = ["e2e_jasmine/jasmine_shared_env_bootstrap.js"],
     data = ["jasmine_shared_env_bootstrap.js"],
-    jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "@npm//@bazel/jasmine",
         "@npm//jasmine",
         "@npm//jasmine-core",
         "@npm//zone.js",
@@ -30,8 +24,4 @@ jasmine_node_test(
         "coverage_source.js",
     ],
     coverage = True,
-    jasmine = "@npm_bazel_jasmine//:index.js",
-    deps = [
-        "@npm//@bazel/jasmine",
-    ],
 )
diff --git a/e2e/ts_library/some_module/BUILD.bazel b/e2e/ts_library/some_module/BUILD.bazel
index 98e10c3163..ba8e7c3120 100644
--- a/e2e/ts_library/some_module/BUILD.bazel
+++ b/e2e/ts_library/some_module/BUILD.bazel
@@ -25,7 +25,7 @@ nodejs_binary(
         ":main",
         ":some_module",
     ],
-    entry_point = ":main.js",
+    entry_point = ":main.ts",
 )
 
 sh_test(
diff --git a/e2e/typescript_3.1/BUILD.bazel b/e2e/typescript_3.1/BUILD.bazel
index 0e1d3a76d0..68dc4174be 100644
--- a/e2e/typescript_3.1/BUILD.bazel
+++ b/e2e/typescript_3.1/BUILD.bazel
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary", "rollup_bundle")
+load("@build_bazel_rules_nodejs//:defs.bzl", "rollup_bundle")
 load("@npm_bazel_jasmine//:index.bzl", "jasmine_node_test")
 load("@npm_bazel_typescript//:index.bzl", "ts_library")
 
@@ -57,26 +57,9 @@ jasmine_node_test(
     ],
 )
 
-nodejs_binary(
-    name = "main_js",
-    data = [
-        ":main",
-    ],
-    entry_point = "e2e_typescript_3_1/main.js",
-)
-
-nodejs_binary(
-    name = "main_js_sm",
-    data = [
-        ":main",
-        "@npm//source-map-support",
-    ],
-    entry_point = "e2e_typescript_3_1/main.js",
-)
-
 rollup_bundle(
     name = "bundle",
-    entry_point = "main",
+    entry_point = ":main.ts",
     deps = [
         ":main",
     ],
@@ -84,7 +67,7 @@ rollup_bundle(
 
 rollup_bundle(
     name = "bundle_sm",
-    entry_point = "main",
+    entry_point = ":main.ts",
     deps = [
         ":main",
         "@npm//source-map-support",
diff --git a/examples/app/BUILD.bazel b/examples/app/BUILD.bazel
index 9c7880d4f7..95501893d0 100644
--- a/examples/app/BUILD.bazel
+++ b/examples/app/BUILD.bazel
@@ -19,7 +19,7 @@ ts_devserver(
 
 rollup_bundle(
     name = "bundle",
-    entry_point = "examples_app/app",
+    entry_point = ":app.ts",
     deps = [":app"],
 )
 
diff --git a/examples/parcel/BUILD.bazel b/examples/parcel/BUILD.bazel
index 18112820f1..b60327f406 100644
--- a/examples/parcel/BUILD.bazel
+++ b/examples/parcel/BUILD.bazel
@@ -5,9 +5,8 @@ parcel(
     name = "bundle",
     srcs = [
         "bar.js",
-        "foo.js",
     ],
-    entry_point = "foo.js",
+    entry_point = ":foo.js",
 )
 
 jasmine_node_test(
diff --git a/examples/parcel/parcel.bzl b/examples/parcel/parcel.bzl
index 899da32e96..d1eb224cd6 100644
--- a/examples/parcel/parcel.bzl
+++ b/examples/parcel/parcel.bzl
@@ -27,12 +27,12 @@ def _parcel_impl(ctx):
     """
 
     # Options documented at https://parceljs.org/cli.html
-    args = ["build", ctx.attr.entry_point]
+    args = ["build", ctx.file.entry_point.short_path]
     args += ["--out-dir", ctx.outputs.bundle.dirname]
     args += ["--out-file", ctx.outputs.bundle.basename]
 
     ctx.actions.run(
-        inputs = ctx.files.srcs,
+        inputs = ctx.files.srcs + [ctx.file.entry_point],
         executable = ctx.executable.parcel,
         outputs = [ctx.outputs.bundle, ctx.outputs.sourcemap],
         arguments = args,
@@ -44,7 +44,10 @@ parcel = rule(
     implementation = _parcel_impl,
     attrs = {
         "srcs": attr.label_list(allow_files = True),
-        "entry_point": attr.string(mandatory = True),
+        "entry_point": attr.label(
+            allow_single_file = True,
+            mandatory = True,
+        ),
         "parcel": attr.label(
             # This default assumes that users name their install "npm"
             default = Label("@npm//parcel-bundler/bin:parcel"),
diff --git a/examples/protocol_buffers/BUILD.bazel b/examples/protocol_buffers/BUILD.bazel
index 1d06f97204..34c370b050 100644
--- a/examples/protocol_buffers/BUILD.bazel
+++ b/examples/protocol_buffers/BUILD.bazel
@@ -70,7 +70,7 @@ ts_devserver(
 # Test for production mode
 rollup_bundle(
     name = "bundle",
-    entry_point = "examples_protocol_buffers/app",
+    entry_point = ":app.ts",
     # TODO(alexeagle): we should be able to get this from //:protobufjs_bootstrap_scripts
     # and automatically plumb it through to Rollup.
     globals = {
diff --git a/examples/webapp/BUILD.bazel b/examples/webapp/BUILD.bazel
index 85df3e5171..24d6919d0b 100644
--- a/examples/webapp/BUILD.bazel
+++ b/examples/webapp/BUILD.bazel
@@ -6,7 +6,7 @@ load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_pac
 rollup_bundle(
     name = "bundle",
     srcs = glob(["*.js"]),
-    entry_point = "index.js",
+    entry_point = ":index.js",
 )
 
 web_package(
diff --git a/internal/common/collect_es6_sources.bzl b/internal/common/collect_es6_sources.bzl
index ec9cf6acb5..83f6d25d0f 100644
--- a/internal/common/collect_es6_sources.bzl
+++ b/internal/common/collect_es6_sources.bzl
@@ -31,6 +31,11 @@ def collect_es6_sources(ctx):
     non_rerooted_files = [d for d in ctx.files.deps if d.is_source]
     if hasattr(ctx.attr, "srcs"):
         non_rerooted_files += ctx.files.srcs
+
+    # Some rules such as rollup_bundle specify an entry_point which should
+    # be collected if the file is a js file.
+    if hasattr(ctx.attr, "entry_point"):
+        non_rerooted_files += [s for s in ctx.files.entry_point if s.extension == "js"]
     for dep in ctx.attr.deps:
         if hasattr(dep, "typescript"):
             non_rerooted_files += dep.typescript.transitive_es6_sources.to_list()
diff --git a/internal/e2e/rollup/BUILD.bazel b/internal/e2e/rollup/BUILD.bazel
index 99041bf140..fde910683e 100644
--- a/internal/e2e/rollup/BUILD.bazel
+++ b/internal/e2e/rollup/BUILD.bazel
@@ -3,11 +3,8 @@ load("//:defs.bzl", "rollup_bundle")
 
 rollup_bundle(
     name = "bundle",
-    srcs = [
-        "bar.js",
-        "foo.js",
-    ],
-    entry_point = "internal/e2e/rollup/foo.js",
+    srcs = ["bar.js"],
+    entry_point = ":foo.js",
     globals = {"some_global_var": "runtime_name_of_global_var"},
     license_banner = ":license.txt",
     deps = [
diff --git a/internal/e2e/rollup_code_splitting/BUILD.bazel b/internal/e2e/rollup_code_splitting/BUILD.bazel
index 84b9d9be62..650b2b4228 100644
--- a/internal/e2e/rollup_code_splitting/BUILD.bazel
+++ b/internal/e2e/rollup_code_splitting/BUILD.bazel
@@ -6,8 +6,8 @@ rollup_bundle(
         ["*.js"],
         exclude = ["*.spec.js"],
     ),
-    additional_entry_points = ["internal/e2e/rollup_code_splitting/additional_entry.js"],
-    entry_point = "internal/e2e/rollup_code_splitting/main1.js",
+    additional_entry_points = ["build_bazel_rules_nodejs/internal/e2e/rollup_code_splitting/additional_entry"],
+    entry_point = ":main1.js",
     license_banner = ":license.txt",
 )
 
@@ -18,10 +18,11 @@ jasmine_node_test(
         "main1.spec.js",
     ],
     data = glob([
-        "*_golden.js_",
+        "goldens/*",
     ]) + [
         ":bundle",
         ":bundle.min.js",
+        ":bundle.min.es2015.js",
     ],
     deps = [
         "//internal/e2e:check_lib",
diff --git a/internal/e2e/rollup_code_splitting/additional_entry.spec.js b/internal/e2e/rollup_code_splitting/additional_entry.spec.js
index 602b653445..c1598de5be 100644
--- a/internal/e2e/rollup_code_splitting/additional_entry.spec.js
+++ b/internal/e2e/rollup_code_splitting/additional_entry.spec.js
@@ -5,7 +5,8 @@ const path = __dirname;
 
 describe('bundling additional entry point', () => {
   it('should work', () => {
-    check(path, 'bundle.min.js', 'bundle-min_golden.js_');
+    check(path, 'bundle.min.js', 'goldens/bundle.min.js_');
+    check(path, 'bundle.min.es2015.js', 'goldens/bundle.min.es2015.js_');
   });
 
   // Disabled because native ESModules can't be loaded in current nodejs
diff --git a/internal/e2e/rollup_code_splitting/goldens/bundle.min.es2015.js_ b/internal/e2e/rollup_code_splitting/goldens/bundle.min.es2015.js_
new file mode 100755
index 0000000000..8fafe68af6
--- /dev/null
+++ b/internal/e2e/rollup_code_splitting/goldens/bundle.min.es2015.js_
@@ -0,0 +1 @@
+import('./bundle_chunks_min_es2015/main1.js');
\ No newline at end of file
diff --git a/internal/e2e/rollup_code_splitting/bundle-min_golden.js_ b/internal/e2e/rollup_code_splitting/goldens/bundle.min.js_
similarity index 61%
rename from internal/e2e/rollup_code_splitting/bundle-min_golden.js_
rename to internal/e2e/rollup_code_splitting/goldens/bundle.min.js_
index f29b46c8c0..f102e20e4d 100755
--- a/internal/e2e/rollup_code_splitting/bundle-min_golden.js_
+++ b/internal/e2e/rollup_code_splitting/goldens/bundle.min.js_
@@ -3,7 +3,7 @@
 (function(global) {
 System.config({
   packages: {
-    '': {map: {"./main1.js": "bundle_chunks_min/main1.js", "./additional_entry.js": "bundle_chunks_min/additional_entry.js"}, defaultExtension: 'js'},
+    '': {map: {"./main1": "bundle_chunks_min/main1", "./additional_entry": "bundle_chunks_min/additional_entry"}, defaultExtension: 'js'},
   }
 });
 System.import('main1.js').catch(function(err) {
diff --git a/internal/e2e/rollup_fine_grained_deps/BUILD.bazel b/internal/e2e/rollup_fine_grained_deps/BUILD.bazel
index 48c878ec8f..c98a9ef0f7 100644
--- a/internal/e2e/rollup_fine_grained_deps/BUILD.bazel
+++ b/internal/e2e/rollup_fine_grained_deps/BUILD.bazel
@@ -4,16 +4,14 @@ load("//:defs.bzl", "jasmine_node_test", "nodejs_binary", "rollup_bundle")
 # and no fine grained deps
 rollup_bundle(
     name = "bundle_no_deps",
-    srcs = ["no-deps.js"],
-    entry_point = "internal/e2e/rollup_fine_grained_deps/no-deps.js",
+    entry_point = ":no-deps.js",
 )
 
 # You can have a rollup_bundle with no node_modules attribute
 # and fine grained deps
 rollup_bundle(
     name = "bundle",
-    srcs = ["has-deps.js"],
-    entry_point = "internal/e2e/rollup_fine_grained_deps/has-deps.js",
+    entry_point = ":has-deps.js",
     deps = [
         "@fine_grained_deps_yarn//@gregmagolan/test-a",
         "@fine_grained_deps_yarn//@gregmagolan/test-b",
@@ -24,8 +22,7 @@ rollup_bundle(
 # and no fine grained deps
 rollup_bundle(
     name = "bundle_legacy",
-    srcs = ["has-deps.js"],
-    entry_point = "internal/e2e/rollup_fine_grained_deps/has-deps.js",
+    entry_point = ":has-deps.js",
     node_modules = "@fine_grained_deps_yarn//:node_modules",
 )
 
@@ -33,8 +30,7 @@ rollup_bundle(
 # and fine grained deps so long as they come from the same root
 rollup_bundle(
     name = "bundle_hybrid",
-    srcs = ["has-deps.js"],
-    entry_point = "internal/e2e/rollup_fine_grained_deps/has-deps.js",
+    entry_point = ":has-deps.js",
     node_modules = "@fine_grained_deps_yarn//:node_modules",
     deps = [
         "@fine_grained_deps_yarn//@gregmagolan/test-a",
diff --git a/internal/node/node.bzl b/internal/node/node.bzl
index 1078f4a706..9ac1cae29b 100644
--- a/internal/node/node.bzl
+++ b/internal/node/node.bzl
@@ -89,6 +89,13 @@ def _write_loader_script(ctx):
     if len(ctx.attr.entry_point.files) != 1:
         fail("labels in entry_point must contain exactly one file")
 
+    entry_point_path = expand_path_into_runfiles(ctx, ctx.file.entry_point.short_path)
+
+    # If the entry point specified is a typescript file then set the entry
+    # point to the corresponding .js file
+    if entry_point_path.endswith(".ts"):
+        entry_point_path = entry_point_path[:-3] + ".js"
+
     ctx.actions.expand_template(
         template = ctx.file._loader_template,
         output = ctx.outputs.loader,
@@ -97,7 +104,7 @@ def _write_loader_script(ctx):
             "TEMPLATED_bootstrap": "\n  " + ",\n  ".join(
                 ["\"" + d + "\"" for d in ctx.attr.bootstrap],
             ),
-            "TEMPLATED_entry_point": expand_path_into_runfiles(ctx, ctx.file.entry_point.short_path),
+            "TEMPLATED_entry_point": entry_point_path,
             "TEMPLATED_gen_dir": ctx.genfiles_dir.path,
             "TEMPLATED_install_source_map_support": str(ctx.attr.install_source_map_support).lower(),
             "TEMPLATED_module_roots": "\n  " + ",\n  ".join(module_mappings),
@@ -172,7 +179,11 @@ def _nodejs_binary_impl(ctx):
         is_executable = True,
     )
 
-    runfiles = depset([node, ctx.outputs.loader, ctx.file._repository_args, ctx.file.entry_point], transitive = [sources, node_modules])
+    runfiles = depset([node, ctx.outputs.loader, ctx.file._repository_args], transitive = [sources, node_modules])
+
+    # entry point is only needed in runfiles if it is a .js file
+    if ctx.file.entry_point.extension == "js":
+        runfiles = depset([ctx.file.entry_point], transitive = [runfiles])
 
     return [DefaultInfo(
         executable = ctx.outputs.script,
@@ -215,32 +226,60 @@ _NODEJS_EXECUTABLE_ATTRS = {
     "entry_point": attr.label(
         doc = """The script which should be executed first, usually containing a main function.
         The `entry_point` accepts a target's name as an entry point. 
-        If the target is a rule, it should produce the JavaScript entry file that will be passed to the nodejs_binary rule). 
+
+        If the entry JavaScript file belongs to the same package (as the BUILD file), 
+        you can simply reference it by its relative name to the package directory:
+
+        ```
+        nodejs_binary(
+            name = "my_binary",
+            ...
+            entry_point = ":file.js",
+        )
+        ```
+
+        You can specify the entry point as a typescript file so long as you also include
+        the ts_library target in data:
+
+        ```
+        ts_library(
+            name = "main",
+            srcs = ["main.ts"],
+        )
+
+        nodejs_binary(
+            name = "bin",
+            data = [":main"]
+            entry_point = ":main.ts",
+        )
+        ```
+
+        The rule will use the corresponding es5 `.js` output of the ts_library rule as the entry point.
+
+        If the entry point target is a rule, it should produce the JavaScript entry file that will be passed to the nodejs_binary rule). 
         For example:
 
         ```
         filegroup(
             name = "entry_file",
-            srcs = ["workspace/path/to/entry/file"]
+            srcs = ["main.js"],
         )
+
         nodejs_binary(
             name = "my_binary",
-            ...
             entry_point = ":entry_file",
         )
         ```
 
-        If the entry JavaScript file belongs to the same package (as the BUILD file), 
-        you can simply reference it by its relative name to the package directory:
+        The entry_point can also be a label in another workspace:
 
         ```
         nodejs_binary(
-            name = "my_binary",
-            ...
-            entry_point = ":file.js",
+            name = "history-server",
+            entry_point = "@npm//node_modules/history-server:modules/cli.js",
+            data = ["@npm//history-server"],
         )
         ```
-
         """,
         mandatory = True,
         allow_single_file = True,
diff --git a/internal/npm_install/BUILD.bazel b/internal/npm_install/BUILD.bazel
index 2cccbf6c8a..7f45172fad 100644
--- a/internal/npm_install/BUILD.bazel
+++ b/internal/npm_install/BUILD.bazel
@@ -33,7 +33,7 @@ nodejs_binary(
         ":browserify-wrapped.js",
         "//third_party/github.com/browserify/browserify:sources",
     ],
-    entry_point = "build_bazel_rules_nodejs/internal/npm_install/browserify-wrapped.js",
+    entry_point = ":browserify-wrapped.js",
     install_source_map_support = False,
     visibility = ["//visibility:public"],
 )
diff --git a/internal/rollup/rollup_bundle.bzl b/internal/rollup/rollup_bundle.bzl
index 4cf3e73ac6..340ba7bc01 100644
--- a/internal/rollup/rollup_bundle.bzl
+++ b/internal/rollup/rollup_bundle.bzl
@@ -20,6 +20,7 @@ You do not need to install them into your project.
 
 load("@build_bazel_rules_nodejs//internal/common:node_module_info.bzl", "NodeModuleSources", "collect_node_modules_aspect")
 load("//internal/common:collect_es6_sources.bzl", _collect_es2015_sources = "collect_es6_sources")
+load("//internal/common:expand_into_runfiles.bzl", "expand_path_into_runfiles")
 load("//internal/common:module_mappings.bzl", "get_module_mappings")
 
 _ROLLUP_MODULE_MAPPINGS_ATTR = "rollup_module_mappings"
@@ -80,6 +81,13 @@ def _compute_node_modules_root(ctx):
         ] if f])
     return node_modules_root
 
+# Expand entry_point into runfiles and strip the file extension
+def _entry_point_path(ctx):
+    return "/".join([
+        expand_path_into_runfiles(ctx, ctx.file.entry_point.dirname),
+        ctx.file.entry_point.basename,
+    ])[:-(len(ctx.file.entry_point.extension) + 1)]
+
 def write_rollup_config(ctx, plugins = [], root_dir = None, filename = "_%s.rollup.conf.js", output_format = "iife", additional_entry_points = []):
     """Generate a rollup config file.
 
@@ -102,7 +110,7 @@ def write_rollup_config(ctx, plugins = [], root_dir = None, filename = "_%s.roll
     # build_file_path includes the BUILD.bazel file, transform here to only include the dirname
     build_file_dirname = "/".join(ctx.build_file_path.split("/")[:-1])
 
-    entry_points = [ctx.attr.entry_point] + additional_entry_points
+    entry_points = [_entry_point_path(ctx)] + additional_entry_points
 
     mappings = dict()
     all_deps = ctx.attr.deps + ctx.attr.srcs
@@ -363,9 +371,7 @@ def run_sourcemapexplorer(ctx, js, map, output):
 def _generate_toplevel_entry(ctx, bundles_folder, output):
     """Generates a native ESmodule that imports the entry point
     """
-    main_entry_point_basename = ctx.attr.entry_point.split("/")[-1]
-    if not main_entry_point_basename.endswith(".js"):
-        main_entry_point_basename += ".js"
+    main_entry_point_basename = _entry_point_path(ctx).split("/")[-1] + ".js"
     ctx.actions.write(output, """import('./%s/%s');""" % (bundles_folder, main_entry_point_basename))
 
 def _generate_code_split_entry(ctx, bundles_folder, output):
@@ -419,10 +425,11 @@ def _generate_code_split_entry(ctx, bundles_folder, output):
       bundles_folder: the folder name with the bundled chunks to map to
       output: the file to generate
     """
-    main_entry_point_basename = ctx.attr.entry_point.split("/")[-1]
-    main_entry_point_dirname = "/".join(ctx.attr.entry_point.split("/")[:-1]) + "/"
+    entry_point_path = _entry_point_path(ctx)
+    main_entry_point_basename = entry_point_path.split("/")[-1] + ".js"
+    main_entry_point_dirname = "/".join(entry_point_path.split("/")[:-1]) + "/"
     entry_points = {}
-    for e in [ctx.attr.entry_point] + ctx.attr.additional_entry_points:
+    for e in [entry_point_path] + ctx.attr.additional_entry_points:
         entry_point = e[len(main_entry_point_dirname):]
         entry_points["./" + entry_point] = bundles_folder + "/" + entry_point.split("/")[-1]
 
@@ -436,6 +443,9 @@ def _generate_code_split_entry(ctx, bundles_folder, output):
     )
 
 def _rollup_bundle(ctx):
+    if len(ctx.attr.entry_point.files) != 1:
+        fail("labels in entry_point must contain exactly one file")
+
     if ctx.attr.additional_entry_points:
         # Generate code split bundles if additional entry points have been specified.
         # See doc for additional_entry_points for more information.
@@ -601,11 +611,55 @@ ROLLUP_ATTRS = {
         It is sufficient to load one of these SystemJS boilerplate/entry point
         files as a script in your HTML to load your application""",
     ),
-    "entry_point": attr.string(
+    "entry_point": attr.label(
         doc = """The starting point of the application, passed as the `--input` flag to rollup.
-        This should be a path relative to the workspace root.
+        The `entry_point` accepts a target's name as an entry point.
+
+        If the entry JavaScript file belongs to the same package (as the BUILD file), 
+        you can simply reference it by its relative name to the package directory:
+
+        ```
+        rollup_bundle(
+            name = "bundle",
+            entry_point = ":main.js",
+        )
+        ```
+
+        You can specify the entry point as a typescript file so long as you also include
+        the ts_library target in deps:
+
+        ```
+        ts_library(
+            name = "main",
+            srcs = ["main.ts"],
+        )
+
+        rollup_bundle(
+            name = "bundle",
+            deps = [":main"]
+            entry_point = ":main.ts",
+        )
+        ```
+
+        The rule will use the corresponding es2015 `.js` output of the ts_library rule as the entry point.
+
+        If the entry point target is a rule, it should produce the JavaScript entry file that will be passed to the nodejs_binary rule). 
+        For example:
+
+        ```
+        filegroup(
+            name = "entry_file",
+            srcs = ["main.js"],
+        )
+
+        rollup_bundle(
+            name = "bundle",
+            entry_point = ":entry_file",
+        )
+        ```
         """,
         mandatory = True,
+        allow_single_file = True,
     ),
     "global_name": attr.string(
         doc = """A name given to this package when referenced as a global variable.
diff --git a/internal/web_package/test/BUILD.bazel b/internal/web_package/test/BUILD.bazel
index 655475270f..c23b04ba89 100644
--- a/internal/web_package/test/BUILD.bazel
+++ b/internal/web_package/test/BUILD.bazel
@@ -5,8 +5,7 @@ package(default_visibility = ["//visibility:public"])
 
 rollup_bundle(
     name = "bundle",
-    srcs = glob(["*.js"]),
-    entry_point = "internal/web_package/test/script.js",
+    entry_point = ":script.js",
 )
 
 web_package(
diff --git a/internal/web_package/test2/BUILD.bazel b/internal/web_package/test2/BUILD.bazel
index 0fb78b8a13..7d1a0cca66 100644
--- a/internal/web_package/test2/BUILD.bazel
+++ b/internal/web_package/test2/BUILD.bazel
@@ -3,8 +3,7 @@ load("@build_bazel_rules_nodejs//internal/web_package:web_package.bzl", "web_pac
 
 rollup_bundle(
     name = "local_bundle",
-    srcs = glob(["*.js"]),
-    entry_point = "internal/web_package/test2/script.js",
+    entry_point = ":script.js",
 )
 
 # Same exts as //internal/web_package/test-exports, //internal/web_package/test2/rel-exports
diff --git a/packages/create/BUILD.bazel b/packages/create/BUILD.bazel
index f932fb274d..bfd4dcf86e 100644
--- a/packages/create/BUILD.bazel
+++ b/packages/create/BUILD.bazel
@@ -27,7 +27,7 @@ nodejs_test(
         ":npm_package",
         "@npm//minimist",
     ],
-    entry_point = "build_bazel_rules_nodejs/packages/create/test.js",
+    entry_point = ":test.js",
 )
 
 # TODO(alexeagle): add e2e testing by running bazel in a newly created project
diff --git a/packages/jasmine/BUILD.bazel b/packages/jasmine/BUILD.bazel
index f7ac5321c9..02f922473f 100644
--- a/packages/jasmine/BUILD.bazel
+++ b/packages/jasmine/BUILD.bazel
@@ -60,7 +60,7 @@ npm_package(
 )
 
 js_library(
-    name = "jasmine_runner",
+    name = "jasmine__pkg",
     srcs = [
         "index.js",
         "src/jasmine_runner.js",
diff --git a/packages/jasmine/src/jasmine_node_test.bzl b/packages/jasmine/src/jasmine_node_test.bzl
index ce876cacce..ab9656f97b 100644
--- a/packages/jasmine/src/jasmine_node_test.bzl
+++ b/packages/jasmine/src/jasmine_node_test.bzl
@@ -29,22 +29,25 @@ def jasmine_node_test(
         expected_exit_code = 0,
         tags = [],
         coverage = False,
-        jasmine = "@npm//@bazel/jasmine",
+        jasmine = "@npm//node_modules/@bazel/jasmine:index.js",
         **kwargs):
     """Runs tests in NodeJS using the Jasmine test runner.
 
     To debug the test, see debugging notes in `nodejs_test`.
 
     Args:
-      name: name of the resulting label
+      name: Name of the resulting label
       srcs: JavaScript source files containing Jasmine specs
       data: Runtime dependencies which will be loaded while the test executes
       deps: Other targets which produce JavaScript, such as ts_library
       expected_exit_code: The expected exit code for the test. Defaults to 0.
-      tags: bazel tags applied to test
-      jasmine: a label providing the @bazel/jasmine npm dependency
-      coverage: Enables code coverage collection and reporting
-      **kwargs: remaining arguments are passed to the test rule
+      tags: Bazel tags applied to test
+      coverage: Enables code coverage collection and reporting. Defaults to False.
+      jasmine: A label providing the @bazel/jasmine npm dependency. Defaults
+               to "@npm//@bazel/jasmine" so that the correct jasmine & jasmine-core
+               dependencies are resolved unless they are overwritten in a bootstrap
+               file.
+      **kwargs: Remaining arguments are passed to the test rule
     """
     devmode_js_sources(
         name = "%s_devmode_srcs" % name,
@@ -53,7 +56,7 @@ def jasmine_node_test(
         tags = tags,
     )
 
-    all_data = data + srcs + deps + [jasmine]
+    all_data = data + srcs + deps + [Label(jasmine).relative(":jasmine__pkg")]
 
     all_data += [":%s_devmode_srcs.MF" % name]
     all_data += [Label("@bazel_tools//tools/bash/runfiles")]
diff --git a/packages/jasmine/test/BUILD.bazel b/packages/jasmine/test/BUILD.bazel
index 70d35e6a7c..f4848597bd 100644
--- a/packages/jasmine/test/BUILD.bazel
+++ b/packages/jasmine/test/BUILD.bazel
@@ -9,7 +9,7 @@ jasmine_node_test(
     # target if they are not using the default @npm//@bazel/jasmine
     jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -23,7 +23,7 @@ jasmine_node_test(
     # target if they are not using the default @npm//@bazel/jasmine
     jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -37,7 +37,7 @@ jasmine_node_test(
     # target if they are not using the default @npm//@bazel/jasmine
     jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -51,7 +51,7 @@ jasmine_node_test(
     # target if they are not using the default @npm//@bazel/jasmine
     jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -66,7 +66,7 @@ jasmine_node_test(
     jasmine = "@npm_bazel_jasmine//:index.js",
     shard_count = 3,
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -78,7 +78,7 @@ jasmine_node_test(
     jasmine = "@npm_bazel_jasmine//:index.js",
     shard_count = 2,
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -102,7 +102,7 @@ jasmine_node_test(
     # to return a 'incomplete' status
     tags = ["manual"],
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
     ],
 )
@@ -116,7 +116,7 @@ jasmine_node_test(
     coverage = True,
     jasmine = "@npm_bazel_jasmine//:index.js",
     deps = [
-        "//:jasmine_runner",
+        "//:jasmine__pkg",
         "@npm//jasmine",
         "@npm//v8-coverage",
     ],
diff --git a/packages/labs/package.json b/packages/labs/package.json
index 118f87988f..889c2825ef 100644
--- a/packages/labs/package.json
+++ b/packages/labs/package.json
@@ -11,6 +11,9 @@
     "bugs": {
         "url": "https://github.com/bazelbuild/rules_nodejs/issues"
     },
+    "bin": {
+      "webpack": "./webpack/src/cli.js"
+    },
     "devDependencies": {
         "@bazel/typescript": "file:../../dist/npm_bazel_typescript",
         "@types/jasmine": "^3.3.9",
diff --git a/packages/labs/webpack/BUILD.bazel b/packages/labs/webpack/BUILD.bazel
index e058ecf5da..6c23a1eea9 100644
--- a/packages/labs/webpack/BUILD.bazel
+++ b/packages/labs/webpack/BUILD.bazel
@@ -1,5 +1,5 @@
 # BEGIN-INTERNAL
-load("@build_bazel_rules_nodejs//:defs.bzl", "npm_package")
+load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary", "npm_package")
 
 npm_package(
     name = "webpack",
@@ -10,9 +10,18 @@ npm_package(
     replacements = {"#@external\\s": ""},
     visibility = ["//:__pkg__"],
     deps = [
-        "//webpack/src:cli",
+        "//webpack/src:cli_lib",
         "//webpack/src:package_contents",
     ],
 )
 
+nodejs_binary(
+    name = "cli",
+    data = [
+        "//webpack/src:cli_lib",
+        "@npm//webpack",
+    ],
+    entry_point = "//webpack/src:cli.ts",
+    visibility = ["//visibility:public"],
+)
 # END-INTERNAL
diff --git a/packages/labs/webpack/src/BUILD.bazel b/packages/labs/webpack/src/BUILD.bazel
index d42d6bbf9e..c9aeebed86 100644
--- a/packages/labs/webpack/src/BUILD.bazel
+++ b/packages/labs/webpack/src/BUILD.bazel
@@ -1,11 +1,12 @@
-load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
-
 # BEGIN-INTERNAL
 load("@npm_bazel_typescript//:defs.bzl", "ts_library")
 
+exports_files(["cli.ts"])
+
 ts_library(
     name = "cli_lib",
     srcs = glob(["*.ts"]),
+    visibility = ["//:__subpackages__"],
     deps = [
         "@npm//@types",
     ],
@@ -20,24 +21,3 @@ filegroup(
     visibility = ["//webpack:__subpackages__"],
 )
 # END-INTERNAL
-
-nodejs_binary(
-    name = "cli",
-    data = [
-        # BEGIN-INTERNAL
-        # For local development, we depend on the TypeScript output
-        ":cli_lib",
-        # END-INTERNAL
-
-        # For external usage, we depend on the published .JS files
-        #@external "@npm//@bazel/labs",
-        "@npm//webpack",
-    ],
-    # BEGIN-INTERNAL
-    # For local development, our module has this AMD name
-    entry_point = ":cli_lib",
-    # END-INTERNAL
-    # For external usage, we resolve the module from node_modules
-    #@external entry_point = "@bazel/labs/webpack/src:cli_lib",
-    visibility = ["//visibility:public"],
-)
diff --git a/packages/labs/webpack/src/cli.ts b/packages/labs/webpack/src/cli.ts
index 01b27bc97f..43057154c8 100644
--- a/packages/labs/webpack/src/cli.ts
+++ b/packages/labs/webpack/src/cli.ts
@@ -21,7 +21,7 @@ function configure(args: string[]): webpack.Configuration {
   };
 }
 
-function main(config: webpack.Configuration): 0|1 {
+function compile(config: webpack.Configuration): 0|1 {
   const compiler = webpack(config);
   let exitCode: 0|1 = 0;
   compiler.run((err, stats) => {
@@ -41,10 +41,14 @@ function main(config: webpack.Configuration): 0|1 {
   return exitCode;
 }
 
-if (require.main === module) {
+export function main() {
   // Avoid limitations of length of argv by using a flagfile
   // This also makes it easier to debug - you can just look
   // at this flagfile to see what args were passed to webpack
   const args = fs.readFileSync(process.argv[2], {encoding: 'utf-8'}).split('\n').map(unquoteArgs);
-  process.exitCode = main(configure(args));
+  process.exitCode = compile(configure(args));
+}
+
+if (require.main === module) {
+  main()
 }
diff --git a/packages/labs/webpack/src/webpack_bundle.bzl b/packages/labs/webpack/src/webpack_bundle.bzl
index a6410435e5..6b2184da8a 100644
--- a/packages/labs/webpack/src/webpack_bundle.bzl
+++ b/packages/labs/webpack/src/webpack_bundle.bzl
@@ -20,7 +20,7 @@ This rule is experimental, as part of Angular Labs! There may be breaking change
 WEBPACK_BUNDLE_ATTRS = {
     "srcs": attr.label_list(allow_files = True),
     "entry_point": attr.label(allow_single_file = True, mandatory = True),
-    "webpack": attr.label(default = "@npm_bazel_labs//webpack/src:cli", executable = True, cfg = "host"),
+    "webpack": attr.label(default = "@npm//@bazel/labs/bin:webpack", executable = True, cfg = "host"),
 }
 WEBPACK_BUNDLE_OUTS = {
     "bundle": "%{name}.js",
diff --git a/packages/labs/webpack/test/BUILD.bazel b/packages/labs/webpack/test/BUILD.bazel
index bfb37ace57..f70c338039 100644
--- a/packages/labs/webpack/test/BUILD.bazel
+++ b/packages/labs/webpack/test/BUILD.bazel
@@ -6,6 +6,11 @@ webpack_bundle(
     name = "bundle",
     srcs = glob(["*.js"]),
     entry_point = "index.js",
+    # The webpack label here is specific to local testing since
+    # there is no @bazel/labs npm package here. Users
+    # will always have this label point to their @foobar//@bazel/labs/bin:webpack
+    # target if they are not using the default @npm//@bazel/labs/bin:webpack
+    webpack = "@npm_bazel_labs//webpack:cli",
 )
 
 ts_library(
diff --git a/packages/typescript/WORKSPACE b/packages/typescript/WORKSPACE
index e63a64a4fd..84cb6d1c98 100644
--- a/packages/typescript/WORKSPACE
+++ b/packages/typescript/WORKSPACE
@@ -39,11 +39,11 @@ rules_nodejs_dev_dependencies()
 # We use git_repository since Renovate knows how to update it.
 # With http_archive it only sees releases/download/*.tar.gz urls
 
-# TODO(manekinekko): switch to https://github.com/bazelbuild/rules_typescript/ when the changes have been released
+# TODO(gregmagolan): switch to https://github.com/bazelbuild/rules_typescript/ HEAD when the changes are ready for release
 git_repository(
     name = "build_bazel_rules_typescript",
-    commit = "68d92c916ef0829113ade3bb24fbf70bd32208de",
-    remote = "http://github.com/manekinekko/rules_typescript.git",
+    commit = "6521ce4e0d4959eaf46a4738d45f3f480d4af25f",
+    remote = "http://github.com/gregmagolan/rules_typescript.git",
 )
 
 # We have a source dependency on build_bazel_rules_typescript
diff --git a/scripts/setup_examples_angular.sh b/scripts/setup_examples_angular.sh
index d6e310f3cd..7bfd90a709 100755
--- a/scripts/setup_examples_angular.sh
+++ b/scripts/setup_examples_angular.sh
@@ -28,7 +28,8 @@ printf "\n\nSetting up /examples/angular\n"
   # Clean example
   echo_and_run cd ${EXAMPLES_DIR}
   rm -rf angular
-  echo_and_run git clone https://github.com/angular/angular-bazel-example.git angular
+  # TODO(gmagolan): switch back upstream
+  echo_and_run git clone --single-branch --branch entry-point https://github.com/gregmagolan/angular-bazel-example.git angular
   (
     echo_and_run cd angular
 
diff --git a/tools/npm_packages/bazel_workspaces/a/BUILD.bazel b/tools/npm_packages/bazel_workspaces/a/BUILD.bazel
index 0c0bc63434..f4363550d1 100644
--- a/tools/npm_packages/bazel_workspaces/a/BUILD.bazel
+++ b/tools/npm_packages/bazel_workspaces/a/BUILD.bazel
@@ -5,5 +5,5 @@ nodejs_binary(
     data = [
         ":index.js",
     ],
-    entry_point = "bazel_workspace_a/index.js",
+    entry_point = ":index.js",
 )
diff --git a/tools/npm_packages/bazel_workspaces/a/subdir/BUILD.bazel b/tools/npm_packages/bazel_workspaces/a/subdir/BUILD.bazel
index 79650d95ef..f4363550d1 100644
--- a/tools/npm_packages/bazel_workspaces/a/subdir/BUILD.bazel
+++ b/tools/npm_packages/bazel_workspaces/a/subdir/BUILD.bazel
@@ -5,5 +5,5 @@ nodejs_binary(
     data = [
         ":index.js",
     ],
-    entry_point = "bazel_workspace_a/subdir/index.js",
+    entry_point = ":index.js",
 )
diff --git a/tools/npm_packages/bazel_workspaces/b/BUILD.bazel b/tools/npm_packages/bazel_workspaces/b/BUILD.bazel
index 3ab8090ffd..f4363550d1 100644
--- a/tools/npm_packages/bazel_workspaces/b/BUILD.bazel
+++ b/tools/npm_packages/bazel_workspaces/b/BUILD.bazel
@@ -5,5 +5,5 @@ nodejs_binary(
     data = [
         ":index.js",
     ],
-    entry_point = "bazel_workspace_b/index.js",
+    entry_point = ":index.js",
 )
diff --git a/tools/npm_packages/bazel_workspaces/b/subdir/BUILD.bazel b/tools/npm_packages/bazel_workspaces/b/subdir/BUILD.bazel
index f901d4a405..f4363550d1 100644
--- a/tools/npm_packages/bazel_workspaces/b/subdir/BUILD.bazel
+++ b/tools/npm_packages/bazel_workspaces/b/subdir/BUILD.bazel
@@ -5,5 +5,5 @@ nodejs_binary(
     data = [
         ":index.js",
     ],
-    entry_point = "bazel_workspace_b/subdir/index.js",
+    entry_point = ":index.js",
 )
diff --git a/tools/npm_packages/bazel_workspaces/package.json b/tools/npm_packages/bazel_workspaces/package.json
index a4538150f1..e78a47f468 100644
--- a/tools/npm_packages/bazel_workspaces/package.json
+++ b/tools/npm_packages/bazel_workspaces/package.json
@@ -1,6 +1,6 @@
 {
   "name": "bazel_workspace",
-  "version": "0.0.1",
+  "version": "0.0.2",
   "bazelWorkspaces": {
     "bazel_workspace_a": {
         "rootPath": "a"
diff --git a/yarn.lock b/yarn.lock
index 64bffd6049..8a22f33c5a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -264,7 +264,7 @@ base@^0.11.1:
     pascalcase "^0.1.1"
 
 "bazel_workspaces@file:./tools/npm_packages/bazel_workspaces":
-  version "0.0.1"
+  version "0.0.2"
 
 bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
   version "4.11.8"