@angular-devkit/build-angular 14.0.0-rc.1 → 14.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -5
- package/src/babel/presets/application.d.ts +2 -1
- package/src/babel/presets/application.js +2 -3
- package/src/babel/webpack-loader.js +27 -15
- package/src/builders/browser-esbuild/esbuild.d.ts +2 -0
- package/src/builders/browser-esbuild/esbuild.js +4 -1
- package/src/builders/browser-esbuild/index.js +14 -10
- package/src/builders/browser-esbuild/stylesheets.js +2 -1
- package/src/builders/protractor/index.js +50 -52
- package/src/webpack/configs/common.js +1 -0
- package/src/webpack/configs/styles.js +17 -10
- package/src/webpack/plugins/css-optimizer-plugin.js +7 -0
- package/src/webpack/plugins/javascript-optimizer-plugin.js +6 -0
- package/src/webpack/plugins/typescript.js +5 -0
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@angular-devkit/build-angular",
|
|
3
|
-
"version": "14.0.0
|
|
3
|
+
"version": "14.0.0",
|
|
4
4
|
"description": "Angular Webpack Build Facade",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"typings": "src/index.d.ts",
|
|
7
7
|
"builders": "builders.json",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@ampproject/remapping": "2.2.0",
|
|
10
|
-
"@angular-devkit/architect": "0.1400.0
|
|
11
|
-
"@angular-devkit/build-webpack": "0.1400.0
|
|
12
|
-
"@angular-devkit/core": "14.0.0
|
|
10
|
+
"@angular-devkit/architect": "0.1400.0",
|
|
11
|
+
"@angular-devkit/build-webpack": "0.1400.0",
|
|
12
|
+
"@angular-devkit/core": "14.0.0",
|
|
13
13
|
"@babel/core": "7.17.10",
|
|
14
14
|
"@babel/generator": "7.17.10",
|
|
15
15
|
"@babel/helper-annotate-as-pure": "7.16.7",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@babel/runtime": "7.17.9",
|
|
21
21
|
"@babel/template": "7.16.7",
|
|
22
22
|
"@discoveryjs/json-ext": "0.5.7",
|
|
23
|
-
"@ngtools/webpack": "14.0.0
|
|
23
|
+
"@ngtools/webpack": "14.0.0",
|
|
24
24
|
"ansi-colors": "4.1.1",
|
|
25
25
|
"babel-loader": "8.2.5",
|
|
26
26
|
"babel-plugin-istanbul": "6.1.1",
|
|
@@ -32,7 +32,7 @@ export interface ApplicationPresetOptions {
|
|
|
32
32
|
jitMode: boolean;
|
|
33
33
|
linkerPluginCreator: typeof import('@angular/compiler-cli/linker/babel').createEs2015LinkerPlugin;
|
|
34
34
|
};
|
|
35
|
-
|
|
35
|
+
forcePresetEnv?: boolean;
|
|
36
36
|
forceAsyncTransformation?: boolean;
|
|
37
37
|
instrumentCode?: {
|
|
38
38
|
includedBasePath: string;
|
|
@@ -43,6 +43,7 @@ export interface ApplicationPresetOptions {
|
|
|
43
43
|
pureTopLevel: boolean;
|
|
44
44
|
wrapDecorators: boolean;
|
|
45
45
|
};
|
|
46
|
+
supportedBrowsers?: string[];
|
|
46
47
|
diagnosticReporter?: DiagnosticReporter;
|
|
47
48
|
}
|
|
48
49
|
export default function (api: unknown, options: ApplicationPresetOptions): {
|
|
@@ -116,14 +116,13 @@ function default_1(api, options) {
|
|
|
116
116
|
},
|
|
117
117
|
}));
|
|
118
118
|
}
|
|
119
|
-
if (options.
|
|
119
|
+
if (options.forcePresetEnv) {
|
|
120
120
|
presets.push([
|
|
121
121
|
require('@babel/preset-env').default,
|
|
122
122
|
{
|
|
123
123
|
bugfixes: true,
|
|
124
124
|
modules: false,
|
|
125
|
-
|
|
126
|
-
targets: { ie: 9 },
|
|
125
|
+
targets: options.supportedBrowsers,
|
|
127
126
|
exclude: ['transform-typeof-symbol'],
|
|
128
127
|
},
|
|
129
128
|
]);
|
|
@@ -53,15 +53,16 @@ exports.default = (0, babel_loader_1.custom)(() => {
|
|
|
53
53
|
return {
|
|
54
54
|
async customOptions(options, { source, map }) {
|
|
55
55
|
var _a, _b;
|
|
56
|
-
const { i18n, scriptTarget, aot, optimize, instrumentCode, ...rawOptions } = options;
|
|
56
|
+
const { i18n, scriptTarget, aot, optimize, instrumentCode, supportedBrowsers, ...rawOptions } = options;
|
|
57
57
|
// Must process file if plugins are added
|
|
58
58
|
let shouldProcess = Array.isArray(rawOptions.plugins) && rawOptions.plugins.length > 0;
|
|
59
59
|
const customOptions = {
|
|
60
60
|
forceAsyncTransformation: false,
|
|
61
|
-
|
|
61
|
+
forcePresetEnv: false,
|
|
62
62
|
angularLinker: undefined,
|
|
63
63
|
i18n: undefined,
|
|
64
64
|
instrumentCode: undefined,
|
|
65
|
+
supportedBrowsers,
|
|
65
66
|
};
|
|
66
67
|
// Analyze file for linking
|
|
67
68
|
if (await requiresLinking(this.resourcePath, source)) {
|
|
@@ -78,20 +79,31 @@ exports.default = (0, babel_loader_1.custom)(() => {
|
|
|
78
79
|
}
|
|
79
80
|
// Analyze for ES target processing
|
|
80
81
|
const esTarget = scriptTarget;
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
const isJsFile = /\.[cm]?js$/.test(this.resourcePath);
|
|
83
|
+
// The below should be dropped when we no longer support ES5 TypeScript output.
|
|
84
|
+
if (esTarget === typescript_1.ScriptTarget.ES5) {
|
|
85
|
+
// This is needed because when target is ES5 we change the TypeScript target to ES2015
|
|
86
|
+
// because it simplifies build-optimization passes.
|
|
87
|
+
// @see https://github.com/angular/angular-cli/blob/22af6520834171d01413d4c7e4a9f13fb752252e/packages/angular_devkit/build_angular/src/webpack/plugins/typescript.ts#L51-L56
|
|
88
|
+
customOptions.forcePresetEnv = true;
|
|
89
|
+
// Comparable behavior to tsconfig target of ES5
|
|
90
|
+
customOptions.supportedBrowsers = ['IE 9'];
|
|
91
|
+
}
|
|
92
|
+
else if (isJsFile) {
|
|
93
|
+
// Applications code ES version can be controlled using TypeScript's `target` option.
|
|
94
|
+
// However, this doesn't effect libraries and hence we use preset-env to downlevel ES fetaures
|
|
95
|
+
// based on the supported browsers in browserlist.
|
|
96
|
+
customOptions.forcePresetEnv = true;
|
|
97
|
+
}
|
|
98
|
+
if ((esTarget !== undefined && esTarget >= typescript_1.ScriptTarget.ES2017) || isJsFile) {
|
|
99
|
+
// Application code (TS files) will only contain native async if target is ES2017+.
|
|
100
|
+
// However, third-party libraries can regardless of the target option.
|
|
101
|
+
// APF packages with code in [f]esm2015 directories is downlevelled to ES2015 and
|
|
102
|
+
// will not have native async.
|
|
103
|
+
customOptions.forceAsyncTransformation =
|
|
104
|
+
!/[\\/][_f]?esm2015[\\/]/.test(this.resourcePath) && source.includes('async');
|
|
94
105
|
}
|
|
106
|
+
shouldProcess || (shouldProcess = customOptions.forceAsyncTransformation || customOptions.forcePresetEnv || false);
|
|
95
107
|
// Analyze for i18n inlining
|
|
96
108
|
if (i18n &&
|
|
97
109
|
!/[\\/]@angular[\\/](?:compiler|localize)/.test(this.resourcePath) &&
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { BuilderContext } from '@angular-devkit/architect';
|
|
9
9
|
import { BuildFailure, BuildOptions, BuildResult, Message, OutputFile } from 'esbuild';
|
|
10
|
+
/** Default outdir setting for esbuild. */
|
|
11
|
+
export declare const DEFAULT_OUTDIR: string;
|
|
10
12
|
/**
|
|
11
13
|
* Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild.
|
|
12
14
|
* @param value A potential esbuild BuildFailure error object.
|
|
@@ -7,8 +7,11 @@
|
|
|
7
7
|
* found in the LICENSE file at https://angular.io/license
|
|
8
8
|
*/
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.logMessages = exports.bundle = exports.isEsBuildFailure = void 0;
|
|
10
|
+
exports.logMessages = exports.bundle = exports.isEsBuildFailure = exports.DEFAULT_OUTDIR = void 0;
|
|
11
11
|
const esbuild_1 = require("esbuild");
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
/** Default outdir setting for esbuild. */
|
|
14
|
+
exports.DEFAULT_OUTDIR = (0, path_1.resolve)('/virtual-output');
|
|
12
15
|
/**
|
|
13
16
|
* Determines if an unknown value is an esbuild BuildFailure error object thrown by esbuild.
|
|
14
17
|
* @param value A potential esbuild BuildFailure error object.
|
|
@@ -99,11 +99,11 @@ async function execute(options, context) {
|
|
|
99
99
|
// Entries in the metafile are relative to the `absWorkingDir` option which is set to the workspaceRoot
|
|
100
100
|
const relativeFilePath = path.relative(workspaceRoot, outputFile.path);
|
|
101
101
|
const entryPoint = (_c = (_b = result.metafile) === null || _b === void 0 ? void 0 : _b.outputs[relativeFilePath]) === null || _c === void 0 ? void 0 : _c.entryPoint;
|
|
102
|
+
outputFile.path = path.relative(esbuild_1.DEFAULT_OUTDIR, outputFile.path);
|
|
102
103
|
if (entryPoint) {
|
|
103
104
|
// An entryPoint value indicates an initial file
|
|
104
105
|
initialFiles.push({
|
|
105
|
-
|
|
106
|
-
file: outputFile.path.slice(1),
|
|
106
|
+
file: outputFile.path,
|
|
107
107
|
name: (_d = entryPointNameLookup.get(entryPoint)) !== null && _d !== void 0 ? _d : '',
|
|
108
108
|
extension: path.extname(outputFile.path),
|
|
109
109
|
});
|
|
@@ -124,7 +124,9 @@ async function execute(options, context) {
|
|
|
124
124
|
// resolveGlobalStyles is temporarily reused from the Webpack builder code
|
|
125
125
|
const { entryPoints: stylesheetEntrypoints, noInjectNames } = (0, configs_1.resolveGlobalStyles)(options.styles, workspaceRoot, !!options.preserveSymlinks);
|
|
126
126
|
for (const [name, files] of Object.entries(stylesheetEntrypoints)) {
|
|
127
|
-
const virtualEntryData = files
|
|
127
|
+
const virtualEntryData = files
|
|
128
|
+
.map((file) => `@import '${file.replace(/\\/g, '/')}';`)
|
|
129
|
+
.join('\n');
|
|
128
130
|
const sheetResult = await (0, stylesheets_1.bundleStylesheetText)(virtualEntryData, { virtualName: `angular:style/global;${name}`, resolvePath: workspaceRoot }, {
|
|
129
131
|
optimization: !!optimizationOptions.styles.minify,
|
|
130
132
|
sourcemap: !!sourcemapOptions.styles,
|
|
@@ -139,7 +141,7 @@ async function execute(options, context) {
|
|
|
139
141
|
// The virtual stylesheets will be named `stdin` by esbuild. This must be replaced
|
|
140
142
|
// with the actual name of the global style and the leading directory separator must
|
|
141
143
|
// also be removed to make the path relative.
|
|
142
|
-
const sheetPath = sheetResult.path.replace('stdin', name)
|
|
144
|
+
const sheetPath = sheetResult.path.replace('stdin', name);
|
|
143
145
|
outputFiles.push(createOutputFileFromText(sheetPath, sheetResult.contents));
|
|
144
146
|
if (sheetResult.map) {
|
|
145
147
|
outputFiles.push(createOutputFileFromText(sheetPath + '.map', sheetResult.map));
|
|
@@ -168,10 +170,12 @@ async function execute(options, context) {
|
|
|
168
170
|
optimization: optimizationOptions,
|
|
169
171
|
crossOrigin: options.crossOrigin,
|
|
170
172
|
});
|
|
171
|
-
|
|
173
|
+
/** Virtual output path to support reading in-memory files. */
|
|
174
|
+
const virtualOutputPath = '/';
|
|
175
|
+
indexHtmlGenerator.readAsset = async function (filePath) {
|
|
172
176
|
// Remove leading directory separator
|
|
173
|
-
|
|
174
|
-
const file = outputFiles.find((file) => file.path ===
|
|
177
|
+
const relativefilePath = path.relative(virtualOutputPath, filePath);
|
|
178
|
+
const file = outputFiles.find((file) => file.path === relativefilePath);
|
|
175
179
|
if (file) {
|
|
176
180
|
return file.text;
|
|
177
181
|
}
|
|
@@ -180,7 +184,7 @@ async function execute(options, context) {
|
|
|
180
184
|
const { content, warnings, errors } = await indexHtmlGenerator.process({
|
|
181
185
|
baseHref: options.baseHref,
|
|
182
186
|
lang: undefined,
|
|
183
|
-
outputPath:
|
|
187
|
+
outputPath: virtualOutputPath,
|
|
184
188
|
files: initialFiles,
|
|
185
189
|
});
|
|
186
190
|
for (const error of errors) {
|
|
@@ -220,13 +224,13 @@ async function bundleCode(workspaceRoot, entryPoints, outputNames, options, opti
|
|
|
220
224
|
assetNames: outputNames.media,
|
|
221
225
|
target: 'es2020',
|
|
222
226
|
mainFields: ['es2020', 'browser', 'module', 'main'],
|
|
223
|
-
conditions: ['es2020', 'module'],
|
|
227
|
+
conditions: ['es2020', 'es2015', 'module'],
|
|
224
228
|
resolveExtensions: ['.ts', '.tsx', '.mjs', '.js'],
|
|
225
229
|
logLevel: options.verbose ? 'debug' : 'silent',
|
|
226
230
|
metafile: true,
|
|
227
231
|
minify: optimizationOptions.scripts,
|
|
228
232
|
pure: ['forwardRef'],
|
|
229
|
-
outdir:
|
|
233
|
+
outdir: esbuild_1.DEFAULT_OUTDIR,
|
|
230
234
|
sourcemap: sourcemapOptions.scripts && (sourcemapOptions.hidden ? 'external' : true),
|
|
231
235
|
splitting: true,
|
|
232
236
|
tsconfig,
|
|
@@ -45,7 +45,7 @@ async function bundleStylesheet(entry, options) {
|
|
|
45
45
|
logLevel: 'silent',
|
|
46
46
|
minify: options.optimization,
|
|
47
47
|
sourcemap: options.sourcemap,
|
|
48
|
-
outdir:
|
|
48
|
+
outdir: esbuild_1.DEFAULT_OUTDIR,
|
|
49
49
|
write: false,
|
|
50
50
|
platform: 'browser',
|
|
51
51
|
preserveSymlinks: options.preserveSymlinks,
|
|
@@ -62,6 +62,7 @@ async function bundleStylesheet(entry, options) {
|
|
|
62
62
|
const resourceFiles = [];
|
|
63
63
|
if (result.outputFiles) {
|
|
64
64
|
for (const outputFile of result.outputFiles) {
|
|
65
|
+
outputFile.path = path.relative(esbuild_1.DEFAULT_OUTDIR, outputFile.path);
|
|
65
66
|
const filename = path.basename(outputFile.path);
|
|
66
67
|
if (filename.endsWith('.css')) {
|
|
67
68
|
outputPath = outputFile.path;
|
|
@@ -100,67 +100,65 @@ async function execute(options, context) {
|
|
|
100
100
|
}
|
|
101
101
|
let baseUrl = options.baseUrl;
|
|
102
102
|
let server;
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
publicHost
|
|
103
|
+
try {
|
|
104
|
+
if (options.devServerTarget) {
|
|
105
|
+
const target = (0, architect_1.targetFromTargetString)(options.devServerTarget);
|
|
106
|
+
const serverOptions = await context.getTargetOptions(target);
|
|
107
|
+
const overrides = {
|
|
108
|
+
watch: false,
|
|
109
|
+
liveReload: false,
|
|
110
|
+
};
|
|
111
|
+
if (options.host !== undefined) {
|
|
112
|
+
overrides.host = options.host;
|
|
113
|
+
}
|
|
114
|
+
else if (typeof serverOptions.host === 'string') {
|
|
115
|
+
options.host = serverOptions.host;
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
options.host = overrides.host = 'localhost';
|
|
119
|
+
}
|
|
120
|
+
if (options.port !== undefined) {
|
|
121
|
+
overrides.port = options.port;
|
|
122
|
+
}
|
|
123
|
+
else if (typeof serverOptions.port === 'number') {
|
|
124
|
+
options.port = serverOptions.port;
|
|
125
|
+
}
|
|
126
|
+
server = await context.scheduleTarget(target, overrides);
|
|
127
|
+
const result = await server.result;
|
|
128
|
+
if (!result.success) {
|
|
129
|
+
return { success: false };
|
|
130
|
+
}
|
|
131
|
+
if (typeof serverOptions.publicHost === 'string') {
|
|
132
|
+
let publicHost = serverOptions.publicHost;
|
|
133
|
+
if (!/^\w+:\/\//.test(publicHost)) {
|
|
134
|
+
publicHost = `${serverOptions.ssl ? 'https' : 'http'}://${publicHost}`;
|
|
135
|
+
}
|
|
136
|
+
const clientUrl = url.parse(publicHost);
|
|
137
|
+
baseUrl = url.format(clientUrl);
|
|
138
|
+
}
|
|
139
|
+
else if (typeof result.baseUrl === 'string') {
|
|
140
|
+
baseUrl = result.baseUrl;
|
|
141
|
+
}
|
|
142
|
+
else if (typeof result.port === 'number') {
|
|
143
|
+
baseUrl = url.format({
|
|
144
|
+
protocol: serverOptions.ssl ? 'https' : 'http',
|
|
145
|
+
hostname: options.host,
|
|
146
|
+
port: result.port.toString(),
|
|
147
|
+
});
|
|
134
148
|
}
|
|
135
|
-
const clientUrl = url.parse(publicHost);
|
|
136
|
-
baseUrl = url.format(clientUrl);
|
|
137
|
-
}
|
|
138
|
-
else if (typeof result.baseUrl === 'string') {
|
|
139
|
-
baseUrl = result.baseUrl;
|
|
140
149
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
port: result.port.toString(),
|
|
146
|
-
});
|
|
150
|
+
// Like the baseUrl in protractor config file when using the API we need to add
|
|
151
|
+
// a trailing slash when provide to the baseUrl.
|
|
152
|
+
if (baseUrl && !baseUrl.endsWith('/')) {
|
|
153
|
+
baseUrl += '/';
|
|
147
154
|
}
|
|
148
|
-
}
|
|
149
|
-
// Like the baseUrl in protractor config file when using the API we need to add
|
|
150
|
-
// a trailing slash when provide to the baseUrl.
|
|
151
|
-
if (baseUrl && !baseUrl.endsWith('/')) {
|
|
152
|
-
baseUrl += '/';
|
|
153
|
-
}
|
|
154
|
-
try {
|
|
155
155
|
return await runProtractor(context.workspaceRoot, { ...options, baseUrl });
|
|
156
156
|
}
|
|
157
157
|
catch {
|
|
158
158
|
return { success: false };
|
|
159
159
|
}
|
|
160
160
|
finally {
|
|
161
|
-
|
|
162
|
-
await server.stop();
|
|
163
|
-
}
|
|
161
|
+
await (server === null || server === void 0 ? void 0 : server.stop());
|
|
164
162
|
}
|
|
165
163
|
}
|
|
166
164
|
exports.execute = execute;
|
|
@@ -300,6 +300,7 @@ async function getCommonConfig(wco) {
|
|
|
300
300
|
scriptTarget,
|
|
301
301
|
aot: buildOptions.aot,
|
|
302
302
|
optimize: buildOptions.buildOptimizer,
|
|
303
|
+
supportedBrowsers: buildOptions.supportedBrowsers,
|
|
303
304
|
instrumentCode: codeCoverage
|
|
304
305
|
? {
|
|
305
306
|
includedBasePath: sourceRoot,
|
|
@@ -110,19 +110,10 @@ function getStylesConfig(wco) {
|
|
|
110
110
|
const assetNameTemplate = (0, helpers_1.assetNameTemplateFactory)(hashFormat);
|
|
111
111
|
const extraPostcssPlugins = [];
|
|
112
112
|
// Attempt to setup Tailwind CSS
|
|
113
|
-
// A configuration file can exist in the project or workspace root
|
|
114
|
-
const tailwindConfigFile = 'tailwind.config.js';
|
|
115
|
-
let tailwindConfigPath;
|
|
116
|
-
for (const basePath of [wco.projectRoot, wco.root]) {
|
|
117
|
-
const fullPath = path.join(basePath, tailwindConfigFile);
|
|
118
|
-
if (fs.existsSync(fullPath)) {
|
|
119
|
-
tailwindConfigPath = fullPath;
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
113
|
// Only load Tailwind CSS plugin if configuration file was found.
|
|
124
114
|
// This acts as a guard to ensure the project actually wants to use Tailwind CSS.
|
|
125
115
|
// The package may be unknowningly present due to a third-party transitive package dependency.
|
|
116
|
+
const tailwindConfigPath = getTailwindConfigPath(wco);
|
|
126
117
|
if (tailwindConfigPath) {
|
|
127
118
|
let tailwindPackagePath;
|
|
128
119
|
try {
|
|
@@ -374,3 +365,19 @@ function getStylesConfig(wco) {
|
|
|
374
365
|
};
|
|
375
366
|
}
|
|
376
367
|
exports.getStylesConfig = getStylesConfig;
|
|
368
|
+
function getTailwindConfigPath({ projectRoot, root }) {
|
|
369
|
+
// A configuration file can exist in the project or workspace root
|
|
370
|
+
// The list of valid config files can be found:
|
|
371
|
+
// https://github.com/tailwindlabs/tailwindcss/blob/8845d112fb62d79815b50b3bae80c317450b8b92/src/util/resolveConfigPath.js#L46-L52
|
|
372
|
+
const tailwindConfigFiles = ['tailwind.config.js', 'tailwind.config.cjs'];
|
|
373
|
+
for (const basePath of [projectRoot, root]) {
|
|
374
|
+
for (const configFile of tailwindConfigFiles) {
|
|
375
|
+
// Irrespective of the name project level configuration should always take precedence.
|
|
376
|
+
const fullPath = path.join(basePath, configFile);
|
|
377
|
+
if (fs.existsSync(fullPath)) {
|
|
378
|
+
return fullPath;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
@@ -30,11 +30,13 @@ class CssOptimizerPlugin {
|
|
|
30
30
|
apply(compiler) {
|
|
31
31
|
const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
|
|
32
32
|
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
33
|
+
const logger = compilation.getLogger('build-angular.CssOptimizerPlugin');
|
|
33
34
|
compilation.hooks.processAssets.tapPromise({
|
|
34
35
|
name: PLUGIN_NAME,
|
|
35
36
|
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
|
|
36
37
|
}, async (compilationAssets) => {
|
|
37
38
|
const cache = compilation.options.cache && compilation.getCache(PLUGIN_NAME);
|
|
39
|
+
logger.time('optimize css assets');
|
|
38
40
|
for (const assetName of Object.keys(compilationAssets)) {
|
|
39
41
|
if (!/\.(?:css|scss|sass|less|styl)$/.test(assetName)) {
|
|
40
42
|
continue;
|
|
@@ -51,6 +53,7 @@ class CssOptimizerPlugin {
|
|
|
51
53
|
cacheItem = cache.getItemCache(name, eTag);
|
|
52
54
|
const cachedOutput = await cacheItem.getPromise();
|
|
53
55
|
if (cachedOutput) {
|
|
56
|
+
logger.debug(`${name} restored from cache`);
|
|
54
57
|
await this.addWarnings(compilation, cachedOutput.warnings);
|
|
55
58
|
compilation.updateAsset(name, cachedOutput.source, (assetInfo) => ({
|
|
56
59
|
...assetInfo,
|
|
@@ -61,7 +64,10 @@ class CssOptimizerPlugin {
|
|
|
61
64
|
}
|
|
62
65
|
const { source, map: inputMap } = styleAssetSource.sourceAndMap();
|
|
63
66
|
const input = typeof source === 'string' ? source : source.toString();
|
|
67
|
+
const optimizeAssetLabel = `optimize asset: ${asset.name}`;
|
|
68
|
+
logger.time(optimizeAssetLabel);
|
|
64
69
|
const { code, warnings, map } = await this.optimize(input, asset.name, inputMap, this.targets);
|
|
70
|
+
logger.timeEnd(optimizeAssetLabel);
|
|
65
71
|
await this.addWarnings(compilation, warnings);
|
|
66
72
|
const optimizedAsset = map
|
|
67
73
|
? new SourceMapSource(code, name, map)
|
|
@@ -75,6 +81,7 @@ class CssOptimizerPlugin {
|
|
|
75
81
|
warnings,
|
|
76
82
|
}));
|
|
77
83
|
}
|
|
84
|
+
logger.timeEnd('optimize css assets');
|
|
78
85
|
});
|
|
79
86
|
});
|
|
80
87
|
}
|
|
@@ -38,10 +38,12 @@ class JavaScriptOptimizerPlugin {
|
|
|
38
38
|
apply(compiler) {
|
|
39
39
|
const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
|
|
40
40
|
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
|
|
41
|
+
const logger = compilation.getLogger('build-angular.JavaScriptOptimizerPlugin');
|
|
41
42
|
compilation.hooks.processAssets.tapPromise({
|
|
42
43
|
name: PLUGIN_NAME,
|
|
43
44
|
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
|
|
44
45
|
}, async (compilationAssets) => {
|
|
46
|
+
logger.time('optimize js assets');
|
|
45
47
|
const scriptsToOptimize = [];
|
|
46
48
|
const cache = compilation.options.cache && compilation.getCache('JavaScriptOptimizerPlugin');
|
|
47
49
|
// Analyze the compilation assets for scripts that require optimization
|
|
@@ -61,6 +63,7 @@ class JavaScriptOptimizerPlugin {
|
|
|
61
63
|
cacheItem = cache.getItemCache(name, eTag);
|
|
62
64
|
const cachedOutput = await cacheItem.getPromise();
|
|
63
65
|
if (cachedOutput) {
|
|
66
|
+
logger.debug(`${name} restored from cache`);
|
|
64
67
|
compilation.updateAsset(name, cachedOutput.source, (assetInfo) => ({
|
|
65
68
|
...assetInfo,
|
|
66
69
|
minimized: true,
|
|
@@ -125,6 +128,7 @@ class JavaScriptOptimizerPlugin {
|
|
|
125
128
|
try {
|
|
126
129
|
const tasks = [];
|
|
127
130
|
for (const { name, code, map, cacheItem } of scriptsToOptimize) {
|
|
131
|
+
logger.time(`optimize asset: ${name}`);
|
|
128
132
|
tasks.push(workerPool
|
|
129
133
|
.run({
|
|
130
134
|
asset: {
|
|
@@ -142,6 +146,7 @@ class JavaScriptOptimizerPlugin {
|
|
|
142
146
|
...assetInfo,
|
|
143
147
|
minimized: true,
|
|
144
148
|
}));
|
|
149
|
+
logger.timeEnd(`optimize asset: ${name}`);
|
|
145
150
|
return cacheItem === null || cacheItem === void 0 ? void 0 : cacheItem.storePromise({
|
|
146
151
|
source: optimizedAsset,
|
|
147
152
|
});
|
|
@@ -155,6 +160,7 @@ class JavaScriptOptimizerPlugin {
|
|
|
155
160
|
finally {
|
|
156
161
|
void workerPool.destroy();
|
|
157
162
|
}
|
|
163
|
+
logger.timeEnd('optimize js assets');
|
|
158
164
|
});
|
|
159
165
|
});
|
|
160
166
|
}
|
|
@@ -20,6 +20,7 @@ function ensureIvy(wco) {
|
|
|
20
20
|
'\nFor additional information or if the build fails, please see https://angular.io/guide/ivy');
|
|
21
21
|
wco.tsConfig.options.enableIvy = true;
|
|
22
22
|
}
|
|
23
|
+
let es5TargetWarningsShown = false;
|
|
23
24
|
function createIvyPlugin(wco, aot, tsconfig) {
|
|
24
25
|
if (aot) {
|
|
25
26
|
ensureIvy(wco);
|
|
@@ -39,6 +40,10 @@ function createIvyPlugin(wco, aot, tsconfig) {
|
|
|
39
40
|
// as for third-party libraries. This greatly reduces the complexity of static analysis.
|
|
40
41
|
if (wco.scriptTarget < typescript_1.ScriptTarget.ES2015) {
|
|
41
42
|
compilerOptions.target = typescript_1.ScriptTarget.ES2015;
|
|
43
|
+
if (!es5TargetWarningsShown) {
|
|
44
|
+
wco.logger.warn('DEPRECATED: ES5 output is deprecated. Please update TypeScript `target` compiler option to ES2015 or later.');
|
|
45
|
+
es5TargetWarningsShown = true;
|
|
46
|
+
}
|
|
42
47
|
}
|
|
43
48
|
const fileReplacements = {};
|
|
44
49
|
if (buildOptions.fileReplacements) {
|