Skip to content
This repository was archived by the owner on Jun 24, 2025. It is now read-only.

Commit 10f044a

Browse files
authored
Merge pull request #1436 from TriliumNext/build_copy-dist-trilium-merge
build: port copy-trilium.sh cleanup functionality to cross-platform TS
2 parents cbf3ee9 + 5a2c5d8 commit 10f044a

File tree

9 files changed

+153
-103
lines changed

9 files changed

+153
-103
lines changed

.dockerignore

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ npm-debug.log
3434

3535
# exceptions
3636
!/bin/copy-dist.ts
37-
!/bin/electron-forge/sign-windows.cjs
37+
!/bin/cleanupNodeModules.ts
3838

3939
# temporary exception to make copy-dist inside Docker build not fail
40-
# TriliumNextTODO: make copy-dist *not* requiring to copy this file for builds other than electron-forge
40+
# TriliumNextTODO: make copy-dist *not* requiring to copy these file for builds other than electron-forge
4141
!forge.config.cjs
4242
!/bin/tpl
43-
!/bin/electron-forge/desktop.ejs
43+
!/bin/electron-forge/desktop.ejs
44+
!/bin/electron-forge/sign-windows.cjs

Dockerfile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,11 @@ COPY --from=builder /usr/src/app ./
3939

4040
RUN sed -i "/electron/d" package.json && \
4141
npm ci --omit=dev && \
42+
node --experimental-strip-types ./bin/cleanupNodeModules.ts . --skip-prune-dev-deps && \
4243
npm cache clean --force && \
43-
rm -rf /tmp/node-compile-cache
44+
rm -rf \
45+
/tmp/node-compile-cache \
46+
/usr/src/app/bin/cleanupNodeModules.ts
4447

4548
# Configure container
4649
EXPOSE 8080

Dockerfile.alpine

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,11 @@ COPY --from=builder /usr/src/app ./
3434

3535
RUN sed -i "/electron/d" package.json && \
3636
npm ci --omit=dev && \
37+
node --experimental-strip-types ./bin/cleanupNodeModules.ts . --skip-prune-dev-deps && \
3738
npm cache clean --force && \
38-
rm -rf /tmp/node-compile-cache
39+
rm -rf \
40+
/tmp/node-compile-cache \
41+
/usr/src/app/bin/cleanupNodeModules.ts
3942

4043
# Add application user
4144
RUN adduser -s /bin/false node; exit 0

bin/build-server.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,16 @@ NODE_VERSION=22.14.0
2525

2626
BUILD_DIR="./build"
2727
DIST_DIR="./dist"
28+
CLEANUP_SCRIPT="./bin/cleanupNodeModules.ts"
2829

29-
./bin/copy-trilium.sh
30+
31+
# Trigger the build
32+
echo "Build start"
33+
npm run build:prepare-dist
34+
echo "Build finished"
35+
36+
# pruning of unnecessary files and devDeps in node_modules
37+
node --experimental-strip-types $CLEANUP_SCRIPT $BUILD_DIR
3038

3139
NODE_FILENAME=node-v${NODE_VERSION}-linux-${ARCH}
3240

bin/cleanupNodeModules.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import fs from "fs-extra";
2+
import path from "path";
3+
import type { Dirent } from "fs-extra";
4+
import { execSync } from "node:child_process";
5+
6+
/**
7+
* Example usage with node >= v22:
8+
* node --experimental-strip-types bin/cleanupNodeModules.ts /path/to/build/folder [--skip-prune-dev-deps]
9+
* Example usage with tsx:
10+
* tsx bin/cleanupNodeModules.ts /path/to/build/folder [--skip-prune-dev-deps]
11+
*/
12+
function main() {
13+
14+
if (process.argv.length > 4 || process.argv.length < 3) {
15+
console.error("Usage: cleanupNodeModules.ts [path-to-build-folder] [--skip-prune-dev-deps]");
16+
process.exit(1);
17+
}
18+
19+
const basePath = process.argv[2];
20+
const pruneDevDeps = process.argv[3] !== "--skip-prune-dev-deps";
21+
22+
if (!fs.existsSync(basePath)) {
23+
console.error(`Supplied path '${basePath}' does not exist. Aborting.`);
24+
process.exit(1);
25+
}
26+
27+
console.log(`Starting pruning of node_modules ${!pruneDevDeps ? '(skipping npm pruning)' : ''} in '${basePath}'...`);
28+
cleanupNodeModules(basePath, pruneDevDeps);
29+
console.log("Successfully pruned node_modules.");
30+
}
31+
32+
function cleanupNodeModules(basePath: string, pruneDevDeps: boolean = true) {
33+
34+
// This needs to run for the server and Docker build,
35+
// but needs to be skipped for electron-forge: its
36+
// built-in pruning takes care of it already
37+
if (pruneDevDeps) {
38+
execSync(`npm ci --omit=dev --prefix ${basePath}`);
39+
}
40+
41+
const nodeModulesDirPath = path.join(basePath, "node_modules");
42+
const nodeModulesContent = fs.readdirSync(nodeModulesDirPath, { recursive: true, withFileTypes: true });
43+
//const libDir = fs.readdirSync(path.join(basePath, "./libraries"), { recursive: true, withFileTypes: true });
44+
45+
/**
46+
* Delete unnecessary folders
47+
*/
48+
const filterableDirs = new Set([
49+
"demo",
50+
"demos",
51+
"doc",
52+
"docs",
53+
"example",
54+
"examples",
55+
"test",
56+
"tests"
57+
]);
58+
59+
nodeModulesContent
60+
.filter(el => el.isDirectory() && filterableDirs.has(el.name))
61+
.forEach(dir => removeDirent(dir));
62+
63+
/**
64+
* Delete unnecessary files based on file extension
65+
* TODO filter out useless (README).md files
66+
*/
67+
const filterableFileExt = new Set([
68+
"ts",
69+
"map"
70+
]);
71+
72+
nodeModulesContent
73+
// TriliumNextTODO: check if we can improve this naive file ext matching, without introducing any additional dependency
74+
.filter(el => el.isFile() && filterableFileExt.has(el.name.split(".").at(-1) || ""))
75+
.forEach(dir => removeDirent(dir));
76+
77+
78+
/**
79+
* Delete specific unnecessary folders
80+
* TODO: check if we want removeSync to throw an error, if path does not exist anymore -> currently it will silently fail
81+
*/
82+
const extraFoldersDelete = new Set([
83+
path.join(nodeModulesDirPath, ".bin"),
84+
path.join(nodeModulesDirPath, "@excalidraw", "excalidraw", "dist", "dev"),
85+
path.join(nodeModulesDirPath, "boxicons", "svg"),
86+
path.join(nodeModulesDirPath, "boxicons", "node_modules"),
87+
path.join(nodeModulesDirPath, "boxicons", "src"),
88+
path.join(nodeModulesDirPath, "boxicons", "iconjar"),
89+
path.join(nodeModulesDirPath, "@jimp", "plugin-print", "fonts"),
90+
path.join(nodeModulesDirPath, "jimp", "dist", "browser") // missing "@" in front of jimp is not a typo here
91+
]);
92+
93+
nodeModulesContent
94+
.filter(el => el.isDirectory() && extraFoldersDelete.has(path.join(el.parentPath, el.name)))
95+
.forEach(dir => removeDirent(dir))
96+
}
97+
98+
99+
function removeDirent(el: Dirent) {
100+
const elementToDelete = path.join(el.parentPath, el.name);
101+
fs.removeSync(elementToDelete);
102+
103+
if (process.env.VERBOSE) {
104+
console.log(`Deleted ${elementToDelete}`);
105+
}
106+
107+
}
108+
109+
main()

bin/copy-dist.ts

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,10 @@ function log(...args: any[]) {
1111
}
1212
}
1313

14-
function copyNodeModuleFileOrFolder(source: string) {
15-
const destination = path.join(DEST_DIR, source);
16-
log(`Copying ${source} to ${destination}`);
17-
fs.ensureDirSync(path.dirname(destination));
18-
fs.copySync(source, destination);
19-
}
20-
2114
try {
2215

2316
const assetsToCopy = new Set([
17+
// copy node_module, to avoid downloading packages a 2nd time during pruning
2418
"./node_modules",
2519
"./images",
2620
"./libraries",
@@ -33,6 +27,7 @@ try {
3327
"./README.md",
3428
"./forge.config.cjs",
3529
"./bin/tpl/",
30+
"./bin/cleanupNodeModules.ts",
3631
"./bin/electron-forge/desktop.ejs",
3732
"./bin/electron-forge/sign-windows.cjs",
3833
"./src/views/",
@@ -61,50 +56,10 @@ try {
6156
fs.copySync(dir, path.join(PUBLIC_DIR, path.basename(dir)));
6257
}
6358

64-
const nodeModulesFile = new Set([
65-
"node_modules/react/umd/react.production.min.js",
66-
"node_modules/react/umd/react.development.js",
67-
"node_modules/react-dom/umd/react-dom.production.min.js",
68-
"node_modules/react-dom/umd/react-dom.development.js",
69-
"node_modules/katex/dist/katex.min.js",
70-
"node_modules/katex/dist/contrib/mhchem.min.js",
71-
"node_modules/katex/dist/contrib/auto-render.min.js",
72-
"node_modules/@highlightjs/cdn-assets/highlight.min.js",
73-
]);
74-
75-
const nodeModulesFolder = new Set([
76-
"node_modules/@excalidraw/excalidraw/dist/prod/fonts/",
77-
"node_modules/katex/dist/",
78-
"node_modules/dayjs/",
79-
"node_modules/boxicons/css/",
80-
"node_modules/boxicons/fonts/",
81-
"node_modules/jquery/dist/",
82-
"node_modules/jquery-hotkeys/",
83-
"node_modules/split.js/dist/",
84-
"node_modules/i18next/",
85-
"node_modules/i18next-http-backend/",
86-
"node_modules/vanilla-js-wheel-zoom/dist/",
87-
"node_modules/mark.js/dist/",
88-
"node_modules/normalize.css/",
89-
"node_modules/jquery.fancytree/dist/",
90-
"node_modules/autocomplete.js/dist/",
91-
"node_modules/codemirror/lib/",
92-
"node_modules/codemirror/addon/",
93-
"node_modules/codemirror/mode/",
94-
"node_modules/codemirror/keymap/",
95-
"node_modules/@highlightjs/cdn-assets/languages",
96-
"node_modules/@highlightjs/cdn-assets/styles",
97-
"node_modules/leaflet/dist"
98-
]);
99-
100-
101-
102-
for (const nodeModuleItem of [...nodeModulesFile, ...nodeModulesFolder]) {
103-
copyNodeModuleFileOrFolder(nodeModuleItem);
104-
}
10559
console.log("Copying complete!")
10660

10761
} catch(err) {
10862
console.error("Error during copy:", err)
10963
process.exit(1)
11064
}
65+

bin/copy-trilium.sh

Lines changed: 0 additions & 44 deletions
This file was deleted.

forge.config.cjs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const path = require("path");
22
const fs = require("fs-extra");
3+
const { execSync } = require("child_process");
34

45
const APP_NAME = "TriliumNext Notes";
56
const BIN_PATH = path.normalize("./bin/electron-forge");
@@ -39,6 +40,22 @@ module.exports = {
3940
"translations/",
4041
"node_modules/@highlightjs/cdn-assets/styles"
4142
],
43+
afterPrune: [
44+
(buildPath, _electronVersion, _platform, _arch, callback) => {
45+
// buildPath is a temporary directory that electron-packager creates - it's in the form of
46+
// /tmp/electron-packager/tmp-SjJl0s/resources/app
47+
try {
48+
const cleanupNodeModulesScript = path.join(buildPath, "bin", "cleanupNodeModules.ts");
49+
// we don't have access to any devDeps like 'tsx' here, so use the built-in '--experimental-strip-types' flag instead
50+
const command = `node --experimental-strip-types ${cleanupNodeModulesScript} "${buildPath}" --skip-prune-dev-deps`;
51+
// execSync throws, if above returns any non-zero exit code
52+
execSync(command);
53+
callback()
54+
} catch(err) {
55+
callback(err)
56+
}
57+
}
58+
],
4259
afterComplete: [
4360
(buildPath, _electronVersion, platform, _arch, callback) => {
4461
// Only move resources on non-macOS platforms

package.json

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,9 @@
3838
"electron:switch": "electron-rebuild",
3939
"docs:edit": "cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_ENV=dev TRILIUM_PORT=37741 electron ./electron-docs-main.ts .",
4040
"docs:edit-nix": "electron-rebuild --version 33.3.1 && cross-env NODE_OPTIONS=\"--import tsx\" TRILIUM_DATA_DIR=./data-docs TRILIUM_PORT=37741 TRILIUM_ENV=dev nix-shell -p electron_33 --run \"electron ./electron-docs-main.ts .\"",
41-
"electron-forge:prepare": "npm run build:prepare-dist",
42-
"electron-forge:start": "npm run electron-forge:prepare && cd ./build && electron-forge start",
43-
"electron-forge:make": "npm run electron-forge:prepare && cross-env DEBUG=electron-windows-installer:* electron-forge make ./build",
44-
"electron-forge:package": "npm run electron-forge:prepare && cd ./build && electron-forge package",
41+
"electron-forge:start": "npm run build:prepare-dist && cd ./build && electron-forge start",
42+
"electron-forge:make": "npm run build:prepare-dist && cross-env DEBUG=electron-windows-installer:* electron-forge make ./build",
43+
"electron-forge:package": "npm run build:prepare-dist && cd ./build && electron-forge package",
4544
"docs:build-backend": "rimraf ./docs/backend_api && typedoc ./docs/backend_api src/becca/entities/*.ts src/services/backend_script_api.ts src/services/sql.ts",
4645
"docs:build-frontend": "rimraf ./docs/frontend_api && jsdoc -c jsdoc-conf.json -d ./docs/frontend_api src/public/app/entities/*.js src/public/app/services/frontend_script_api.js src/public/app/widgets/basic_widget.js src/public/app/widgets/note_context_aware_widget.js src/public/app/widgets/right_panel_widget.js",
4746
"docs:build": "npm run docs:build-backend && npm run docs:build-frontend",
@@ -232,7 +231,6 @@
232231
"lorem-ipsum": "2.0.8",
233232
"mind-elixir": "4.4.3",
234233
"mini-css-extract-plugin": "2.9.2",
235-
"node-abi": "4.2.0",
236234
"nodemon": "3.1.9",
237235
"postcss-loader": "8.1.1",
238236
"prettier": "3.5.3",

0 commit comments

Comments
 (0)