diff --git a/apps/client/src/desktop.ts b/apps/client/src/desktop.ts
index 42e1c44e9..42fe11655 100644
--- a/apps/client/src/desktop.ts
+++ b/apps/client/src/desktop.ts
@@ -1,116 +1,7 @@
-import appContext from "./components/app_context.js";
-import utils from "./services/utils.js";
-import noteTooltipService from "./services/note_tooltip.js";
-import bundleService from "./services/bundle.js";
-import toastService from "./services/toast.js";
-import noteAutocompleteService from "./services/note_autocomplete.js";
-import electronContextMenu from "./menus/electron_context_menu.js";
-import glob from "./services/glob.js";
-import { t } from "./services/i18n.js";
-import options from "./services/options.js";
-import type ElectronRemote from "@electron/remote";
-import type Electron from "electron";
-import "./stylesheets/bootstrap.scss";
-import "boxicons";
-import "jquery-hotkeys";
-import "autocomplete.js/index_jquery.js";
+import $ from "jquery";
+(window as any).$ = $;
+(window as any).jQuery = $;
-await appContext.earlyInit();
+$("body").show();
-bundleService.getWidgetBundlesByParent().then(async (widgetBundles) => {
- // A dynamic import is required for layouts since they initialize components which require translations.
- const DesktopLayout = (await import("./layouts/desktop_layout.js")).default;
-
- appContext.setLayout(new DesktopLayout(widgetBundles));
- appContext.start().catch((e) => {
- toastService.showPersistent({
- title: t("toast.critical-error.title"),
- icon: "alert",
- message: t("toast.critical-error.message", { message: e.message })
- });
- console.error("Critical error occured", e);
- });
-});
-
-glob.setupGlobs();
-
-if (utils.isElectron()) {
- initOnElectron();
-}
-
-noteTooltipService.setupGlobalTooltip();
-
-noteAutocompleteService.init();
-
-if (utils.isElectron()) {
- electronContextMenu.setupContextMenu();
-}
-
-function initOnElectron() {
- const electron: typeof Electron = utils.dynamicRequire("electron");
- electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName));
- electron.ipcRenderer.on("openInSameTab", async (event, noteId) => appContext.tabManager.openInSameTab(noteId));
- const electronRemote: typeof ElectronRemote = utils.dynamicRequire("@electron/remote");
- const currentWindow = electronRemote.getCurrentWindow();
- const style = window.getComputedStyle(document.body);
-
- initDarkOrLightMode(style);
- initTransparencyEffects(style, currentWindow);
-
- if (options.get("nativeTitleBarVisible") !== "true") {
- initTitleBarButtons(style, currentWindow);
- }
-}
-
-function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
- if (window.glob.platform === "win32") {
- const applyWindowsOverlay = () => {
- const color = style.getPropertyValue("--native-titlebar-background");
- const symbolColor = style.getPropertyValue("--native-titlebar-foreground");
- if (color && symbolColor) {
- currentWindow.setTitleBarOverlay({ color, symbolColor });
- }
- };
-
- applyWindowsOverlay();
-
- // Register for changes to the native title bar colors.
- window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", applyWindowsOverlay);
- }
-
- if (window.glob.platform === "darwin") {
- const xOffset = parseInt(style.getPropertyValue("--native-titlebar-darwin-x-offset"), 10);
- const yOffset = parseInt(style.getPropertyValue("--native-titlebar-darwin-y-offset"), 10);
- currentWindow.setWindowButtonPosition({ x: xOffset, y: yOffset });
- }
-}
-
-function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
- if (window.glob.platform === "win32") {
- const material = style.getPropertyValue("--background-material");
- // TriliumNextTODO: find a nicer way to make TypeScript happy – unfortunately TS did not like Array.includes here
- const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const;
- const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
- if (foundBgMaterialOption) {
- currentWindow.setBackgroundMaterial(foundBgMaterialOption);
- }
- }
-}
-
-/**
- * Informs Electron that we prefer a dark or light theme. Apart from changing prefers-color-scheme at CSS level which is a side effect,
- * this fixes color issues with background effects or native title bars.
- *
- * @param style the root CSS element to read variables from.
- */
-function initDarkOrLightMode(style: CSSStyleDeclaration) {
- let themeSource: typeof nativeTheme.themeSource = "system";
-
- const themeStyle = style.getPropertyValue("--theme-style");
- if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) {
- themeSource = themeStyle;
- }
-
- const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote;
- nativeTheme.themeSource = themeSource;
-}
+await import("./desktop_main.js");
diff --git a/apps/client/src/desktop_main.ts b/apps/client/src/desktop_main.ts
new file mode 100644
index 000000000..42e1c44e9
--- /dev/null
+++ b/apps/client/src/desktop_main.ts
@@ -0,0 +1,116 @@
+import appContext from "./components/app_context.js";
+import utils from "./services/utils.js";
+import noteTooltipService from "./services/note_tooltip.js";
+import bundleService from "./services/bundle.js";
+import toastService from "./services/toast.js";
+import noteAutocompleteService from "./services/note_autocomplete.js";
+import electronContextMenu from "./menus/electron_context_menu.js";
+import glob from "./services/glob.js";
+import { t } from "./services/i18n.js";
+import options from "./services/options.js";
+import type ElectronRemote from "@electron/remote";
+import type Electron from "electron";
+import "./stylesheets/bootstrap.scss";
+import "boxicons";
+import "jquery-hotkeys";
+import "autocomplete.js/index_jquery.js";
+
+await appContext.earlyInit();
+
+bundleService.getWidgetBundlesByParent().then(async (widgetBundles) => {
+ // A dynamic import is required for layouts since they initialize components which require translations.
+ const DesktopLayout = (await import("./layouts/desktop_layout.js")).default;
+
+ appContext.setLayout(new DesktopLayout(widgetBundles));
+ appContext.start().catch((e) => {
+ toastService.showPersistent({
+ title: t("toast.critical-error.title"),
+ icon: "alert",
+ message: t("toast.critical-error.message", { message: e.message })
+ });
+ console.error("Critical error occured", e);
+ });
+});
+
+glob.setupGlobs();
+
+if (utils.isElectron()) {
+ initOnElectron();
+}
+
+noteTooltipService.setupGlobalTooltip();
+
+noteAutocompleteService.init();
+
+if (utils.isElectron()) {
+ electronContextMenu.setupContextMenu();
+}
+
+function initOnElectron() {
+ const electron: typeof Electron = utils.dynamicRequire("electron");
+ electron.ipcRenderer.on("globalShortcut", async (event, actionName) => appContext.triggerCommand(actionName));
+ electron.ipcRenderer.on("openInSameTab", async (event, noteId) => appContext.tabManager.openInSameTab(noteId));
+ const electronRemote: typeof ElectronRemote = utils.dynamicRequire("@electron/remote");
+ const currentWindow = electronRemote.getCurrentWindow();
+ const style = window.getComputedStyle(document.body);
+
+ initDarkOrLightMode(style);
+ initTransparencyEffects(style, currentWindow);
+
+ if (options.get("nativeTitleBarVisible") !== "true") {
+ initTitleBarButtons(style, currentWindow);
+ }
+}
+
+function initTitleBarButtons(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
+ if (window.glob.platform === "win32") {
+ const applyWindowsOverlay = () => {
+ const color = style.getPropertyValue("--native-titlebar-background");
+ const symbolColor = style.getPropertyValue("--native-titlebar-foreground");
+ if (color && symbolColor) {
+ currentWindow.setTitleBarOverlay({ color, symbolColor });
+ }
+ };
+
+ applyWindowsOverlay();
+
+ // Register for changes to the native title bar colors.
+ window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", applyWindowsOverlay);
+ }
+
+ if (window.glob.platform === "darwin") {
+ const xOffset = parseInt(style.getPropertyValue("--native-titlebar-darwin-x-offset"), 10);
+ const yOffset = parseInt(style.getPropertyValue("--native-titlebar-darwin-y-offset"), 10);
+ currentWindow.setWindowButtonPosition({ x: xOffset, y: yOffset });
+ }
+}
+
+function initTransparencyEffects(style: CSSStyleDeclaration, currentWindow: Electron.BrowserWindow) {
+ if (window.glob.platform === "win32") {
+ const material = style.getPropertyValue("--background-material");
+ // TriliumNextTODO: find a nicer way to make TypeScript happy – unfortunately TS did not like Array.includes here
+ const bgMaterialOptions = ["auto", "none", "mica", "acrylic", "tabbed"] as const;
+ const foundBgMaterialOption = bgMaterialOptions.find((bgMaterialOption) => material === bgMaterialOption);
+ if (foundBgMaterialOption) {
+ currentWindow.setBackgroundMaterial(foundBgMaterialOption);
+ }
+ }
+}
+
+/**
+ * Informs Electron that we prefer a dark or light theme. Apart from changing prefers-color-scheme at CSS level which is a side effect,
+ * this fixes color issues with background effects or native title bars.
+ *
+ * @param style the root CSS element to read variables from.
+ */
+function initDarkOrLightMode(style: CSSStyleDeclaration) {
+ let themeSource: typeof nativeTheme.themeSource = "system";
+
+ const themeStyle = style.getPropertyValue("--theme-style");
+ if (style.getPropertyValue("--theme-style-auto") !== "true" && (themeStyle === "light" || themeStyle === "dark")) {
+ themeSource = themeStyle;
+ }
+
+ const { nativeTheme } = utils.dynamicRequire("@electron/remote") as typeof ElectronRemote;
+ nativeTheme.themeSource = themeSource;
+}
diff --git a/apps/client/src/setup.ts b/apps/client/src/setup.ts
index 1ade057c1..033bb4f42 100644
--- a/apps/client/src/setup.ts
+++ b/apps/client/src/setup.ts
@@ -1,7 +1,8 @@
+import "jquery";
+import "jquery-hotkeys";
import utils from "./services/utils.js";
import ko from "knockout";
import "./stylesheets/bootstrap.scss";
-import "jquery-hotkeys";
// TriliumNextTODO: properly make use of below types
// type SetupModelSetupType = "new-document" | "sync-from-desktop" | "sync-from-server" | "";
diff --git a/apps/server/package.json b/apps/server/package.json
index 3c3f18eb1..2c8e50151 100644
--- a/apps/server/package.json
+++ b/apps/server/package.json
@@ -39,7 +39,6 @@
"@types/ws": "8.18.1",
"@types/xml2js": "0.4.14",
"express-http-proxy": "2.1.1",
- "jquery": "3.7.1",
"@anthropic-ai/sdk": "0.51.0",
"@braintree/sanitize-url": "7.1.1",
"@triliumnext/commons": "workspace:*",
diff --git a/apps/server/src/assets/views/desktop.ejs b/apps/server/src/assets/views/desktop.ejs
index 6ccc75560..5e6216477 100644
--- a/apps/server/src/assets/views/desktop.ejs
+++ b/apps/server/src/assets/views/desktop.ejs
@@ -34,9 +34,6 @@
-
-
-
@@ -59,10 +56,6 @@
-
-
diff --git a/apps/server/src/assets/views/mobile.ejs b/apps/server/src/assets/views/mobile.ejs
index a33e15997..2e2e7240f 100644
--- a/apps/server/src/assets/views/mobile.ejs
+++ b/apps/server/src/assets/views/mobile.ejs
@@ -111,8 +111,6 @@
<%- include("./partials/windowGlobal.ejs", locals) %>
-
-
diff --git a/apps/server/src/assets/views/setup.ejs b/apps/server/src/assets/views/setup.ejs
index 062d3cd03..484696f66 100644
--- a/apps/server/src/assets/views/setup.ejs
+++ b/apps/server/src/assets/views/setup.ejs
@@ -168,8 +168,6 @@
-
-
diff --git a/apps/server/src/routes/assets.ts b/apps/server/src/routes/assets.ts
index 90a07cd1a..0007b4577 100644
--- a/apps/server/src/routes/assets.ts
+++ b/apps/server/src/routes/assets.ts
@@ -44,10 +44,6 @@ async function register(app: express.Application) {
app.use(`/assets/vX/stylesheets`, express.static(path.join(srcRoot, "public/stylesheets")));
app.use(`/${assetPath}/libraries`, persistentCacheStatic(path.join(srcRoot, "public/libraries")));
app.use(`/assets/vX/libraries`, express.static(path.join(srcRoot, "..", "libraries")));
-
- const nodeModulesDir = isDev ? path.join(srcRoot, "..", "node_modules") : path.join(resourceDir, "node_modules");
-
- app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(nodeModulesDir, "jquery/dist/")));
}
export default {
diff --git a/apps/server/webpack.config.cjs b/apps/server/webpack.config.cjs
index 220b17646..6a5d7a05c 100644
--- a/apps/server/webpack.config.cjs
+++ b/apps/server/webpack.config.cjs
@@ -13,8 +13,6 @@ function buildFilesToCopy() {
});
const nodePaths = [
- "jquery/dist",
-
// Required as they are native dependencies and cannot be well bundled.
"better-sqlite3",
"bindings",