UNPKG

@angular-devkit/build-angular

Version:
169 lines (168 loc) 8.47 kB
"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; } }, }, ], ], }; }, }; });