Skip to content

Commit b7ee7c4

Browse files
committed
fix(@angular-devkit/build-angular): workaround high memory usage for differential loading
Large files (10MB+) currently cause an excessive amount of memory usage during AST processing. This is currently being remedied upstream. However for the current time period, this change allows for successful builds without increasing the Node.js memory limit.
1 parent 62617ee commit b7ee7c4

File tree

1 file changed

+27
-25
lines changed

1 file changed

+27
-25
lines changed

packages/angular_devkit/build_angular/src/utils/process-bundle.ts

Lines changed: 27 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
import { transformAsync } from '@babel/core';
98
import { createHash } from 'crypto';
109
import * as fs from 'fs';
1110
import * as path from 'path';
1211
import { RawSourceMap, SourceMapConsumer, SourceMapGenerator } from 'source-map';
1312
import { minify } from 'terser';
13+
import { ScriptTarget, transpileModule } from 'typescript';
14+
import { SourceMapSource } from 'webpack-sources';
1415
import { manglingDisabled } from './mangle-options';
1516

1617
const cacache = require('cacache');
@@ -91,11 +92,10 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
9192
const downlevelFilename = filename.replace('es2015', 'es5');
9293
const downlevel = !options.optimizeOnly;
9394

94-
// if code size is larger than 500kB, manually handle sourcemaps with newer source-map package.
95-
// babel currently uses an older version that still supports sync calls
95+
// if code size is larger than 1 MB, manually handle sourcemaps with newer source-map package.
9696
const codeSize = Buffer.byteLength(options.code);
9797
const mapSize = options.map ? Buffer.byteLength(options.map) : 0;
98-
const manualSourceMaps = codeSize >= 500 * 1024 || mapSize >= 500 * 1024;
98+
const manualSourceMaps = codeSize >= 1024 * 1024 || mapSize >= 1024 * 1024;
9999

100100
const sourceCode = options.code;
101101
const sourceMap = options.map ? JSON.parse(options.map) : undefined;
@@ -104,29 +104,31 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
104104
let downlevelMap;
105105
if (downlevel) {
106106
// Downlevel the bundle
107-
const transformResult = await transformAsync(sourceCode, {
108-
filename: options.filename,
109-
inputSourceMap: manualSourceMaps ? undefined : sourceMap,
110-
babelrc: false,
111-
// modules aren't needed since the bundles use webpack's custom module loading
112-
// 'transform-typeof-symbol' generates slower code
113-
presets: [['@babel/preset-env', { modules: false, exclude: ['transform-typeof-symbol'] }]],
114-
minified: options.optimize,
115-
// `false` ensures it is disabled and prevents large file warnings
116-
compact: options.optimize || false,
117-
sourceMaps: !!sourceMap,
107+
const transformResult = transpileModule(sourceCode, {
108+
fileName: downlevelFilename,
109+
compilerOptions: {
110+
sourceMap: !!sourceMap,
111+
target: ScriptTarget.ES5,
112+
},
118113
});
119114

120-
if (!transformResult || !transformResult.code) {
121-
throw new Error(`Unknown error occurred processing bundle for "${options.filename}".`);
122-
}
123-
downlevelCode = transformResult.code;
124-
125-
if (manualSourceMaps && sourceMap && transformResult.map) {
126-
downlevelMap = await mergeSourcemaps(sourceMap, transformResult.map);
127-
} else {
128-
// undefined is needed here to normalize the property type
129-
downlevelMap = transformResult.map || undefined;
115+
downlevelCode = transformResult.outputText;
116+
117+
if (sourceMap && transformResult.sourceMapText) {
118+
if (manualSourceMaps) {
119+
downlevelMap = await mergeSourcemaps(sourceMap, JSON.parse(transformResult.sourceMapText));
120+
} else {
121+
// More accurate but significantly more costly
122+
const tempSource = new SourceMapSource(
123+
transformResult.outputText,
124+
downlevelFilename,
125+
JSON.parse(transformResult.sourceMapText),
126+
sourceCode,
127+
sourceMap,
128+
);
129+
130+
downlevelMap = tempSource.map();
131+
}
130132
}
131133
}
132134

0 commit comments

Comments
 (0)