From 48865858750bc1607f20db9b6bf9f913870742bc Mon Sep 17 00:00:00 2001 From: Paul Gschwendtner Date: Mon, 27 Sep 2021 23:56:23 +0200 Subject: [PATCH] feat(bazel): create transition for enabling partial compilation (#43431) Creates, a currently still unused, Bazel transition that will control a build setting that is enabling the partial compilation mode for `ng_module` rule targets. This is in preparation of implementing the Angular Package Format v13 (which should ship in partial compilation). Note: Various other approaches aside from the `transition` has been considered. Here is a small summary of the largest ideas that have been tried for the APF v13 partial compilation refactor. **Using an aspect for partial compilation in `ng_package`** Similar to how we had an aspect for ESM5 compilation in the past, an aspect could be used to create partial compilation prodmode output for packaging. The aspect would take the existing prodmode compilation details and "replay" the compilation with a modified tsconfig that enables partial compilation. This _can_ work but requires lots of caution and is very prone to issues. In order to avoid conflicts with the existing prodmode output, the partial compilation outputs would need to be written to a sub-directory. This makes module resolution extremely difficult when `ng_package` creates the FESM bundles. Also it is difficult to merge multiple of these aspect-compiled folders into a single one for exposing the non-bundled ESM output. It becomes especially difficult to ensure that such an aspect target will actually use the _correct_ dependency type definition when compiled. e.g. consider a case where a partial compiled target relies on another Angular target. The dependency will be compiled partially first, but the other target _needs_ to rely on the partial compilation `d.ts` output of the dependency (and *NOT* the devmode `.d.ts` output). This is incorrect and can cause other type-checking issues / or invalid output. To make this work, the module resolution when invoking tsc_wrapped would also need to be updated/patched. This is out of scope and not reasonable to maintain. **Exposing a third output flavor directly in the rule** Instead of replying a compilation, we could expose an output flavor next to `devmode` and `prodmode`. This sounded like the easiest solution at first, but it will have the same problems as the aspect approach (in terms of module resoltion and avoiding conflicts of files). We cannot control how TS emits `.d.ts` or `.js` files (without patching into the compiler host), so we would need to store the compilation output in a sub-folder similar to the aspect.. resulting in the same issues. This is do-able but would require module resolution to be patched and we do not have control over `@bazel/typescript`. Also, `@bazel/typescript` does not forsee a third output flavor, so that logic would need to be changed significantly as well. PR Close #43431 --- packages/bazel/BUILD.bazel | 5 ++++ packages/bazel/src/BUILD.bazel | 7 ++++++ packages/bazel/src/ng_module/BUILD.bazel | 8 ++++++ .../src/ng_module/partial_compilation.bzl | 25 +++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 packages/bazel/src/ng_module/BUILD.bazel create mode 100644 packages/bazel/src/ng_module/partial_compilation.bzl diff --git a/packages/bazel/BUILD.bazel b/packages/bazel/BUILD.bazel index 89ee85b4a46..95ec943ee01 100644 --- a/packages/bazel/BUILD.bazel +++ b/packages/bazel/BUILD.bazel @@ -8,6 +8,7 @@ pkg_npm( exclude = ["yarn.lock"], ) + [ "//packages/bazel/src:package_assets", + "//packages/bazel/src/ng_module:package_assets", "//packages/bazel/src/api-extractor:package_assets", "//packages/bazel/src/ng_package:package_assets", "//packages/bazel/src/ngc-wrapped:package_assets", @@ -15,6 +16,10 @@ pkg_npm( ], substitutions = { "(#|//)\\s+BEGIN-DEV-ONLY[\\w\\W]+?(#|//)\\s+END-DEV-ONLY": "", + # The partial compilation transition is applied in the user workspace. We do not want to require + # users having to define the build setting, so we directly point the flag label to the place where + # we expect `@angular/bazel` being located. Note: This expects the `@npm//` workspace to be used. + "//packages/bazel/src:partial_compilation": "@npm//@angular/bazel/src:partial_compilation", "//packages/bazel/": "//@angular/bazel/", "@npm//@bazel/typescript/internal:": "//@bazel/typescript/internal:", }, diff --git a/packages/bazel/src/BUILD.bazel b/packages/bazel/src/BUILD.bazel index e1498ab4dc9..6ebd35696e2 100644 --- a/packages/bazel/src/BUILD.bazel +++ b/packages/bazel/src/BUILD.bazel @@ -1,3 +1,4 @@ +load("//packages/bazel/src/ng_module:partial_compilation.bzl", "ng_partial_compilation_flag") # BEGIN-DEV-ONLY package(default_visibility = ["//packages/bazel:__subpackages__"]) @@ -7,3 +8,9 @@ filegroup( srcs = glob(["*"]), ) # END-DEV-ONLY + +ng_partial_compilation_flag( + name = "partial_compilation", + build_setting_default = False, + visibility = ["//visibility:public"], +) diff --git a/packages/bazel/src/ng_module/BUILD.bazel b/packages/bazel/src/ng_module/BUILD.bazel new file mode 100644 index 00000000000..ff253742bd6 --- /dev/null +++ b/packages/bazel/src/ng_module/BUILD.bazel @@ -0,0 +1,8 @@ +# BEGIN-DEV-ONLY +package(default_visibility = ["//packages/bazel:__subpackages__"]) + +filegroup( + name = "package_assets", + srcs = glob(["*"]), +) +# END-DEV-ONLY diff --git a/packages/bazel/src/ng_module/partial_compilation.bzl b/packages/bazel/src/ng_module/partial_compilation.bzl new file mode 100644 index 00000000000..15b79845482 --- /dev/null +++ b/packages/bazel/src/ng_module/partial_compilation.bzl @@ -0,0 +1,25 @@ +# Copyright Google LLC 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 + +NgPartialCompilationInfo = provider( + fields = {"enabled": "Whether partial compilation is enabled."}, +) + +def _ng_partial_compilation_flag_impl(ctx): + return NgPartialCompilationInfo(enabled = ctx.build_setting_value) + +ng_partial_compilation_flag = rule( + implementation = _ng_partial_compilation_flag_impl, + build_setting = config.bool(flag = True), +) + +def _partial_compilation_transition_impl(settings, attr): + return {"//packages/bazel/src:partial_compilation": True} + +partial_compilation_transition = transition( + implementation = _partial_compilation_transition_impl, + inputs = [], + outputs = ["//packages/bazel/src:partial_compilation"], +)