豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit c154da1

Browse files
committed
fix(bazel): downlevel async generators along with async/await
This is necessary as ESBuild does not support it. It is also needed to bring our pipeline in sync with the Angular CLI. Note that I combined both linker & optimization into a single plugin so that we do not have to run slow Babel compilations more than once. This matches with the Angular CLI too. Long-term we might be able to leverage a plugin from them directly when the ESBuild builder is the default.
1 parent 9a7aea3 commit c154da1

File tree

12 files changed

+196
-173
lines changed

12 files changed

+196
-173
lines changed

bazel/app-bundling/esbuild.config-tmpl.mjs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import * as path from 'path';
1010

1111
import {createEsbuildAngularOptimizePlugin} from '@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs';
12-
import {createEs2015LinkerPlugin} from '@angular/compiler-cli/linker/babel';
13-
import {ConsoleLogger, NodeJSFileSystem, LogLevel} from '@angular/compiler-cli';
1412
import {GLOBAL_DEFS_FOR_TERSER_WITH_AOT} from '@angular/compiler-cli/private/tooling';
1513

1614
/** Root path pointing to the app bundle source entry-point file. */
@@ -31,13 +29,6 @@ function isFileSideEffectFree(filePath) {
3129
return !filePath.includes(entryPointBasepath);
3230
}
3331

34-
/** Babel plugin running the Angular linker. */
35-
const linkerBabelPlugin = createEs2015LinkerPlugin({
36-
fileSystem: new NodeJSFileSystem(),
37-
logger: new ConsoleLogger(LogLevel.warn),
38-
linkerJitMode: false,
39-
});
40-
4132
export default {
4233
// Note: We prefer `.mjs` here as this is the extension used by Angular APF packages.
4334
resolveExtensions: ['.mjs', '.js'],
@@ -58,7 +49,20 @@ export default {
5849
},
5950
// ESBuild requires the `define` option to take a string-based dictionary.
6051
define: convertObjectToStringDictionary(GLOBAL_DEFS_FOR_TERSER_WITH_AOT),
61-
plugins: [createEsbuildAngularOptimizePlugin(isFileSideEffectFree, [linkerBabelPlugin])],
52+
plugins: [
53+
await createEsbuildAngularOptimizePlugin({
54+
optimize: {
55+
isFileSideEffectFree: isFileSideEffectFree,
56+
},
57+
downlevelAsyncGeneratorsIfPresent: true,
58+
enableLinker: {
59+
ensureNoPartialDeclaration: false,
60+
linkerOptions: {
61+
linkerJitMode: false,
62+
},
63+
},
64+
}),
65+
],
6266
};
6367

6468
/** Converts an object to a string dictionary. */

bazel/spec-bundling/esbuild.config-tmpl.mjs

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,17 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
/**
10-
* Loads and creates the ESBuild linker plugin.
11-
*
12-
* The plugin is not loaded at top-level as not all spec bundle targets rely
13-
* on the linker and this would slow-down bundling.
14-
*/
15-
async function fetchAndCreateLinkerEsbuildPlugin() {
16-
// Note: This needs to be a NPM module path as this ESBuild config is generated and can
17-
// end up in arbitrary Bazel packages or differently-named consumer workspaces.
18-
const {createLinkerEsbuildPlugin} = await import(
19-
'@angular/build-tooling/shared-scripts/angular-linker/esbuild-plugin.mjs'
20-
);
21-
return await createLinkerEsbuildPlugin(/.*/, /* ensureNoPartialDeclaration */ true, {
22-
unknownDeclarationVersionHandling: TMPL_LINKER_UNKNOWN_DECLARATION_HANDLING,
23-
});
24-
}
25-
26-
// Based on the Bazel action and its substitutions, we run the linker for all inputs.
27-
const plugins = TMPL_RUN_LINKER ? [await fetchAndCreateLinkerEsbuildPlugin()] : [];
9+
import {createEsbuildAngularOptimizePlugin} from '@angular/build-tooling/shared-scripts/angular-optimization/esbuild-plugin.mjs';
2810

2911
// List of supported features as per ESBuild. See:
3012
// https://esbuild.github.io/api/#supported.
3113
const supported = {};
3214

15+
const downlevelAsyncAwait = TMPL_DOWNLEVEL_ASYNC_AWAIT;
16+
3317
// Async/Await can be downleveled so that ZoneJS can intercept. See:
3418
// https://github.com/angular/angular-cli/blob/afe9feaa45913/packages/angular_devkit/build_angular/src/builders/browser-esbuild/index.ts#L313-L318.
35-
if (TMPL_DOWNLEVEL_ASYNC_AWAIT) {
19+
if (downlevelAsyncAwait) {
3620
supported['async-await'] = false;
3721
}
3822

@@ -44,5 +28,20 @@ export default {
4428
// Addition of `.mjs` to the non-jsx defaults. https://esbuild.github.io/api/#resolve-extensions
4529
resolveExtensions: ['.mjs', '.js', '.json'],
4630
supported,
47-
plugins,
31+
plugins: [
32+
await createEsbuildAngularOptimizePlugin({
33+
optimize: undefined,
34+
downlevelAsyncGeneratorsIfPresent: downlevelAsyncAwait,
35+
enableLinker: TMPL_RUN_LINKER
36+
? {
37+
ensureNoPartialDeclaration: true,
38+
linkerOptions: {
39+
// JIT mode is needed for tests overriding components/modules etc.
40+
linkerJitMode: true,
41+
unknownDeclarationVersionHandling: TMPL_LINKER_UNKNOWN_DECLARATION_HANDLING,
42+
},
43+
}
44+
: undefined,
45+
}),
46+
],
4847
};

bazel/spec-bundling/spec-bundle.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def spec_bundle(
6464
name = "%s_config" % name,
6565
config_file = ":%s_config_file" % name,
6666
testonly = True,
67-
deps = ["//shared-scripts/angular-linker:js_lib"],
67+
deps = ["//shared-scripts/angular-optimization:js_lib"],
6868
)
6969

7070
if is_browser_test and not workspace_name:

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"@angular/benchpress": "0.3.0",
2121
"@babel/core": "^7.16.0",
2222
"@babel/helper-annotate-as-pure": "^7.18.6",
23+
"@babel/plugin-proposal-async-generator-functions": "^7.20.1",
2324
"@bazel/buildifier": "5.1.0",
2425
"@bazel/concatjs": "5.7.3",
2526
"@bazel/esbuild": "5.7.3",

shared-scripts/BUILD.bazel

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package(default_visibility = ["//visibility:public"])
33
filegroup(
44
name = "static_files",
55
srcs = glob(["*"]) + [
6-
"//shared-scripts/angular-linker:static_files",
76
"//shared-scripts/angular-optimization:static_files",
87
],
98
)

shared-scripts/angular-linker/BUILD.bazel

Lines changed: 0 additions & 25 deletions
This file was deleted.

shared-scripts/angular-linker/esbuild-plugin.mjs

Lines changed: 0 additions & 91 deletions
This file was deleted.

shared-scripts/angular-optimization/BUILD.bazel

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ js_library(
3131
copy_to_bin(
3232
name = "js_lib_files",
3333
srcs = [
34+
"ensure-no-linker-decl.mjs",
35+
"esbuild-plugin.d.ts",
3436
"esbuild-plugin.mjs",
3537
],
3638
)
@@ -41,6 +43,8 @@ js_library(
4143
srcs = [":js_lib_files"],
4244
deps = [
4345
":angular_devkit_plugins",
46+
"@npm//@angular/compiler-cli",
4447
"@npm//@babel/core",
48+
"@npm//@babel/plugin-proposal-async-generator-functions",
4549
],
4650
)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/** Naively checks whether this node path resolves to an Angular declare invocation. */
10+
function isNgDeclareCallExpression(nodePath) {
11+
if (!nodePath.node.name.startsWith('ɵɵngDeclare')) {
12+
return false;
13+
}
14+
15+
// Expect the `ngDeclare` identifier to be used as part of a property access that
16+
// is invoked within a call expression. e.g. `i0.ɵɵngDeclare<>`.
17+
return (
18+
nodePath.parentPath?.type === 'MemberExpression' &&
19+
nodePath.parentPath.parentPath?.type === 'CallExpression'
20+
);
21+
}
22+
23+
/** Asserts that the given AST does not contain any Angular partial declaration. */
24+
export async function assertNoPartialDeclaration(filePath, ast, traverseFn) {
25+
// Naively check if there are any Angular declarations left that haven't been linked.
26+
traverseFn(ast, {
27+
Identifier: (astPath) => {
28+
if (isNgDeclareCallExpression(astPath)) {
29+
throw astPath.buildCodeFrameError(
30+
`Found Angular declaration that has not been linked. ${filePath}`,
31+
Error,
32+
);
33+
}
34+
},
35+
});
36+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export interface OptimizationOptions {
10+
enableLinker?: {
11+
ensureNoPartialDeclaration: boolean;
12+
linkerOptions?: object;
13+
};
14+
optimize?: {
15+
isSideEffectFree?: (absoluteDiskPath: string) => boolean;
16+
};
17+
downlevelAsyncGeneratorsIfPresent?: boolean;
18+
}

0 commit comments

Comments
 (0)