@angular/build
Version:
Official build system for Angular
115 lines • 4.86 kB
JavaScript
;
/**
* @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.dev/license
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.invalidateUpdatedFiles = invalidateUpdatedFiles;
exports.handleUpdate = handleUpdate;
const node_path_1 = require("node:path");
const internal_1 = require("../internal");
/**
* Invalidates any updated asset or generated files and resets their `updated` state.
* This function also clears the server application cache when necessary.
*
* @returns A list of files that were updated and invalidated.
*/
async function invalidateUpdatedFiles(normalizePath, generatedFiles, assetFiles, server) {
const updatedFiles = [];
// Invalidate any updated asset
for (const [file, record] of assetFiles) {
if (!record.updated) {
continue;
}
record.updated = false;
updatedFiles.push(file);
}
// Invalidate any updated files
let serverApplicationChanged = false;
for (const [file, record] of generatedFiles) {
if (!record.updated) {
continue;
}
record.updated = false;
updatedFiles.push(file);
serverApplicationChanged ||= record.type === internal_1.BuildOutputFileType.ServerApplication;
const updatedModules = server.moduleGraph.getModulesByFile(normalizePath((0, node_path_1.join)(server.config.root, file)));
updatedModules?.forEach((m) => server.moduleGraph.invalidateModule(m));
}
if (serverApplicationChanged) {
// Clear the server app cache and trigger module evaluation before reload to initiate dependency optimization.
// The querystring is needed as a workaround for:
// `ɵgetOrCreateAngularServerApp` can be undefined right after an error.
const { ɵdestroyAngularServerApp } = (await server.ssrLoadModule(`/main.server.mjs?timestamp=${Date.now()}`));
ɵdestroyAngularServerApp();
}
return updatedFiles;
}
/**
* Handles updates for the client by sending HMR or full page reload commands
* based on the updated files. It also ensures proper tracking of component styles and determines if
* a full reload is needed.
*/
function handleUpdate(server, serverOptions, logger, componentStyles, updatedFiles) {
if (!updatedFiles.length) {
return;
}
if (serverOptions.hmr) {
if (updatedFiles.every((f) => f.endsWith('.css'))) {
let requiresReload = false;
const timestamp = Date.now();
const updates = updatedFiles.flatMap((filePath) => {
// For component styles, an HMR update must be sent for each one with the corresponding
// component identifier search parameter (`ngcomp`). The Vite client code will not keep
// the existing search parameters when it performs an update and each one must be
// specified explicitly. Typically, there is only one each though as specific style files
// are not typically reused across components.
const record = componentStyles.get(filePath);
if (record) {
if (record.reload) {
// Shadow DOM components currently require a full reload.
// Vite's CSS hot replacement does not support shadow root searching.
requiresReload = true;
return [];
}
return Array.from(record.used ?? []).map((id) => {
return {
type: 'css-update',
timestamp,
path: `${filePath}?ngcomp` + (typeof id === 'string' ? `=${id}` : ''),
acceptedPath: filePath,
};
});
}
return {
type: 'css-update',
timestamp,
path: filePath,
acceptedPath: filePath,
};
});
if (!requiresReload) {
server.ws.send({
type: 'update',
updates,
});
logger.info('Stylesheet update sent to client(s).');
return;
}
}
}
// Send reload command to clients
if (serverOptions.liveReload) {
// Clear used component tracking on full reload
componentStyles.forEach((record) => record.used?.clear());
server.ws.send({
type: 'full-reload',
path: '*',
});
logger.info('Page reload sent to client(s).');
}
}
//# sourceMappingURL=hmr.js.map