fix(@angular-devkit/build-angular): properly process es2016+ targets with differential loading

A target of es2015 was previously assumed when using differential loading.  This could result in erroneously downleveling an es2016+ output file instead of generating a new es5 output file.
This commit is contained in:
Charles Lyding 2019-11-19 12:34:16 -05:00 committed by Douglas Parker
parent 5c9fc32ae6
commit cfc0aa4780
4 changed files with 58 additions and 18 deletions

View File

@ -370,7 +370,7 @@ export function buildWebpackBrowser(
} }
// If not optimizing then ES2015 polyfills do not need processing // If not optimizing then ES2015 polyfills do not need processing
// Unlike other module scripts, it is never downleveled // Unlike other module scripts, it is never downleveled
const es2015Polyfills = file.file.startsWith('polyfills-es2015'); const es2015Polyfills = file.file.startsWith('polyfills-es20');
if (!actionOptions.optimize && es2015Polyfills) { if (!actionOptions.optimize && es2015Polyfills) {
continue; continue;
} }
@ -392,7 +392,7 @@ export function buildWebpackBrowser(
if (es5Polyfills) { if (es5Polyfills) {
fs.unlinkSync(filename); fs.unlinkSync(filename);
filename = filename.replace('-es2015', ''); filename = filename.replace(/\-es20\d{2}/, '');
} }
// Record the bundle processing action // Record the bundle processing action
@ -417,8 +417,8 @@ export function buildWebpackBrowser(
// Add the newly created ES5 bundles to the index as nomodule scripts // Add the newly created ES5 bundles to the index as nomodule scripts
const newFilename = es5Polyfills const newFilename = es5Polyfills
? file.file.replace('-es2015', '') ? file.file.replace(/\-es20\d{2}/, '')
: file.file.replace('es2015', 'es5'); : file.file.replace(/\-es20\d{2}/, '-es5');
noModuleFiles.push({ ...file, file: newFilename }); noModuleFiles.push({ ...file, file: newFilename });
} }

View File

@ -148,7 +148,7 @@ export class BundleActionCache {
cacheEntry = entries[CacheKey.DownlevelCode]; cacheEntry = entries[CacheKey.DownlevelCode];
if (cacheEntry) { if (cacheEntry) {
result.downlevel = { result.downlevel = {
filename: action.filename.replace('es2015', 'es5'), filename: action.filename.replace(/\-es20\d{2}/, '-es5'),
size: cacheEntry.size, size: cacheEntry.size,
integrity: cacheEntry.integrity, integrity: cacheEntry.integrity,
}; };
@ -158,7 +158,7 @@ export class BundleActionCache {
cacheEntry = entries[CacheKey.DownlevelMap]; cacheEntry = entries[CacheKey.DownlevelMap];
if (cacheEntry) { if (cacheEntry) {
result.downlevel.map = { result.downlevel.map = {
filename: action.filename.replace('es2015', 'es5') + '.map', filename: action.filename.replace(/\-es20\d{2}/, '-es5') + '.map',
size: cacheEntry.size, size: cacheEntry.size,
}; };

View File

@ -97,7 +97,7 @@ export async function process(options: ProcessBundleOptions): Promise<ProcessBun
const basePath = path.dirname(options.filename); const basePath = path.dirname(options.filename);
const filename = path.basename(options.filename); const filename = path.basename(options.filename);
const downlevelFilename = filename.replace('es2015', 'es5'); const downlevelFilename = filename.replace(/\-es20\d{2}/, '-es5');
const downlevel = !options.optimizeOnly; const downlevel = !options.optimizeOnly;
// if code size is larger than 500kB, manually handle sourcemaps with newer source-map package. // if code size is larger than 500kB, manually handle sourcemaps with newer source-map package.
@ -403,9 +403,9 @@ async function processRuntime(
// Adjust lazy loaded scripts to point to the proper variant // Adjust lazy loaded scripts to point to the proper variant
// Extra spacing is intentional to align source line positions // Extra spacing is intentional to align source line positions
downlevelCode = downlevelCode.replace('"-es2015.', ' "-es5.'); downlevelCode = downlevelCode.replace(/"\-es20\d{2}\./, ' "-es5.');
const downlevelFilePath = options.filename.replace('es2015', 'es5'); const downlevelFilePath = options.filename.replace(/\-es20\d{2}/, '-es5');
let downlevelMap; let downlevelMap;
let result; let result;
if (options.optimize) { if (options.optimize) {

View File

@ -26,7 +26,7 @@ describe('Browser Builder with differential loading', () => {
afterEach(async () => host.restore().toPromise()); afterEach(async () => host.restore().toPromise());
it('emits all the neccessary files', async () => { it('emits all the neccessary files for default configuration', async () => {
const { files } = await browserBuild(architect, host, target); const { files } = await browserBuild(architect, host, target);
const expectedOutputs = [ const expectedOutputs = [
@ -62,6 +62,48 @@ describe('Browser Builder with differential loading', () => {
expect(Object.keys(files)).toEqual(jasmine.arrayWithExactContents(expectedOutputs)); expect(Object.keys(files)).toEqual(jasmine.arrayWithExactContents(expectedOutputs));
}); });
it('emits all the neccessary files for target of ES2016', async () => {
host.replaceInFile(
'tsconfig.json',
'"target": "es2015",',
`"target": "es2016",`,
);
const { files } = await browserBuild(architect, host, target);
const expectedOutputs = [
'favicon.ico',
'index.html',
'main-es2016.js',
'main-es2016.js.map',
'main-es5.js',
'main-es5.js.map',
'polyfills-es2016.js',
'polyfills-es2016.js.map',
'polyfills-es5.js',
'polyfills-es5.js.map',
'runtime-es2016.js',
'runtime-es2016.js.map',
'runtime-es5.js',
'runtime-es5.js.map',
'styles-es2016.js',
'styles-es2016.js.map',
'styles-es5.js',
'styles-es5.js.map',
'vendor-es2016.js',
'vendor-es2016.js.map',
'vendor-es5.js',
'vendor-es5.js.map',
] as PathFragment[];
expect(Object.keys(files)).toEqual(jasmine.arrayWithExactContents(expectedOutputs));
});
it('deactivates differential loading for watch mode', async () => { it('deactivates differential loading for watch mode', async () => {
const { files } = await browserBuild(architect, host, target, { watch: true }); const { files } = await browserBuild(architect, host, target, { watch: true });
@ -89,14 +131,12 @@ describe('Browser Builder with differential loading', () => {
}); });
it('emits the right ES formats', async () => { it('emits the right ES formats', async () => {
if (!process.env['NG_BUILD_FULL_DIFFERENTIAL']) { const { files } = await browserBuild(architect, host, target, {
// The test fails depending on the order of previously executed tests optimization: true,
// The wrong data is being read from the filesystem. vendorChunk: false,
pending('Incredibly flaky outside full build differential loading'); });
} expect(await files['main-es5.js']).not.toContain('const ');
const { files } = await browserBuild(architect, host, target, { optimization: true }); expect(await files['main-es2015.js']).toContain('const ');
expect(await files['main-es5.js']).not.toContain('class');
expect(await files['main-es2015.js']).toContain('class');
}); });
it('uses the right zone.js variant', async () => { it('uses the right zone.js variant', async () => {