Skip to content

Commit

Permalink
fix(@angular/build): allow asset changes to reload page on incrementa…
Browse files Browse the repository at this point in the history
…l updates

Changes to asset files were previously not considered when determining if
an incremental build result could be background update and not cause a
page reload. Asset modifications will not cause a page reload in incremental
update cases.
Additionally, a superfluous component update result will no longer be emitted
in this case. The required page reload will account for the component updates.
  • Loading branch information
clydin authored and alan-agius4 committed Jan 20, 2025
1 parent be5bf49 commit 102d92b
Showing 1 changed file with 105 additions and 99 deletions.
204 changes: 105 additions & 99 deletions packages/angular/build/src/builders/application/build-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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;
}
}

0 comments on commit 102d92b

Please sign in to comment.