7.6 KiB
DEPLOY-000: Clean Up Old Hashed Files on Deploy
Overview
Fix the deployment process to remove old hashed JavaScript files before creating new ones. Currently, each deployment generates a new index-{hash}.js file for cache-busting but never removes previous versions, causing the deployment folder to accumulate duplicate files and grow indefinitely.
Context
The Problem
When deploying to a local folder, the build process generates content-hashed filenames for cache-busting:
// From deploy-index.ts
if (enableHash) {
const hash = createHash();
hash.update(content, 'utf8');
const hex = hash.digest('hex');
filename = addSuffix(url, '-' + hex); // Creates index-abc123def.js
}
This is good practice—browsers fetch fresh code when the hash changes. However, there's no cleanup step to remove the previous hashed files. After 10 deployments, you have 10 index-*.js files. After 100 deployments, you have 100.
Impact
- Bloated project size: Each index.js is ~500KB+ depending on project complexity
- Confusing output folder: Multiple index files make it unclear which is current
- Upload waste: Deploying to hosting platforms uploads unnecessary files
- Git noise: If committing builds, each deploy adds a new file
Existing Infrastructure
deploy-index.ts - Handles file hashing and writing:
// packages/noodl-editor/src/editor/src/utils/compilation/build/deploy-index.ts
export async function copyDeployFilesToFolder({
project, direntry, files, exportJson, baseUrl, envVariables, runtimeType
}: CopyDeployFilesToFolderArgs)
cleanup.ts - Existing cleanup utility (only handles subfolders):
// packages/noodl-editor/src/editor/src/utils/compilation/build/cleanup.ts
export async function clearFolders({ projectPath, outputPath, files }: ClearFoldersOptions)
deployer.ts - Main deployment orchestration:
// packages/noodl-editor/src/editor/src/utils/compilation/build/deployer.ts
export async function deployToFolder({ project, direntry, environment, baseUrl, envVariables, runtimeType })
Requirements
Functional Requirements
- Remove old hashed files before writing new ones during deployment
- Pattern matching for
index-{hash}.jsfiles (hash is hex string from xxhash64) - Preserve non-hashed files like
index.html, static assets,noodl_bundles/, etc. - Work for all deploy types: local folder, and as foundation for cloud deploys
Non-Functional Requirements
- No user-facing changes (silent fix)
- Minimal performance impact (single directory scan)
- Backward compatible with existing projects
Technical Approach
Option A: Extend cleanup.ts (Recommended)
Add a new function to the existing cleanup module:
// packages/noodl-editor/src/editor/src/utils/compilation/build/cleanup.ts
export interface CleanupHashedFilesOptions {
/** The output directory path */
outputPath: string;
/** File patterns to clean (regex) */
patterns?: RegExp[];
}
const DEFAULT_HASHED_PATTERNS = [
/^index-[a-f0-9]+\.js$/, // index-abc123.js
/^index-[a-f0-9]+\.js\.map$/, // source maps if we add them later
];
export async function cleanupHashedFiles({
outputPath,
patterns = DEFAULT_HASHED_PATTERNS
}: CleanupHashedFilesOptions): Promise<string[]> {
const removedFiles: string[] = [];
if (!filesystem.exists(outputPath)) {
return removedFiles;
}
const files = await filesystem.listDirectory(outputPath);
for (const file of files) {
// Skip directories
if (file.isDirectory) continue;
// Check against patterns
const shouldRemove = patterns.some(pattern => pattern.test(file.name));
if (shouldRemove) {
const filePath = filesystem.join(outputPath, file.name);
await filesystem.remove(filePath);
removedFiles.push(file.name);
}
}
return removedFiles;
}
Option B: Inline in copyDeployFilesToFolder
Add cleanup directly in deploy-index.ts before writing files:
export async function copyDeployFilesToFolder({
project, direntry, files, exportJson, baseUrl, envVariables, runtimeType
}: CopyDeployFilesToFolderArgs) {
// NEW: Clean up old hashed files first
await cleanupOldHashedFiles(direntry);
// ... existing logic
}
async function cleanupOldHashedFiles(direntry: string) {
if (!filesystem.exists(direntry)) return;
const files = await filesystem.listDirectory(direntry);
const hashedPattern = /^index-[a-f0-9]+\.js$/;
for (const file of files) {
if (!file.isDirectory && hashedPattern.test(file.name)) {
await filesystem.remove(filesystem.join(direntry, file.name));
}
}
}
Recommendation
Option A is preferred because:
- Follows existing pattern of
cleanup.tsmodule - More extensible for future hashed assets (CSS, source maps)
- Can be reused by cloud deploy providers
- Easier to test in isolation
Implementation Checklist
Phase 1: Core Fix
-
Add
cleanupHashedFilesfunction tocleanup.ts- Accept output path and optional patterns array
- Default patterns for
index-*.jsfiles - Return list of removed files (for logging/debugging)
- Handle non-existent directories gracefully
-
Integrate into deployment flow
- Import in
deploy-index.ts - Call before
writeIndexFiles()incopyDeployFilesToFolder() - Only run when
enableHashis true (matches current behavior)
- Import in
-
Add logging (optional but helpful)
- Debug log removed files count
- Integrate with existing deployment progress indicators
Phase 2: Testing
-
Manual testing
- Deploy project to local folder
- Verify single
index-{hash}.jsexists - Deploy again with code changes
- Verify old hash file removed, new one exists
- Deploy without changes, verify same hash retained
-
Edge cases
- Empty output directory (first deploy)
- Output directory doesn't exist yet
- Read-only files (if possible on target OS)
- Very long hash patterns (shouldn't occur with xxhash64)
Phase 3: Future Considerations (Out of Scope)
- Clean up other hashed assets when added (CSS, fonts)
- Manifest file tracking deployed assets
- Atomic deploys (write to temp, swap folders)
Files to Modify
| File | Changes |
|---|---|
packages/noodl-editor/src/editor/src/utils/compilation/build/cleanup.ts |
Add cleanupHashedFiles() function |
packages/noodl-editor/src/editor/src/utils/compilation/build/deploy-index.ts |
Import and call cleanup before writing |
Estimated Effort
| Task | Hours |
|---|---|
Implement cleanupHashedFiles |
0.5 |
| Integrate into deploy flow | 0.5 |
| Testing & edge cases | 1.0 |
| Total | 2 hours |
Dependencies
- None (uses existing
@noodl/platformfilesystem APIs)
Risks & Mitigations
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Accidentally delete non-hashed files | Low | High | Strict regex pattern, only match expected format |
| Performance on large folders | Very Low | Low | Single directory scan, typically <100 files |
| Break existing deploys | Very Low | Medium | Pattern only matches hash format, preserves all other files |
Success Criteria
- After multiple deployments to the same folder, only ONE
index-{hash}.jsfile exists - The correct (latest) hash file is retained
- All other deployment files remain intact
- No user-visible changes to deployment flow
Related Tasks
- DEPLOY-001: One-Click Deploy (will benefit from clean output)
- DEPLOY-002: Preview Deployments (needs clean folders per preview)
- DEPLOY-003: Deploy Settings (may add "clean build" toggle)