Skip to content

Commit a28f20b

Browse files
devversionjelbourn
authored andcommitted
build: add workaround for invalid imports generation in bazel
Applies a workaround for the invalid imports generation issue in the Bazel `ng_module` rule. Read more about this here: https://hackmd.io/@devversion/ryCOwIKIS.
1 parent bded378 commit a28f20b

File tree

4 files changed

+95
-1
lines changed

4 files changed

+95
-1
lines changed

WORKSPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ yarn_install(
4242
# are executed in the Bazel sandbox.
4343
data = [
4444
"//:angular-tsconfig.json",
45+
"//:tools/bazel/flat_module_factory_resolution.patch",
4546
"//:tools/bazel/postinstall-patches.js",
4647
"//:tools/bazel/rollup_windows_arguments.patch",
4748
"//:tools/npm/check-npm.js",
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
diff --git node_modules/@angular/compiler/bundles/compiler.umd.js node_modules/@angular/compiler/bundles/compiler.umd.js
2+
index 640c42f..832f8db 100644
3+
--- node_modules/@angular/compiler/bundles/compiler.umd.js
4+
+++ node_modules/@angular/compiler/bundles/compiler.umd.js
5+
@@ -21006,7 +21006,10 @@
6+
};
7+
CompileMetadataResolver.prototype.getGeneratedClass = function (dirType, name) {
8+
if (dirType instanceof StaticSymbol) {
9+
- return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), name);
10+
+ // resolve symbol to the original file path. i.e. symbols resolved through
11+
+ // flat module bundle will be resolved back through the "origins" field.
12+
+ var originalPath = this._reflector.symbolResolver.getResourcePath(dirType);
13+
+ return this._staticSymbolCache.get(ngfactoryFilePath(originalPath), name);
14+
}
15+
else {
16+
return this._createProxyClass(dirType, name);
17+
@@ -21027,7 +21030,8 @@
18+
};
19+
CompileMetadataResolver.prototype.getRendererType = function (dirType) {
20+
if (dirType instanceof StaticSymbol) {
21+
- return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), rendererTypeName(dirType));
22+
+ var originalPath = this._reflector.symbolResolver.getResourcePath(dirType);
23+
+ return this._staticSymbolCache.get(ngfactoryFilePath(originalPath), rendererTypeName(dirType));
24+
}
25+
else {
26+
// returning an object as proxy,
27+
@@ -21037,7 +21041,8 @@
28+
};
29+
CompileMetadataResolver.prototype.getComponentFactory = function (selector, dirType, inputs, outputs) {
30+
if (dirType instanceof StaticSymbol) {
31+
- return this._staticSymbolCache.get(ngfactoryFilePath(dirType.filePath), componentFactoryName(dirType));
32+
+ var originalPath = this._reflector.symbolResolver.getResourcePath(dirType);
33+
+ return this._staticSymbolCache.get(ngfactoryFilePath(originalPath), componentFactoryName(dirType));
34+
}
35+
else {
36+
var hostView = this.getHostComponentViewClass(dirType);

tools/bazel/postinstall-patches.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ const path = require('path');
1010
shelljs.set('-e');
1111
shelljs.cd(path.join(__dirname, '../..'));
1212

13+
// Do not apply postinstall patches when running "postinstall" outside. The
14+
// "generate_build_file.js" file indicates that we run in Bazel managed node modules.
15+
if (!shelljs.test('-e', 'generate_build_file.js')) {
16+
return;
17+
}
18+
1319
// Workaround for https://github.com/angular/angular/issues/18810.
1420
shelljs.exec('ngc -p angular-tsconfig.json');
1521

@@ -54,3 +60,30 @@ shelljs.sed('-i', 'var resolvedEntryPoint = null;', `
5460
if (!shelljs.test('-f', 'node_modules/@angular/bazel/src/ng_package/rollup_bin.js')) {
5561
shelljs.cat(path.join(__dirname, './rollup_windows_arguments.patch')).exec('patch -p0');
5662
}
63+
64+
// Workaround for: https://hackmd.io/MlqFp-yrSx-0mw4rD7dnQQ?both. We only want to discard
65+
// the metadata of files in the bazel managed node modules. That way we keep the default
66+
// behavior of ngc-wrapped except for dependencies between sources of the library. This makes
67+
// the "generateCodeForLibraries" flag more accurate in the Bazel environment where previous
68+
// compilations should not be treated as external libraries. Read more about this in the document.
69+
shelljs.sed('-i', /if \((this\.options\.generateCodeForLibraries === false)/, `
70+
const fs = require('fs');
71+
const hasFlatModuleBundle = fs.existsSync(filePath.replace('.d.ts', '.metadata.json'));
72+
if ((filePath.includes('node_modules/') || !hasFlatModuleBundle) && $1`,
73+
'node_modules/@angular/compiler-cli/src/transformers/compiler_host.js');
74+
shelljs.cat(path.join(__dirname, './flat_module_factory_resolution.patch')).exec('patch -p0');
75+
// The three replacements below ensure that metadata files can be read by NGC and
76+
// that metadata files are collected as Bazel action inputs.
77+
shelljs.sed('-i', /(const NGC_ASSETS = \/[^(]+\()([^)]*)(\).*\/;)/, '$1$2|metadata.json$3',
78+
'node_modules/@angular/bazel/src/ngc-wrapped/index.js');
79+
shelljs.sed('-i', /^((\s*)results = depset\(dep.angular.summaries, transitive = \[results]\))$/,
80+
`$1#\n$2results = depset(dep.angular.metadata, transitive = [results])`,
81+
'node_modules/@angular/bazel/src/ng_module.bzl');
82+
shelljs.sed('-i',
83+
/^((\s*)results = depset\(target.angular.summaries if hasattr\(target, "angular"\) else \[]\))$/,
84+
`$1#\n$2results = depset(target.angular.metadata if hasattr(target, "angular") else [], transitive = [results])`,
85+
'node_modules/@angular/bazel/src/ng_module.bzl');
86+
// Ensure that "metadata" of transitive dependencies can be collected.
87+
shelljs.sed('-i', /("metadata": outs.metadata),/,
88+
`$1 + [m for dep in ctx.attr.deps if hasattr(dep, "angular") for m in dep.angular.metadata],`,
89+
'node_modules/@angular/bazel/src/ng_module.bzl');

tools/defaults.bzl

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,32 @@ def ts_library(tsconfig = None, deps = [], testonly = False, **kwargs):
4343
**kwargs
4444
)
4545

46-
def ng_module(deps = [], tsconfig = None, module_name = None, testonly = False, **kwargs):
46+
def ng_module(
47+
deps = [],
48+
srcs = [],
49+
tsconfig = None,
50+
module_name = None,
51+
flat_module_out_file = None,
52+
testonly = False,
53+
**kwargs):
4754
if not tsconfig:
4855
tsconfig = _getDefaultTsConfig(testonly)
4956

57+
# Targets which have a module name and are not used for tests, should
58+
# have a default flat module out file named "index". This is necessary
59+
# as imports to that target should go through the flat module bundle.
60+
if module_name and not flat_module_out_file and not testonly:
61+
flat_module_out_file = "index"
62+
63+
# Workaround to avoid a lot of changes to the Bazel build rules. Since
64+
# for most targets the flat module out file is "index.js", we cannot
65+
# include "index.ts" (if present) as source-file. This would resolve
66+
# in a conflict in the metadata bundler. Once we switch to Ivy and
67+
# no longer need metadata bundles, we can remove this logic.
68+
if flat_module_out_file == "index":
69+
if "index.ts" in srcs:
70+
srcs.remove("index.ts")
71+
5072
local_deps = [
5173
# Add tslib because we use import helpers for all public packages.
5274
"@npm//tslib",
@@ -63,8 +85,10 @@ def ng_module(deps = [], tsconfig = None, module_name = None, testonly = False,
6385
local_deps = local_deps + [d]
6486

6587
_ng_module(
88+
srcs = srcs,
6689
type_check = _ENABLE_NG_TYPE_CHECKING,
6790
module_name = module_name,
91+
flat_module_out_file = flat_module_out_file,
6892
deps = local_deps,
6993
tsconfig = tsconfig,
7094
testonly = testonly,

0 commit comments

Comments
 (0)