fix(angular): optimize ng-packagr-lite watch mode file writing (#31434)

## Current Behavior

In ng-packagr-lite watch mode, all output files are written to disk on
every incremental build regardless of whether their content actually
changed. This causes downstream watchers (like Vite) to see all files as
"changed" and trigger full rebuilds instead of incremental ones.

## Expected Behavior

Only files with changed content should be written to disk during
incremental builds in watch mode. This allows downstream watchers to
properly detect which files actually changed and perform efficient
incremental rebuilds.

## Related Issue(s)

Fixes #31033

🤖 Generated with [Claude Code](https://claude.ai/code)
This commit is contained in:
Colum Ferry 2025-06-05 11:07:23 +01:00 committed by GitHub
parent 5ffd82ea57
commit bc01bbaca1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -9,12 +9,25 @@
import type { NgEntryPoint } from 'ng-packagr/src/lib/ng-package/entry-point/entry-point'; import type { NgEntryPoint } from 'ng-packagr/src/lib/ng-package/entry-point/entry-point';
import type { NgPackagrOptions } from 'ng-packagr/src/lib/ng-package/options.di'; import type { NgPackagrOptions } from 'ng-packagr/src/lib/ng-package/options.di';
import { mkdir, writeFile } from 'node:fs/promises'; import { mkdir, writeFile, readFile } from 'node:fs/promises';
import { dirname, join, normalize } from 'node:path'; import { dirname, join, normalize } from 'node:path';
import { getNgPackagrVersionInfo } from '../../../../utilities/ng-packagr/ng-packagr-version'; import { getNgPackagrVersionInfo } from '../../../../utilities/ng-packagr/ng-packagr-version';
import { importNgPackagrPath } from '../../../../utilities/ng-packagr/package-imports'; import { importNgPackagrPath } from '../../../../utilities/ng-packagr/package-imports';
import { createNgEntryPoint, type NgEntryPointType } from './entry-point'; import { createNgEntryPoint, type NgEntryPointType } from './entry-point';
async function shouldWriteFile(
filePath: string,
newContent: string
): Promise<boolean> {
try {
const existingContent = await readFile(filePath, 'utf-8');
return existingContent !== newContent;
} catch (error) {
// If we can't read the existing file (including if it doesn't exist), write the new one
return true;
}
}
export const writeBundlesTransform = (_options: NgPackagrOptions) => { export const writeBundlesTransform = (_options: NgPackagrOptions) => {
const { major: ngPackagrMajorVersion } = getNgPackagrVersionInfo(); const { major: ngPackagrMajorVersion } = getNgPackagrVersionInfo();
@ -42,10 +55,13 @@ export const writeBundlesTransform = (_options: NgPackagrOptions) => {
for (const [path, outputCache] of entry.cache.outputCache.entries()) { for (const [path, outputCache] of entry.cache.outputCache.entries()) {
const normalizedPath = normalizeEsm2022Path(path, entryPoint); const normalizedPath = normalizeEsm2022Path(path, entryPoint);
// write the outputs to the file system
// Only write if content has changed
if (await shouldWriteFile(normalizedPath, outputCache.content)) {
await mkdir(dirname(normalizedPath), { recursive: true }); await mkdir(dirname(normalizedPath), { recursive: true });
await writeFile(normalizedPath, outputCache.content); await writeFile(normalizedPath, outputCache.content);
} }
}
if (!entry.cache.outputCache.size && entryPoint.isSecondaryEntryPoint) { if (!entry.cache.outputCache.size && entryPoint.isSecondaryEntryPoint) {
await mkdir(entryPoint.destinationPath, { recursive: true }); await mkdir(entryPoint.destinationPath, { recursive: true });
} }