Skip to content

Commit c9a8e95

Browse files
committed
build: fix release output containing invalid imports sometimes
A very subtle issue has surfaced in our release output. Based on previous builds that have been performed locally by the caretaker performing the release, the release output might differ and contain invalid module imports that break ES2015 output. Notably the es2015 output is not primarily used by the CLI. It uses the flat ES2015 output instead. The issue surfaces because of a bug in `@bazel/typescript` where the `moduleName` for source files is leaking between TSC worker runs. This means that source files are incorrectly referenced by module name, instead of relative path when the prodmode ES2015 output is built. Deep paths to source files are not supported as per Angular Package format. We patch the fix that is pending upstream to ensure our release output works: bazelbuild/rules_typescript#504. Once the fix upstream lands (which might take quite some time; given g3 sync and sync with the rules_nodejs repository), we can remove the patch and update to the latest version of `@bazel/typescript`. Fixes #20179.
1 parent a295ed0 commit c9a8e95

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
diff --git node_modules/@bazel/typescript/internal/tsc_wrapped/compiler_host.js node_modules/@bazel/typescript/internal/tsc_wrapped/compiler_host.js
2+
index 031d9da..de33bf3 100644
3+
--- node_modules/@bazel/typescript/internal/tsc_wrapped/compiler_host.js
4+
+++ node_modules/@bazel/typescript/internal/tsc_wrapped/compiler_host.js
5+
@@ -37,6 +37,45 @@ function validateBazelOptions(bazelOpts) {
6+
'transpiledJsOutputFileName and transpiledJsOutputDirectory.');
7+
}
8+
}
9+
+ /** Name of the TypeScript source file property containing the module name. */
10+
+ const MODULE_NAME_PROP = 'moduleName';
11+
+
12+
+ /**
13+
+ * Updates the given source file with a specified module name at constant time. The module name
14+
+ * is not directly assigned to the source file object, but exposed through a proxy handler that
15+
+ * wraps the source file. This ensures that changing the `moduleName` does not affect the original
16+
+ * source file which originates from a cache and should not be invalidated.
17+
+ */
18+
+ function wrapSourceFileWithModuleName(
19+
+ sourceFile: ts.SourceFile, moduleName: string): ts.SourceFile {
20+
+ return new Proxy(sourceFile, {
21+
+ has: (target, prop) => prop === MODULE_NAME_PROP || Reflect.has(target, prop),
22+
+ ownKeys: (target) => Reflect.ownKeys(target).concat(MODULE_NAME_PROP),
23+
+ getOwnPropertyDescriptor: (target, prop) => {
24+
+ if (prop === MODULE_NAME_PROP) {
25+
+ // TypeScript sometimes will enumerate through top-level properties of
26+
+ // a source file (e.g. to create a mutable clone). The module name should
27+
+ // not be skipped by accident here.
28+
+ return {configurable: true, enumerable: true};
29+
+ }
30+
+ return Reflect.getOwnPropertyDescriptor(target, prop);
31+
+ },
32+
+ get: function(target, prop, receiver) {
33+
+ if (prop === MODULE_NAME_PROP) {
34+
+ return moduleName;
35+
+ }
36+
+ return Reflect.get(target, prop, receiver);
37+
+ },
38+
+ set: function(target, prop, value, receiver) {
39+
+ if (prop === MODULE_NAME_PROP) {
40+
+ return false;
41+
+ }
42+
+ return Reflect.set(target, prop, value, receiver);
43+
+ },
44+
+ })
45+
+ }
46+
+
47+
+
48+
const SOURCE_EXT = /((\.d)?\.tsx?|\.js)$/;
49+
/**
50+
* CompilerHost that knows how to cache parsed files to improve compile times.
51+
@@ -377,9 +403,11 @@ class CompilerHost {
52+
`which would be overwritten with ${moduleName} ` +
53+
`by Bazel's TypeScript compiler.`);
54+
}
55+
- // Setting the moduleName is equivalent to the original source having a
56+
- // ///<amd-module name="some/name"/> directive
57+
- sf.moduleName = moduleName;
58+
+ // Setting the moduleName is equivalent to the original source having the triple
59+
+ // slash `///<amd-module name="some/name"/>` directive. Also note that we do not
60+
+ // directly modify the source file `moduleName` property as that means that
61+
+ // consecutive compilations using a cache could have an unexpected module name.
62+
+ return wrapSourceFileWithModuleName(sf, moduleName);
63+
}
64+
return sf;
65+
});

tools/postinstall/apply-patches.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ function applyPatches() {
110110
// Workaround for: https://github.com/bazelbuild/rules_nodejs/issues/1208.
111111
applyPatch(path.join(__dirname, './manifest_externs_hermeticity.patch'));
112112

113+
// Patches the changes from: https://github.com/bazelbuild/rules_typescript/pull/504.
114+
applyPatch(path.join(__dirname, './@bazel_typescript_tsc_wrapped_worker_cache_fix.patch'));
115+
113116
try {
114117
// Temporary patch pre-req for https://github.com/angular/angular/pull/36333.
115118
// Can be removed once @angular/bazel is updated here to include this patch.

0 commit comments

Comments
 (0)