From 185a6ab562c1028fe19cf48ca22d76435ecbc9b3 Mon Sep 17 00:00:00 2001 From: Alex Eagle Date: Fri, 2 Feb 2018 15:25:33 -0800 Subject: [PATCH] build: add esm5 build (#22258) This is a partial cherry-pick of 370ab66c4f020da7e1a6b25b96109f1b3cbf9cba which included this along with a new feature for ivy. PR Close #22258 --- BUILD.bazel | 1 + package.json | 2 +- packages/animations/browser/BUILD.bazel | 1 + packages/bazel/src/BUILD.bazel | 10 -- packages/bazel/src/esm5.bzl | 127 ++++++++++++++++++ packages/bazel/src/modify_tsconfig.js | 38 ++++++ packages/bazel/src/ng_module.bzl | 1 + packages/common/BUILD.bazel | 4 +- packages/common/http/BUILD.bazel | 4 +- packages/core/test/render3/BUILD.bazel | 1 + packages/http/BUILD.bazel | 4 +- packages/platform-browser/BUILD.bazel | 4 +- .../platform-browser/animations/BUILD.bazel | 4 +- packages/platform-server/BUILD.bazel | 4 +- yarn.lock | 12 +- 15 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 packages/bazel/src/esm5.bzl create mode 100644 packages/bazel/src/modify_tsconfig.js diff --git a/BUILD.bazel b/BUILD.bazel index f88b9e1a20..3ae5672cf0 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -32,6 +32,7 @@ filegroup( "reflect-metadata", "source-map-support", "minimist", + "tslib", ] for ext in [ "*.js", "*.json", diff --git a/package.json b/package.json index c34d5d0e92..49f41dc5d6 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "tsickle": "0.26.0", "tslint": "5.7.0", "tslint-eslint-rules": "4.1.1", - "tsutils": "2.12.1", + "tsutils": "2.20.0", "typescript": "2.6.x", "uglify-js": "2.8.29", "universal-analytics": "0.4.15", diff --git a/packages/animations/browser/BUILD.bazel b/packages/animations/browser/BUILD.bazel index 0bb83984c1..04d4f31bec 100644 --- a/packages/animations/browser/BUILD.bazel +++ b/packages/animations/browser/BUILD.bazel @@ -13,5 +13,6 @@ ng_module( module_name = "@angular/animations/browser", deps = [ "//packages/animations", + "//packages/core", ], ) diff --git a/packages/bazel/src/BUILD.bazel b/packages/bazel/src/BUILD.bazel index 5234f7f060..5d2aa39ebc 100644 --- a/packages/bazel/src/BUILD.bazel +++ b/packages/bazel/src/BUILD.bazel @@ -2,16 +2,6 @@ package(default_visibility = ["//visibility:public"]) load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary") -nodejs_binary( - name = "rollup_with_build_optimizer", - data = ["@angular_devkit//packages/angular_devkit/build_optimizer:lib"], - # Since our rule extends the one in rules_nodejs, we use the same runtime - # dependency @build_bazel_rules_nodejs_rollup_deps. We don't need any - # additional npm dependencies when we run rollup or uglify. - entry_point = "build_bazel_rules_nodejs_rollup_deps/node_modules/rollup/bin/rollup", - node_modules = "@build_bazel_rules_nodejs_rollup_deps//:node_modules", -) - nodejs_binary( name = "modify_tsconfig", data = ["modify_tsconfig.js"], diff --git a/packages/bazel/src/esm5.bzl b/packages/bazel/src/esm5.bzl new file mode 100644 index 0000000000..514ed7e357 --- /dev/null +++ b/packages/bazel/src/esm5.bzl @@ -0,0 +1,127 @@ +# Copyright Google Inc. All Rights Reserved. +# +# Use of this source code is governed by an MIT-style license that can be +# found in the LICENSE file at https://angular.io/license + +"""Provides ES5 syntax with ESModule import/exports. + +This exposes another flavor of output JavaScript, which is ES5 syntax +with ES2015 module syntax (import/export). +All Bazel rules should consume the standard dev or prod mode. +However we need to publish this flavor on NPM, so it's necessary to be able +to produce it. +""" + +# The provider downstream rules use to access the outputs +ESM5Info = provider( + doc = "Typescript compilation outputs in ES5 syntax with ES Modules", + fields = { + "transitive_output": """Dict of [rootDir, .js depset] entries. + + The value is a depset of the .js output files. + The key is the prefix that should be stripped off the files + when resolving modules, eg. for file + bazel-bin/[external/wkspc/]path/to/package/label.esm5/path/to/package/file.js + the rootdir would be + bazel-bin/[external/wkspc/]path/to/package/label.esm5""", + }, +) + +def _map_closure_path(file): + result = file.short_path[:-len(".closure.js")] + # short_path is meant to be used when accessing runfiles in a binary, where + # the CWD is inside the current repo. Therefore files in external repo have a + # short_path of ../external/wkspc/path/to/package + # We want to strip the first two segments from such paths. + if (result.startswith("../")): + result = "/".join(result.split("/")[2:]) + return result + ".js" + +def _join(array): + return "/".join([p for p in array if p]) + +def _esm5_outputs_aspect(target, ctx): + if not hasattr(target, "typescript"): + return [] + + # We create a new tsconfig.json file that will have our compilation settings + tsconfig = ctx.actions.declare_file("%s_esm5.tsconfig.json" % target.label.name) + + workspace = target.label.workspace_root if target.label.workspace_root else "" + + # re-root the outputs under a ".esm5" directory so the path don't collide + out_dir = ctx.label.name + ".esm5" + if workspace: + out_dir = out_dir + "/" + workspace + + outputs = [ctx.actions.declare_file(_join([out_dir, _map_closure_path(f)])) + for f in target.typescript.replay_params.outputs + if not f.short_path.endswith(".externs.js")] + + ctx.actions.run( + executable = ctx.executable._modify_tsconfig, + inputs = [target.typescript.replay_params.tsconfig], + outputs = [tsconfig], + arguments = [ + target.typescript.replay_params.tsconfig.path, + tsconfig.path, + _join([workspace, target.label.package, ctx.label.name + ".esm5"]), + ctx.bin_dir.path + ], + ) + + ctx.action( + progress_message = "Compiling TypeScript (ES5 with ES Modules) %s" % target.label, + inputs = target.typescript.replay_params.inputs + [tsconfig], + outputs = outputs, + arguments = [tsconfig.path], + executable = target.typescript.replay_params.compiler, + execution_requirements = { + "supports-workers": "0", + }, + ) + + root_dir = _join([ + ctx.bin_dir.path, + workspace, + target.label.package, + ctx.label.name + ".esm5", + ]) + + transitive_output={root_dir: depset(outputs)} + for dep in ctx.rule.attr.deps: + if ESM5Info in dep: + transitive_output.update(dep[ESM5Info].transitive_output) + + return [ESM5Info( + transitive_output = transitive_output, + )] + +# Downstream rules can use this aspect to access the ESM5 output flavor. +# Only terminal rules (those which expect never to be used in deps[]) should do +# this. +esm5_outputs_aspect = aspect( + implementation = _esm5_outputs_aspect, + # Recurse to the deps of any target we visit + attr_aspects = ['deps'], + attrs = { + "_modify_tsconfig": attr.label( + default = Label("//packages/bazel/src:modify_tsconfig"), + executable = True, + cfg = "host"), + # We must list tsc_wrapped here to ensure it's built before the action runs + # For some reason, having the compiler output as an input to the action above + # is not sufficient. + "_tsc_wrapped": attr.label( + default = Label("@build_bazel_rules_typescript//internal/tsc_wrapped:tsc_wrapped_bin"), + executable = True, + cfg = "host", + ), + # Same comment as for tsc_wrapped above. + "_ngc_wrapped": attr.label( + default = Label("//packages/bazel/src/ngc-wrapped"), + executable = True, + cfg = "host", + ), + }, +) diff --git a/packages/bazel/src/modify_tsconfig.js b/packages/bazel/src/modify_tsconfig.js new file mode 100644 index 0000000000..37ff67c06f --- /dev/null +++ b/packages/bazel/src/modify_tsconfig.js @@ -0,0 +1,38 @@ +/** + * @license + * Copyright Google Inc. All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://angular.io/license + */ + +/** + * @fileoverview Read a tsconfig.json file intended to produce production mode + * JS output, modify it to produce esm5 output instead, and write the result + * to disk. + */ +const fs = require('fs'); +const path = require('path'); + +function main(args) { + if (args.length < 3) { + console.error('Usage: $0 input.tsconfig.json output.tsconfig.json newRoot binDir'); + } + [input, output, newRoot, binDir] = args; + + const data = JSON.parse(fs.readFileSync(input, {encoding: 'utf-8'})); + data['compilerOptions']['target'] = 'es5'; + data['bazelOptions']['es5Mode'] = true; + data['bazelOptions']['tsickle'] = false; + data['compilerOptions']['outDir'] = path.join(data['compilerOptions']['outDir'], newRoot); + if (data['angularCompilerOptions']) { + data['angularCompilerOptions']['expectedOut'] = + data['angularCompilerOptions']['expectedOut'].map( + f => f.replace(/\.closure\.js$/, '.js').replace(binDir, path.join(binDir, newRoot))); + } + fs.writeFileSync(output, JSON.stringify(data)); +} + +if (require.main === module) { + process.exitCode = main(process.argv.slice(2)); +} diff --git a/packages/bazel/src/ng_module.bzl b/packages/bazel/src/ng_module.bzl index 931624c9d4..7998cdff28 100644 --- a/packages/bazel/src/ng_module.bzl +++ b/packages/bazel/src/ng_module.bzl @@ -180,6 +180,7 @@ def ngc_compile_action(ctx, label, inputs, outputs, messages_out, tsconfig_file, tsconfig = tsconfig_file, inputs = inputs, outputs = outputs, + compiler = ctx.executable.compiler, ) return None diff --git a/packages/common/BUILD.bazel b/packages/common/BUILD.bazel index 665906b0ed..1eb16434eb 100644 --- a/packages/common/BUILD.bazel +++ b/packages/common/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "common", srcs = glob( [ diff --git a/packages/common/http/BUILD.bazel b/packages/common/http/BUILD.bazel index 327cbd783d..ec7ee9ef4e 100644 --- a/packages/common/http/BUILD.bazel +++ b/packages/common/http/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "http", srcs = glob( [ diff --git a/packages/core/test/render3/BUILD.bazel b/packages/core/test/render3/BUILD.bazel index cb62372f78..79b074e729 100644 --- a/packages/core/test/render3/BUILD.bazel +++ b/packages/core/test/render3/BUILD.bazel @@ -22,6 +22,7 @@ ts_library( "//packages/animations", "//packages/animations/browser", "//packages/animations/browser/testing", + "//packages/common", "//packages/core", "//packages/platform-browser", "//packages/platform-browser/animations", diff --git a/packages/http/BUILD.bazel b/packages/http/BUILD.bazel index b3af3d4b73..deeb113944 100644 --- a/packages/http/BUILD.bazel +++ b/packages/http/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "http", srcs = glob( [ diff --git a/packages/platform-browser/BUILD.bazel b/packages/platform-browser/BUILD.bazel index b55119fc08..108a954320 100644 --- a/packages/platform-browser/BUILD.bazel +++ b/packages/platform-browser/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "platform-browser", srcs = glob( [ diff --git a/packages/platform-browser/animations/BUILD.bazel b/packages/platform-browser/animations/BUILD.bazel index 66fe1450f2..4ad034a8c8 100644 --- a/packages/platform-browser/animations/BUILD.bazel +++ b/packages/platform-browser/animations/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "animations", srcs = glob( [ diff --git a/packages/platform-server/BUILD.bazel b/packages/platform-server/BUILD.bazel index abcdb545f9..71320e0bee 100644 --- a/packages/platform-server/BUILD.bazel +++ b/packages/platform-server/BUILD.bazel @@ -1,8 +1,8 @@ package(default_visibility = ["//visibility:public"]) -load("//tools:defaults.bzl", "ts_library") +load("//tools:defaults.bzl", "ng_module") -ts_library( +ng_module( name = "platform-server", srcs = glob( [ diff --git a/yarn.lock b/yarn.lock index 716af993c4..05f87a79e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7096,6 +7096,10 @@ tslib@^1.0.0, tslib@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" +tslib@^1.8.1: + version "1.9.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8" + tslint-eslint-rules@4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/tslint-eslint-rules/-/tslint-eslint-rules-4.1.1.tgz#7c30e7882f26bc276bff91d2384975c69daf88ba" @@ -7137,11 +7141,11 @@ tsscmp@1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.5.tgz#7dc4a33af71581ab4337da91d85ca5427ebd9a97" -tsutils@2.12.1: - version "2.12.1" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.12.1.tgz#f4d95ce3391c8971e46e54c4cf0edb0a21dd5b24" +tsutils@2.20.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.20.0.tgz#303394064bc80be8ee04e10b8609ae852e9312d3" dependencies: - tslib "^1.7.1" + tslib "^1.8.1" tsutils@^1.4.0: version "1.9.1"