-
Notifications
You must be signed in to change notification settings - Fork 27.2k
Expand file tree
/
Copy pathesbuild-plugin.mjs
More file actions
119 lines (103 loc) · 4.3 KB
/
esbuild-plugin.mjs
File metadata and controls
119 lines (103 loc) · 4.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/**
* @license
* Copyright Google LLC
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.dev/license
*/
import fs from 'fs';
import babel from '@babel/core';
import {assertNoPartialDeclaration} from './ensure-no-linker-decl.mjs';
/**
* Creates an ESBuild plugin that configures various Angular optimization Babel plugins.
* The Babel plugins configured usually run in the Angular CLI compilation pipeline.
*
* @param {import('./esbuild-plugin').OptimizationOptions} opts Options
* @param additionalBabelPlugins List of additional Babel plugins that should run as part
* of this ESBuild plugin. This is primarily supported for reducing the amount of ESBuild
* load plugins needed (as they can impact performance significantly).
*/
export async function createEsbuildAngularOptimizePlugin(opts, additionalBabelPlugins = []) {
let linkerCreator = {
compiler: null,
babel: null,
};
let downlevelAsyncGeneratorPlugin = null;
if (opts.enableLinker) {
linkerCreator = {
compiler: await import('@angular/compiler-cli'),
babel: await import('@angular/compiler-cli/linker/babel'),
};
}
if (opts.downlevelAsyncGeneratorsIfPresent) {
downlevelAsyncGeneratorPlugin = (
await import('@babel/plugin-transform-async-generator-functions')
).default.default;
}
const {adjustStaticMembers, adjustTypeScriptEnums, elideAngularMetadata, markTopLevelPure} = (
await import('@angular/build/private')
).default;
return {
name: 'ng-babel-optimize-esbuild',
setup: (build) => {
build.onLoad({filter: /\.[cm]?js$/}, async (args) => {
const filePath = args.path;
const content = await fs.promises.readFile(filePath, 'utf8');
const plugins = [...additionalBabelPlugins];
if (opts.optimize) {
plugins.push(adjustStaticMembers, adjustTypeScriptEnums, elideAngularMetadata);
// If the current file is denoted as explicit side effect free, add the pure
// top-level functions optimization plugin for this file.
if (opts.optimize.isSideEffectFree && opts.optimize.isSideEffectFree(args.path)) {
plugins.push(markTopLevelPure);
}
}
const shouldRunLinker =
opts.enableLinker &&
(opts.enableLinker.filterPaths == null || opts.enableLinker.filterPaths.test(args.path));
if (shouldRunLinker) {
plugins.push(
linkerCreator.babel.createEs2015LinkerPlugin({
...(opts.enableLinker.linkerOptions ?? {}),
fileSystem: new linkerCreator.compiler.NodeJSFileSystem(),
logger: new linkerCreator.compiler.ConsoleLogger(
linkerCreator.compiler.LogLevel.warn,
),
// Workaround for https://github.com/angular/angular/issues/42769 and https://github.com/angular/angular-cli/issues/22647.
sourceMapping: false,
}),
);
}
// Matches Angular CLIs detection:
// https://github.com/angular/angular-cli/blob/afe9feaa45913cbebe7f22c678d693d96f38584a/packages/angular_devkit/build_angular/src/builders/browser-esbuild/javascript-transformer.ts#L74-L76
if (
opts.downlevelAsyncGeneratorsIfPresent &&
content.includes('async') &&
/async(\s+function)?\s*\*/.test(content)
) {
plugins.push(downlevelAsyncGeneratorPlugin);
}
// If no plugins are enabled, return the original code and save time.
if (plugins.length === 0) {
return {contents: content};
}
const ensureNoPartialDeclaration =
opts.enableLinker && opts.enableLinker.ensureNoPartialDeclaration;
const {code, ast} = await babel.transformAsync(content, {
filename: filePath,
filenameRelative: filePath,
plugins: plugins,
// Sourcemaps are generated inline so that ESBuild can process them.
sourceMaps: 'inline',
compact: false,
// AST is needed when we want to ensure no partial declarations later.
ast: ensureNoPartialDeclaration,
});
if (ensureNoPartialDeclaration) {
assertNoPartialDeclaration(filePath, ast, babel.traverse);
}
return {contents: code};
});
},
};
}