diff --git a/packages/angular/build/src/builders/application/build-action.ts b/packages/angular/build/src/builders/application/build-action.ts index f819ef4e097d..d3c1adcd4547 100644 --- a/packages/angular/build/src/builders/application/build-action.ts +++ b/packages/angular/build/src/builders/application/build-action.ts @@ -242,33 +242,11 @@ function* emitOutputResults( return; } - // Template updates only exist if no other JS changes have occurred - const hasTemplateUpdates = !!templateUpdates?.size; - if (hasTemplateUpdates) { - const updateResult: ComponentUpdateResult = { - kind: ResultKind.ComponentUpdate, - updates: Array.from(templateUpdates, ([id, content]) => ({ - type: 'template', - id, - content, - })), - }; - - yield updateResult; - } - - // Use an incremental result if previous output information is available - if (rebuildState && changes) { - const { previousAssetsInfo, previousOutputInfo } = rebuildState; - - const incrementalResult: IncrementalResult = { - kind: ResultKind.Incremental, + // Use a full result if there is no rebuild state (no prior build result) + if (!rebuildState || !changes) { + const result: FullResult = { + kind: ResultKind.Full, warnings: warnings as ResultMessage[], - // These files need to be updated in the dev server but should not signal any updates - background: hasTemplateUpdates, - added: [], - removed: [], - modified: [], files: {}, detail: { externalMetadata, @@ -277,78 +255,42 @@ function* emitOutputResults( outputOptions, }, }; - - // Initially assume all previous output files have been removed - const removedOutputFiles = new Map(previousOutputInfo); - for (const file of outputFiles) { - removedOutputFiles.delete(file.path); - - const previousHash = previousOutputInfo.get(file.path)?.hash; - let needFile = false; - if (previousHash === undefined) { - needFile = true; - incrementalResult.added.push(file.path); - } else if (previousHash !== file.hash) { - needFile = true; - incrementalResult.modified.push(file.path); - } - - if (needFile) { - // Updates to non-JS files must signal an update with the dev server - if (!/(?:\.m?js|\.map)?$/.test(file.path)) { - incrementalResult.background = false; - } - - incrementalResult.files[file.path] = { - type: file.type, - contents: file.contents, - origin: 'memory', - hash: file.hash, - }; - } - } - - // Initially assume all previous assets files have been removed - const removedAssetFiles = new Map(previousAssetsInfo); - for (const { source, destination } of assetFiles) { - removedAssetFiles.delete(source); - - if (!previousAssetsInfo.has(source)) { - incrementalResult.added.push(destination); - } else if (changes.modified.has(source)) { - incrementalResult.modified.push(destination); - } else { - continue; - } - - incrementalResult.files[destination] = { + for (const file of assetFiles) { + result.files[file.destination] = { type: BuildOutputFileType.Browser, - inputPath: source, + inputPath: file.source, origin: 'disk', }; } + for (const file of outputFiles) { + result.files[file.path] = { + type: file.type, + contents: file.contents, + origin: 'memory', + hash: file.hash, + }; + } - // Include the removed output and asset files - incrementalResult.removed.push( - ...Array.from(removedOutputFiles, ([file, { type }]) => ({ - path: file, - type, - })), - ...Array.from(removedAssetFiles.values(), (file) => ({ - path: file, - type: BuildOutputFileType.Browser, - })), - ); - - yield incrementalResult; + yield result; return; } - // Otherwise, use a full result - const result: FullResult = { - kind: ResultKind.Full, + // Template updates only exist if no other JS changes have occurred. + // A full page reload may be required based on the following incremental output change analysis. + const hasTemplateUpdates = !!templateUpdates?.size; + + // Use an incremental result if previous output information is available + const { previousAssetsInfo, previousOutputInfo } = rebuildState; + + const incrementalResult: IncrementalResult = { + kind: ResultKind.Incremental, warnings: warnings as ResultMessage[], + // Initially attempt to use a background update of files to support component updates. + background: hasTemplateUpdates, + added: [], + removed: [], + modified: [], files: {}, detail: { externalMetadata, @@ -357,21 +299,85 @@ function* emitOutputResults( outputOptions, }, }; - for (const file of assetFiles) { - result.files[file.destination] = { + + // Initially assume all previous output files have been removed + const removedOutputFiles = new Map(previousOutputInfo); + for (const file of outputFiles) { + removedOutputFiles.delete(file.path); + + const previousHash = previousOutputInfo.get(file.path)?.hash; + let needFile = false; + if (previousHash === undefined) { + needFile = true; + incrementalResult.added.push(file.path); + } else if (previousHash !== file.hash) { + needFile = true; + incrementalResult.modified.push(file.path); + } + + if (needFile) { + // Updates to non-JS files must signal an update with the dev server + if (!/(?:\.m?js|\.map)$/.test(file.path)) { + incrementalResult.background = false; + } + + incrementalResult.files[file.path] = { + type: file.type, + contents: file.contents, + origin: 'memory', + hash: file.hash, + }; + } + } + + // Initially assume all previous assets files have been removed + const removedAssetFiles = new Map(previousAssetsInfo); + for (const { source, destination } of assetFiles) { + removedAssetFiles.delete(source); + + if (!previousAssetsInfo.has(source)) { + incrementalResult.added.push(destination); + incrementalResult.background = false; + } else if (changes.modified.has(source)) { + incrementalResult.modified.push(destination); + incrementalResult.background = false; + } else { + continue; + } + + incrementalResult.files[destination] = { type: BuildOutputFileType.Browser, - inputPath: file.source, + inputPath: source, origin: 'disk', }; } - for (const file of outputFiles) { - result.files[file.path] = { - type: file.type, - contents: file.contents, - origin: 'memory', - hash: file.hash, + + // Include the removed output and asset files + incrementalResult.removed.push( + ...Array.from(removedOutputFiles, ([file, { type }]) => ({ + path: file, + type, + })), + ...Array.from(removedAssetFiles.values(), (file) => ({ + path: file, + type: BuildOutputFileType.Browser, + })), + ); + + yield incrementalResult; + + // If there are template updates and the incremental update was background only, a component + // update is possible. + if (hasTemplateUpdates && incrementalResult.background) { + const updateResult: ComponentUpdateResult = { + kind: ResultKind.ComponentUpdate, + updates: Array.from(templateUpdates, ([id, content]) => ({ + type: 'template', + id, + content, + })), }; - } - yield result; + yield updateResult; + } }