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
This commit is contained in:
Panagiotis Papadopoulos 2025-03-25 09:02:03 +01:00
parent cd8401089d
commit 1ceaafa1e8
5 changed files with 110 additions and 39 deletions

View File

@ -18,6 +18,7 @@ RUN npm ci && \
/usr/src/app/build \ /usr/src/app/build \
/tmp/node-compile-cache /tmp/node-compile-cache
#TODO: run cleanupNodeModules script
#TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work #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), # 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 # as we install necessary dependencies in runtime buildstage anyways

View File

@ -18,6 +18,7 @@ RUN npm ci && \
/usr/src/app/build \ /usr/src/app/build \
/tmp/node-compile-cache /tmp/node-compile-cache
#TODO: run cleanupNodeModules script
#TODO: improve node_modules handling in copy-dist/Dockerfile -> remove duplicated work #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), # 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 # as we install necessary dependencies in runtime buildstage anyways

87
bin/cleanupNodeModules.ts Normal file
View File

@ -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()

View File

@ -28,6 +28,7 @@ try {
"./README.md", "./README.md",
"./forge.config.cjs", "./forge.config.cjs",
"./bin/tpl/", "./bin/tpl/",
"./bin/cleanupNodeModules.ts",
"./bin/electron-forge/desktop.ejs", "./bin/electron-forge/desktop.ejs",
"./bin/electron-forge/sign-windows.cjs", "./bin/electron-forge/sign-windows.cjs",
"./src/views/", "./src/views/",
@ -59,46 +60,12 @@ try {
console.log("Copying complete!") console.log("Copying complete!")
// TriliumNextTODO: for Docker this needs to run separately *after* build-stage // TriliumNextTODO: for Docker this needs to run separately *after* build-stage
console.log("Pruning npm packages...") // Disable for now, because this messes with electron-forge as well
execSync(`npm ci --omit=dev --prefix ${DEST_DIR}`); //console.log("Pruning npm packages...")
//execSync(`npm ci --omit=dev --prefix ${DEST_DIR}`);
cleanupNodeModules();
} catch(err) { } catch(err) {
console.error("Error during copy:", err) console.error("Error during copy:", err)
process.exit(1) 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));
}

View File

@ -1,5 +1,6 @@
const path = require("path"); const path = require("path");
const fs = require("fs-extra"); const fs = require("fs-extra");
const { execSync } = require("child_process");
const APP_NAME = "TriliumNext Notes"; const APP_NAME = "TriliumNext Notes";
const BIN_PATH = path.normalize("./bin/electron-forge"); const BIN_PATH = path.normalize("./bin/electron-forge");
@ -18,8 +19,6 @@ module.exports = {
// we run electron-forge inside the ./build folder, // we run electron-forge inside the ./build folder,
// to have it output to ./dist, we need to go up a directory first // to have it output to ./dist, we need to go up a directory first
outDir: "../dist", outDir: "../dist",
// we prune ourselves via copy-dist
prune: false,
packagerConfig: { packagerConfig: {
executableName: "trilium", executableName: "trilium",
name: APP_NAME, name: APP_NAME,
@ -41,6 +40,22 @@ module.exports = {
"translations/", "translations/",
"node_modules/@highlightjs/cdn-assets/styles" "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: [ afterComplete: [
(buildPath, _electronVersion, platform, _arch, callback) => { (buildPath, _electronVersion, platform, _arch, callback) => {
// Only move resources on non-macOS platforms // Only move resources on non-macOS platforms