| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | import fs from "fs-extra"; | 
					
						
							|  |  |  | import path from "path"; | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  | import type { Dirent } from "fs-extra"; | 
					
						
							|  |  |  | import { execSync } from "node:child_process"; | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:26:22 +01:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Example usage with node >= v22: | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  |  *    node --experimental-strip-types bin/cleanupNodeModules.ts /path/to/build/folder [--skip-prune-dev-deps] | 
					
						
							| 
									
										
										
										
											2025-03-26 09:26:22 +01:00
										 |  |  |  * Example usage with tsx: | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  |  *    tsx bin/cleanupNodeModules.ts /path/to/build/folder [--skip-prune-dev-deps] | 
					
						
							| 
									
										
										
										
											2025-03-26 09:26:22 +01:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | function main() { | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (process.argv.length > 4 || process.argv.length < 3) { | 
					
						
							|  |  |  |         console.error("Usage: cleanupNodeModules.ts [path-to-build-folder] [--skip-prune-dev-deps]"); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |         process.exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const basePath = process.argv[2]; | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  |     const pruneDevDeps = process.argv[3] !== "--skip-prune-dev-deps"; | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (!fs.existsSync(basePath)) { | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  |         console.error(`Supplied path '${basePath}' does not exist. Aborting.`); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |         process.exit(1); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     console.log(`Starting pruning of node_modules ${!pruneDevDeps ? '(skipping npm pruning)' : ''} in '${basePath}'...`); | 
					
						
							|  |  |  |     cleanupNodeModules(basePath, pruneDevDeps); | 
					
						
							|  |  |  |     console.log("Successfully pruned node_modules."); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  | function cleanupNodeModules(basePath: string, pruneDevDeps: boolean = true) { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     // This needs to run for the server and Docker build,
 | 
					
						
							|  |  |  |     // but needs to be skipped for electron-forge: its
 | 
					
						
							|  |  |  |     // built-in pruning takes care of it already
 | 
					
						
							|  |  |  |     if (pruneDevDeps) { | 
					
						
							|  |  |  |         execSync(`npm ci --omit=dev --prefix ${basePath}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:18:16 +01:00
										 |  |  |     const nodeModulesDirPath = path.join(basePath, "node_modules"); | 
					
						
							|  |  |  |     const nodeModulesContent = fs.readdirSync(nodeModulesDirPath, { recursive: true, withFileTypes: true }); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |     //const libDir = fs.readdirSync(path.join(basePath, "./libraries"), { recursive: true, withFileTypes: true });
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Delete unnecessary folders | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const filterableDirs = new Set([ | 
					
						
							|  |  |  |         "demo", | 
					
						
							|  |  |  |         "demos", | 
					
						
							|  |  |  |         "doc", | 
					
						
							|  |  |  |         "docs", | 
					
						
							|  |  |  |         "example", | 
					
						
							|  |  |  |         "examples", | 
					
						
							|  |  |  |         "test", | 
					
						
							|  |  |  |         "tests" | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:12:22 +01:00
										 |  |  |     nodeModulesContent | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |         .filter(el => el.isDirectory() && filterableDirs.has(el.name)) | 
					
						
							| 
									
										
										
										
											2025-03-26 09:47:06 +01:00
										 |  |  |         .forEach(dir => removeDirent(dir)); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Delete unnecessary files based on file extension | 
					
						
							|  |  |  |      * TODO filter out useless (README).md files | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const filterableFileExt = new Set([ | 
					
						
							|  |  |  |         "ts", | 
					
						
							|  |  |  |         "map" | 
					
						
							|  |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:12:22 +01:00
										 |  |  |     nodeModulesContent | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |         // TriliumNextTODO: check if we can improve this naive file ext matching, without introducing any additional dependency
 | 
					
						
							|  |  |  |         .filter(el => el.isFile() && filterableFileExt.has(el.name.split(".").at(-1) || "")) | 
					
						
							| 
									
										
										
										
											2025-03-26 09:47:06 +01:00
										 |  |  |         .forEach(dir => removeDirent(dir)); | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Delete specific unnecessary folders | 
					
						
							|  |  |  |      * TODO: check if we want removeSync to throw an error, if path does not exist anymore -> currently it will silently fail | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     const extraFoldersDelete = new Set([ | 
					
						
							| 
									
										
										
										
											2025-03-26 09:28:50 +01:00
										 |  |  |         path.join(nodeModulesDirPath, ".bin"), | 
					
						
							| 
									
										
										
										
											2025-03-26 09:18:16 +01:00
										 |  |  |         path.join(nodeModulesDirPath, "@excalidraw", "excalidraw", "dist", "dev"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "boxicons", "svg"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "boxicons", "node_modules"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "boxicons", "src"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "boxicons", "iconjar"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "@jimp", "plugin-print", "fonts"), | 
					
						
							|  |  |  |         path.join(nodeModulesDirPath, "jimp", "dist", "browser") // missing "@" in front of jimp is not a typo here
 | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |     ]); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:12:22 +01:00
										 |  |  |     nodeModulesContent | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  |         .filter(el => el.isDirectory() && extraFoldersDelete.has(path.join(el.parentPath, el.name))) | 
					
						
							| 
									
										
										
										
											2025-03-26 09:47:06 +01:00
										 |  |  |         .forEach(dir => removeDirent(dir)) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-27 00:00:41 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-26 09:47:06 +01:00
										 |  |  | function removeDirent(el: Dirent) { | 
					
						
							|  |  |  |     const elementToDelete = path.join(el.parentPath, el.name); | 
					
						
							|  |  |  |     fs.removeSync(elementToDelete); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (process.env.VERBOSE) { | 
					
						
							|  |  |  |         console.log(`Deleted ${elementToDelete}`); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-25 09:02:03 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | main() |