From 1ceaafa1e88323eb106f00a451515f34d1e62bb2 Mon Sep 17 00:00:00 2001 From: Panagiotis Papadopoulos Date: Tue, 25 Mar 2025 09:02:03 +0100 Subject: [PATCH] build: move cleanupNodeModules to its own file this is necessary, since for Docker and electron-forge, we need to run this as an extra step after copy-dist for electron-forge: after it is done with its own "pruning", as we otherwise would need to also take care of certain electron related pruning for Docker: as a last step in the build stage --- Dockerfile | 1 + Dockerfile.alpine | 1 + bin/cleanupNodeModules.ts | 87 +++++++++++++++++++++++++++++++++++++++ bin/copy-dist.ts | 41 ++---------------- forge.config.cjs | 19 ++++++++- 5 files changed, 110 insertions(+), 39 deletions(-) create mode 100644 bin/cleanupNodeModules.ts diff --git a/Dockerfile b/Dockerfile index 4aac3160f..538f3e58f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,6 +18,7 @@ RUN npm ci && \ /usr/src/app/build \ /tmp/node-compile-cache +#TODO: run cleanupNodeModules script #TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work # currently copy-dist will copy certain node_module folders, but in the Dockerfile we delete them again (to keep image size down), # as we install necessary dependencies in runtime buildstage anyways diff --git a/Dockerfile.alpine b/Dockerfile.alpine index f83789399..595d21561 100644 --- a/Dockerfile.alpine +++ b/Dockerfile.alpine @@ -18,6 +18,7 @@ RUN npm ci && \ /usr/src/app/build \ /tmp/node-compile-cache +#TODO: run cleanupNodeModules script #TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work # currently copy-dist will copy certain node_module folders, but in the Dockerfile we delete them again (to keep image size down), # as we install necessary dependencies in runtime buildstage anyways diff --git a/bin/cleanupNodeModules.ts b/bin/cleanupNodeModules.ts new file mode 100644 index 000000000..2daf7c01b --- /dev/null +++ b/bin/cleanupNodeModules.ts @@ -0,0 +1,87 @@ +import fs from "fs-extra"; +import path from "path"; + +function main() { + if (process.argv.length !== 3) { + console.error("More than one path was supplied as argument. Aborting."); + process.exit(1); + } + + const basePath = process.argv[2]; + + if (!fs.existsSync(basePath)) { + console.error(`Supplied path '${basePath}' does not exist. Aborting.`) + process.exit(1); + } + + cleanupNodeModules(basePath); +} + +function cleanupNodeModules(basePath: string) { + const nodeDir = fs.readdirSync(path.join(basePath, "./node_modules"), { recursive: true, withFileTypes: true }); + //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" + ]); + + nodeDir + .filter(el => el.isDirectory() && filterableDirs.has(el.name)) + .forEach(dir => fs.removeSync(path.join(dir.parentPath, dir.name))); + + + /** + * Delete unnecessary files based on file extension + * TODO filter out useless (README).md files + */ + const filterableFileExt = new Set([ + "ts", + "map" + ]); + + nodeDir + // 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) || "")) + .forEach(file => fs.removeSync(path.join(file.parentPath, file.name))); + + + /** + * Delete specific unnecessary folders + * TODO: use basePath + * 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([ + 'build/node_modules/@excalidraw/excalidraw/dist/dev', + 'build/node_modules/boxicons/svg', + 'build/node_modules/boxicons/node_modules', + 'build/node_modules/boxicons/src', + 'build/node_modules/boxicons/iconjar', + 'build/node_modules/@jimp/plugin-print/fonts', + 'build/node_modules/jimp/dist/browser' + // "node_modules/@excalidraw/excalidraw/dist/dev", + // "node_modules/jimp/browser", + // "node_modules/@jimp/plugin-print/fonts", + // "node_modules/jimp/dist/browser", + // "node_modules/jimp/fonts", + // "node_modules/boxicons/svg", + // "node_modules/boxicons/node_modules/react", + // "node_modules/mermaid/dist/mermaid.js" + ]); + + nodeDir + .filter(el => el.isDirectory() && extraFoldersDelete.has(path.join(el.parentPath, el.name))) + .forEach(dir => fs.removeSync(path.join(dir.parentPath, dir.name))) + +} + +main() \ No newline at end of file diff --git a/bin/copy-dist.ts b/bin/copy-dist.ts index 9fb520907..e04edee0c 100644 --- a/bin/copy-dist.ts +++ b/bin/copy-dist.ts @@ -28,6 +28,7 @@ try { "./README.md", "./forge.config.cjs", "./bin/tpl/", + "./bin/cleanupNodeModules.ts", "./bin/electron-forge/desktop.ejs", "./bin/electron-forge/sign-windows.cjs", "./src/views/", @@ -59,46 +60,12 @@ try { console.log("Copying complete!") // TriliumNextTODO: for Docker this needs to run separately *after* build-stage - console.log("Pruning npm packages...") - execSync(`npm ci --omit=dev --prefix ${DEST_DIR}`); - - cleanupNodeModules(); + // Disable for now, because this messes with electron-forge as well + //console.log("Pruning npm packages...") + //execSync(`npm ci --omit=dev --prefix ${DEST_DIR}`); } catch(err) { console.error("Error during copy:", err) process.exit(1) } -function cleanupNodeModules() { - const nodeDir = fs.readdirSync(path.join(DEST_DIR, "./node_modules"), { recursive: true, withFileTypes: true }); - - const filterableDirs = new Set([ - "demo", - "demos", - "doc", - "docs", - "example", - "examples", - "test", - "tests" - ]); - - nodeDir - .filter(el => el.isDirectory() && filterableDirs.has(el.name)) - .map(el => path.join(DEST_DIR, el.parentPath, el.name)) - .forEach(dir => fs.removeSync(dir)); - - - // Delete unnecessary files based on file extension - const filterableFileExt = new Set([ - "ts", - "map" - ]) - - nodeDir - // TriliumNextTODO: check if we can improve this naive file ext matching - .filter(el => el.isFile() && filterableFileExt.has(el.name.split(".").at(-1) || "")) - .map(file => path.join(DEST_DIR, file.parentPath, file.name)) - .forEach(file => fs.removeSync(file)); - -} diff --git a/forge.config.cjs b/forge.config.cjs index 763cb80e8..1a7e5a3c6 100644 --- a/forge.config.cjs +++ b/forge.config.cjs @@ -1,5 +1,6 @@ const path = require("path"); const fs = require("fs-extra"); +const { execSync } = require("child_process"); const APP_NAME = "TriliumNext Notes"; const BIN_PATH = path.normalize("./bin/electron-forge"); @@ -18,8 +19,6 @@ module.exports = { // we run electron-forge inside the ./build folder, // to have it output to ./dist, we need to go up a directory first outDir: "../dist", - // we prune ourselves via copy-dist - prune: false, packagerConfig: { executableName: "trilium", name: APP_NAME, @@ -41,6 +40,22 @@ module.exports = { "translations/", "node_modules/@highlightjs/cdn-assets/styles" ], + afterPrune: [ + (buildPath, _electronVersion, _platform, _arch, callback) => { + // buildPath is a temporary directory that electron-packager creates - it's in the form of + // /tmp/electron-packager/tmp-SjJl0s/resources/app + try { + const cleanupNodeModulesScript = path.join(buildPath, "bin", "cleanupNodeModules.ts"); + // we don't have access to any devDeps like 'tsx' here, so use the built-in '--experimental-strip-types' flag instead + const command = `node --experimental-strip-types ${cleanupNodeModulesScript} '${buildPath}'`; + // execSync throws, if above returns any non-zero exit code + execSync(command); + callback() + } catch(err) { + callback(err) + } + } + ], afterComplete: [ (buildPath, _electronVersion, platform, _arch, callback) => { // Only move resources on non-macOS platforms