diff --git a/.changeset/guard-astro-sveltekit-writes.md b/.changeset/guard-astro-sveltekit-writes.md new file mode 100644 index 0000000000..3fe628f722 --- /dev/null +++ b/.changeset/guard-astro-sveltekit-writes.md @@ -0,0 +1,6 @@ +--- +'@workflow/astro': patch +'@workflow/sveltekit': patch +--- + +Stop rewriting generated files whose content is unchanged, so a no-op rebuild no longer invalidates them in the dev server. diff --git a/packages/astro/src/builder.ts b/packages/astro/src/builder.ts index d2b491e903..f5449cc12f 100644 --- a/packages/astro/src/builder.ts +++ b/packages/astro/src/builder.ts @@ -7,6 +7,7 @@ import { NORMALIZE_REQUEST_CODE, resolveProjectRoot, VercelBuildOutputAPIBuilder, + writeFileIfChanged, } from '@workflow/builders'; const WORKFLOW_ROUTES = [ @@ -54,7 +55,7 @@ export class LocalBuilder extends BaseBuilder { // Add .gitignore to exclude generated files from version control if (process.env.VERCEL_DEPLOYMENT_ID === undefined) { - await writeFile(join(workflowGeneratedDir, '.gitignore'), '*'); + await writeFileIfChanged(join(workflowGeneratedDir, '.gitignore'), '*'); } // Clean up stale V1 step route (may persist via Vercel build cache) @@ -90,7 +91,10 @@ export const POST = async ({request}) => { export const prerender = false;` ); - await writeFile(workflowsRouteFile, workflowsRouteContent); + // These files are generated into the Astro pages directory, which Vite + // watches in dev, so an identical rewrite would still invalidate the + // module and force a redundant recompile. + await writeFileIfChanged(workflowsRouteFile, workflowsRouteContent); await this.buildWebhookRoute({ workflowGeneratedDir }); @@ -105,7 +109,7 @@ export const prerender = false;` // Expose manifest as a public HTTP route when WORKFLOW_PUBLIC_MANIFEST=1 // Astro maps `foo.json.js` to the URL `/foo.json` if (this.shouldExposePublicManifest && manifestJson) { - await writeFile( + await writeFileIfChanged( join(workflowGeneratedDir, 'manifest.json.js'), `export function GET() { return new Response(${JSON.stringify(manifestJson)}, { @@ -169,7 +173,7 @@ export const OPTIONS = createHandler('OPTIONS'); export const prerender = false;` ); - await writeFile(webhookRouteFile, webhookRouteContent); + await writeFileIfChanged(webhookRouteFile, webhookRouteContent); } } diff --git a/packages/sveltekit/src/builder.ts b/packages/sveltekit/src/builder.ts index 27514b3d94..68260e7669 100644 --- a/packages/sveltekit/src/builder.ts +++ b/packages/sveltekit/src/builder.ts @@ -1,13 +1,5 @@ import { constants } from 'node:fs'; -import { - access, - copyFile, - mkdir, - readFile, - rm, - stat, - writeFile, -} from 'node:fs/promises'; +import { access, mkdir, readFile, rm, stat } from 'node:fs/promises'; import { createRequire } from 'node:module'; import { dirname, join, resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; @@ -17,6 +9,7 @@ import { NORMALIZE_REQUEST_CODE, resolveProjectRoot, type SvelteKitConfig, + writeFileIfChanged, } from '@workflow/builders'; const SVELTEKIT_VIRTUAL_MODULES = [ @@ -70,7 +63,7 @@ export class SvelteKitBuilder extends BaseBuilder { // Add .gitignore to exclude generated files from version control if (process.env.VERCEL_DEPLOYMENT_ID === undefined) { - await writeFile(join(workflowGeneratedDir, '.gitignore'), '*'); + await writeFileIfChanged(join(workflowGeneratedDir, '.gitignore'), '*'); } // Clean up stale V1 step route directory (may persist via Vercel build cache) @@ -110,7 +103,10 @@ export const POST = async ({request}) => { return workflowEntrypoint(workflowCode${options})(normalRequest); }` ); - await writeFile(workflowsRouteFile, workflowsRouteContent); + // These files are generated into the SvelteKit routes directory, which + // Vite watches in dev, so an identical rewrite would still invalidate the + // module and force a redundant recompile. + await writeFileIfChanged(workflowsRouteFile, workflowsRouteContent); await this.buildWebhookRoute({ workflowGeneratedDir }); @@ -131,11 +127,13 @@ export const POST = async ({request}) => { ); await mkdir(staticManifestDir, { recursive: true }); if (process.env.VERCEL_DEPLOYMENT_ID === undefined) { - await writeFile(join(staticManifestDir, '.gitignore'), '*'); + await writeFileIfChanged(join(staticManifestDir, '.gitignore'), '*'); } - await copyFile( - join(workflowGeneratedDir, 'manifest.json'), - join(staticManifestDir, 'manifest.json') + // Written from the same string rather than copied, so an unchanged + // manifest leaves the static copy untouched too. + await writeFileIfChanged( + join(staticManifestDir, 'manifest.json'), + manifestJson ); } } @@ -193,7 +191,7 @@ export const HEAD = createSvelteKitHandler('HEAD'); export const OPTIONS = createSvelteKitHandler('OPTIONS');` ); - await writeFile(webhookRouteFile, webhookRouteContent); + await writeFileIfChanged(webhookRouteFile, webhookRouteContent); } private async loadRoutesDirectory(): Promise {