From 4ac556ba636952c96685803bf33a442b3982a13d Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 14 May 2021 09:46:13 +0200 Subject: [PATCH] fix(@angular-devkit/build-angular): non injected styles should not count as initial Closes #20781 (cherry picked from commit 2643fb11a96befa5800683433a65b37c6bbeb6d7) --- .../src/webpack/utils/async-chunks.ts | 18 +-- .../src/webpack/utils/async-chunks_spec.ts | 144 ------------------ .../e2e/tests/basic/styles-array.ts | 11 +- 3 files changed, 15 insertions(+), 158 deletions(-) delete mode 100644 packages/angular_devkit/build_angular/src/webpack/utils/async-chunks_spec.ts diff --git a/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks.ts b/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks.ts index bec950453c9b..f8c8786396c9 100644 --- a/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks.ts +++ b/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks.ts @@ -30,18 +30,14 @@ export function markAsyncChunksNonInitial( .flatMap((entryPoint) => entryPoints[entryPoint.bundleName].chunks); // Find chunks for each ID. - const asyncChunks = asyncChunkIds - .map((chunkId) => { - const chunk = chunks.find((chunk) => chunk.id === chunkId); - if (!chunk) { - throw new Error(`Failed to find chunk (${chunkId}) in set:\n${JSON.stringify(chunks)}`); - } + const asyncChunks = asyncChunkIds.map((chunkId) => { + const chunk = chunks.find((chunk) => chunk.id === chunkId); + if (!chunk) { + throw new Error(`Failed to find chunk (${chunkId}) in set:\n${JSON.stringify(chunks)}`); + } - return chunk; - }) - // All Webpack chunks are dependent on `runtime`, which is never an async - // entry point, simply ignore this one. - .filter((chunk) => !!chunk.names?.includes('runtime')); + return chunk; + }); // A chunk is considered `initial` only if Webpack already belives it to be initial // and the application developer did not mark it async via an extra entry point. diff --git a/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks_spec.ts b/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks_spec.ts deleted file mode 100644 index a4900f104499..000000000000 --- a/packages/angular_devkit/build_angular/src/webpack/utils/async-chunks_spec.ts +++ /dev/null @@ -1,144 +0,0 @@ -/** - * @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.io/license - */ - -import * as webpack from 'webpack'; -import { markAsyncChunksNonInitial } from './async-chunks'; - -describe('async-chunks', () => { - describe('markAsyncChunksNonInitial()', () => { - it('sets `initial: false` for all extra entry points loaded asynchronously', () => { - const chunks = [ - { - id: 0, - names: ['first'], - initial: true, - files: [], - }, - { - id: 1, - names: ['second'], - initial: true, - files: [], - }, - { - id: 'third', // IDs can be strings too. - names: ['third'], - initial: true, - files: [], - }, - ]; - const entrypoints = { - first: { - chunks: [0], - }, - second: { - chunks: [1], - }, - third: { - chunks: ['third'], - }, - }; - const webpackStats = { chunks, entrypoints }; - - const extraEntryPoints = [ - { - bundleName: 'first', - inject: false, // Loaded asynchronously. - input: 'first.css', - }, - { - bundleName: 'second', - inject: true, - input: 'second.js', - }, - { - bundleName: 'third', - inject: false, // Loaded asynchronously. - input: 'third.js', - }, - ]; - - const newChunks = markAsyncChunksNonInitial( - (webpackStats as unknown) as webpack.StatsCompilation, - extraEntryPoints, - ); - - expect(newChunks).toEqual(([ - { - id: 0, - names: ['first'], - initial: false, // No longer initial because it was marked async. - files: [], - }, - { - id: 1, - names: ['second'], - initial: true, - files: [], - }, - { - id: 'third', - names: ['third'], - initial: false, // No longer initial because it was marked async. - files: [], - }, - ] as unknown) as webpack.StatsChunk[]); - }); - - it('ignores runtime dependency of async chunks', () => { - const chunks = [ - { - id: 0, - names: ['asyncStuff'], - initial: true, - files: [], - }, - { - id: 1, - names: ['runtime'], - initial: true, - files: [], - }, - ]; - const entrypoints = { - asyncStuff: { - chunks: [0, 1], // Includes runtime as a dependency. - }, - }; - const webpackStats = { chunks, entrypoints }; - - const extraEntryPoints = [ - { - bundleName: 'asyncStuff', - inject: false, // Loaded asynchronously. - input: 'asyncStuff.js', - }, - ]; - - const newChunks = markAsyncChunksNonInitial( - (webpackStats as unknown) as webpack.StatsCompilation, - extraEntryPoints, - ); - - expect(newChunks).toEqual(([ - { - id: 0, - names: ['asyncStuff'], - initial: false, // No longer initial because it was marked async. - files: [], - }, - { - id: 1, - names: ['runtime'], - initial: true, // Still initial, even though its a dependency. - files: [], - }, - ] as unknown) as webpack.StatsChunk[]); - }); - }); -}); diff --git a/tests/legacy-cli/e2e/tests/basic/styles-array.ts b/tests/legacy-cli/e2e/tests/basic/styles-array.ts index 23016d015bce..92ce540c2fb6 100644 --- a/tests/legacy-cli/e2e/tests/basic/styles-array.ts +++ b/tests/legacy-cli/e2e/tests/basic/styles-array.ts @@ -3,7 +3,7 @@ import { expectFileToMatch, writeMultipleFiles } from '../../utils/fs'; import { ng } from '../../utils/process'; import { updateJsonFile } from '../../utils/project'; -export default async function() { +export default async function () { await writeMultipleFiles({ 'src/string-style.css': '.string-style { color: red }', 'src/input-style.css': '.input-style { color: red }', @@ -12,7 +12,7 @@ export default async function() { 'src/pre-rename-lazy-style.css': '.pre-rename-lazy-style { color: red }', }); - await updateJsonFile('angular.json', workspaceJson => { + await updateJsonFile('angular.json', (workspaceJson) => { const appArchitect = workspaceJson.projects['test-project'].architect; appArchitect.build.options.styles = [ { input: 'src/string-style.css' }, @@ -27,7 +27,7 @@ export default async function() { ]; }); - await ng('build', '--extract-css', '--configuration=development'); + const { stdout } = await ng('build', '--extract-css', '--configuration=development'); await expectFileToMatch('dist/test-project/styles.css', '.string-style'); await expectFileToMatch('dist/test-project/styles.css', '.input-style'); @@ -41,4 +41,9 @@ export default async function() { `, ); + + // Non injected styles should be listed under lazy chunk files + if (!/Lazy Chunk Files.*\srenamed-lazy-style\.css/m.test(stdout)) { + throw new Error(`Expected "renamed-lazy-style.css" to be listed under "Lazy Chunk Files".`); + } }