-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathwebpack-loader.js
168 lines (168 loc) · 8.27 KB
/
webpack-loader.js
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
"use strict";
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* 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
*/
Object.defineProperty(exports, "__esModule", { value: true });
const babel_loader_1 = require("babel-loader");
const load_esm_1 = require("../../utils/load-esm");
const package_version_1 = require("../../utils/package-version");
const application_1 = require("./presets/application");
/**
* Cached instance of the compiler-cli linker's Babel plugin factory function.
*/
let linkerPluginCreator;
/**
* Cached instance of the localize Babel plugins factory functions.
*/
let i18nPluginCreators;
// eslint-disable-next-line max-lines-per-function
exports.default = (0, babel_loader_1.custom)(() => {
const baseOptions = Object.freeze({
babelrc: false,
configFile: false,
compact: false,
cacheCompression: false,
sourceType: 'unambiguous',
inputSourceMap: false,
});
return {
async customOptions(options, { source, map }) {
const { i18n, aot, optimize, instrumentCode, supportedBrowsers, ...rawOptions } = options;
// Must process file if plugins are added
let shouldProcess = Array.isArray(rawOptions.plugins) && rawOptions.plugins.length > 0;
const customOptions = {
forceAsyncTransformation: false,
angularLinker: undefined,
i18n: undefined,
instrumentCode: undefined,
supportedBrowsers,
};
// Analyze file for linking
if (await (0, application_1.requiresLinking)(this.resourcePath, source)) {
// Load ESM `@angular/compiler-cli/linker/babel` using the TypeScript dynamic import workaround.
// Once TypeScript provides support for keeping the dynamic import this workaround can be
// changed to a direct dynamic import.
linkerPluginCreator ??= (await (0, load_esm_1.loadEsmModule)('@angular/compiler-cli/linker/babel')).createEs2015LinkerPlugin;
customOptions.angularLinker = {
shouldLink: true,
jitMode: aot !== true,
linkerPluginCreator,
};
shouldProcess = true;
}
// Application code (TS files) will only contain native async if target is ES2017+.
// However, third-party libraries can regardless of the target option.
// APF packages with code in [f]esm2015 directories is downlevelled to ES2015 and
// will not have native async.
customOptions.forceAsyncTransformation =
!/[\\/][_f]?esm2015[\\/]/.test(this.resourcePath) && source.includes('async');
shouldProcess ||=
customOptions.forceAsyncTransformation ||
customOptions.supportedBrowsers !== undefined ||
false;
// Analyze for i18n inlining
if (i18n &&
!/[\\/]@angular[\\/](?:compiler|localize)/.test(this.resourcePath) &&
source.includes('$localize')) {
// Load the i18n plugin creators from the new `@angular/localize/tools` entry point.
// This may fail during the transition to ESM due to the entry point not yet existing.
// During the transition, this will always attempt to load the entry point for each file.
// This will only occur during prerelease and will be automatically corrected once the new
// entry point exists.
if (i18nPluginCreators === undefined) {
// Load ESM `@angular/localize/tools` using the TypeScript dynamic import workaround.
// Once TypeScript provides support for keeping the dynamic import this workaround can be
// changed to a direct dynamic import.
i18nPluginCreators = await (0, load_esm_1.loadEsmModule)('@angular/localize/tools');
}
customOptions.i18n = {
...i18n,
pluginCreators: i18nPluginCreators,
};
// Add translation files as dependencies of the file to support rebuilds
// Except for `@angular/core` which needs locale injection but has no translations
if (customOptions.i18n.translationFiles &&
!/[\\/]@angular[\\/]core/.test(this.resourcePath)) {
for (const file of customOptions.i18n.translationFiles) {
this.addDependency(file);
}
}
shouldProcess = true;
}
if (optimize) {
const AngularPackage = /[\\/]node_modules[\\/]@angular[\\/]/.test(this.resourcePath);
const sideEffectFree = !!this._module?.factoryMeta?.sideEffectFree;
customOptions.optimize = {
// Angular packages provide additional tested side effects guarantees and can use
// otherwise unsafe optimizations. (@angular/platform-server/init) however has side-effects.
pureTopLevel: AngularPackage && sideEffectFree,
// JavaScript modules that are marked as side effect free are considered to have
// no decorators that contain non-local effects.
wrapDecorators: sideEffectFree,
};
shouldProcess = true;
}
if (instrumentCode &&
!instrumentCode.excludedPaths.has(this.resourcePath) &&
!/\.(e2e|spec)\.tsx?$|[\\/]node_modules[\\/]/.test(this.resourcePath) &&
this.resourcePath.startsWith(instrumentCode.includedBasePath)) {
// `babel-plugin-istanbul` has it's own includes but we do the below so that we avoid running the loader.
customOptions.instrumentCode = {
includedBasePath: instrumentCode.includedBasePath,
inputSourceMap: map,
};
shouldProcess = true;
}
// Add provided loader options to default base options
const loaderOptions = {
...baseOptions,
...rawOptions,
cacheIdentifier: JSON.stringify({
buildAngular: package_version_1.VERSION,
customOptions,
baseOptions,
rawOptions,
}),
};
// Skip babel processing if no actions are needed
if (!shouldProcess) {
// Force the current file to be ignored
loaderOptions.ignore = [() => true];
}
return { custom: customOptions, loader: loaderOptions };
},
config(configuration, { customOptions }) {
return {
...configuration.options,
// Using `false` disables babel from attempting to locate sourcemaps or process any inline maps.
// The babel types do not include the false option even though it is valid
// eslint-disable-next-line @typescript-eslint/no-explicit-any
inputSourceMap: configuration.options.inputSourceMap ?? false,
presets: [
...(configuration.options.presets || []),
[
require('./presets/application').default,
{
...customOptions,
diagnosticReporter: (type, message) => {
switch (type) {
case 'error':
this.emitError(message);
break;
case 'info': // Webpack does not currently have an informational diagnostic
case 'warning':
this.emitWarning(message);
break;
}
},
},
],
],
};
},
};
});