mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-09-02 05:00:40 +08:00
Merge pull request #1956 from TriliumNext/client_vite
Port client to Vite
This commit is contained in:
commit
a0a5a2c90d
@ -22,9 +22,12 @@
|
||||
"@mind-elixir/node-menu": "1.0.5",
|
||||
"@popperjs/core": "2.11.8",
|
||||
"@triliumnext/ckeditor5": "workspace:*",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"@triliumnext/codemirror": "workspace:*",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
"@triliumnext/highlightjs": "workspace:*",
|
||||
"autocomplete.js": "0.38.1",
|
||||
"bootstrap": "5.3.6",
|
||||
"boxicons": "2.1.4",
|
||||
"dayjs": "1.11.13",
|
||||
"dayjs-plugin-utc": "0.1.2",
|
||||
"debounce": "2.2.0",
|
||||
@ -37,6 +40,7 @@
|
||||
"jquery-hotkeys": "0.2.2",
|
||||
"jquery.fancytree": "2.38.5",
|
||||
"jsplumb": "2.15.6",
|
||||
"katex": "0.16.22",
|
||||
"knockout": "3.5.1",
|
||||
"leaflet": "1.9.4",
|
||||
"leaflet-gpx": "2.2.0",
|
||||
@ -44,6 +48,7 @@
|
||||
"marked": "15.0.12",
|
||||
"mermaid": "11.6.0",
|
||||
"mind-elixir": "4.5.2",
|
||||
"normalize.css": "8.0.1",
|
||||
"panzoom": "9.4.3",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
@ -57,11 +62,13 @@
|
||||
"@types/jquery": "3.5.32",
|
||||
"@types/leaflet": "1.9.18",
|
||||
"@types/leaflet-gpx": "1.3.7",
|
||||
"@types/mark.js": "8.11.12",
|
||||
"@types/react": "19.1.4",
|
||||
"@types/react-dom": "19.1.5",
|
||||
"copy-webpack-plugin": "13.0.0",
|
||||
"happy-dom": "17.4.7",
|
||||
"script-loader": "0.7.2"
|
||||
"script-loader": "0.7.2",
|
||||
"vite-plugin-static-copy": "3.0.0"
|
||||
},
|
||||
"nx": {
|
||||
"name": "client"
|
||||
|
@ -11,6 +11,9 @@ import options from "./services/options.js";
|
||||
import type ElectronRemote from "@electron/remote";
|
||||
import type Electron from "electron";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "jquery-hotkeys";
|
||||
import "autocomplete.js/index_jquery.js";
|
||||
|
||||
await appContext.earlyInit();
|
||||
|
||||
|
@ -2,6 +2,8 @@ import appContext from "./components/app_context.js";
|
||||
import noteAutocompleteService from "./services/note_autocomplete.js";
|
||||
import glob from "./services/glob.js";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "boxicons/css/boxicons.min.css";
|
||||
import "autocomplete.js/index_jquery.js";
|
||||
|
||||
glob.setupGlobs();
|
||||
|
||||
|
5
apps/client/src/runtime.ts
Normal file
5
apps/client/src/runtime.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import $ from "jquery";
|
||||
(window as any).$ = $;
|
||||
(window as any).jQuery = $;
|
||||
|
||||
$("body").show();
|
@ -1,7 +1,6 @@
|
||||
import renderService from "./render.js";
|
||||
import protectedSessionService from "./protected_session.js";
|
||||
import protectedSessionHolder from "./protected_session_holder.js";
|
||||
import libraryLoader from "./library_loader.js";
|
||||
import openService from "./open.js";
|
||||
import froca from "./froca.js";
|
||||
import utils from "./utils.js";
|
||||
@ -15,6 +14,7 @@ import { loadElkIfNeeded, postprocessMermaidSvg } from "./mermaid.js";
|
||||
import renderDoc from "./doc_renderer.js";
|
||||
import { t } from "../services/i18n.js";
|
||||
import WheelZoom from 'vanilla-js-wheel-zoom';
|
||||
import { renderMathInElement } from "./math.js";
|
||||
import { normalizeMimeTypeForCKEditor } from "@triliumnext/commons";
|
||||
|
||||
let idCounter = 1;
|
||||
@ -94,8 +94,6 @@ async function renderText(note: FNote | FAttachment, $renderedContent: JQuery<HT
|
||||
$renderedContent.append($('<div class="ck-content">').html(blob.content));
|
||||
|
||||
if ($renderedContent.find("span.math-tex").length > 0) {
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
|
||||
renderMathInElement($renderedContent[0], { trust: true });
|
||||
}
|
||||
|
||||
|
@ -48,5 +48,6 @@ function getUrl(docNameValue: string, language: string) {
|
||||
// Cannot have spaces in the URL due to how JQuery.load works.
|
||||
docNameValue = docNameValue.replaceAll(" ", "%20");
|
||||
|
||||
return `${window.glob.appPath}/doc_notes/${language}/${docNameValue}.html`;
|
||||
const basePath = window.glob.isDev ? new URL(window.glob.assetPath).pathname : window.glob.assetPath;
|
||||
return `${basePath}/doc_notes/${language}/${docNameValue}.html`;
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
import utils from "./utils.js";
|
||||
import appContext from "../components/app_context.js";
|
||||
import server from "./server.js";
|
||||
import libraryLoader from "./library_loader.js";
|
||||
import ws from "./ws.js";
|
||||
import froca from "./froca.js";
|
||||
import linkService from "./link.js";
|
||||
@ -17,7 +16,6 @@ function setupGlobs() {
|
||||
|
||||
// required for ESLint plugin and CKEditor
|
||||
window.glob.getActiveContextNote = () => appContext.tabManager.getActiveContextNote();
|
||||
window.glob.requireLibrary = libraryLoader.requireLibrary;
|
||||
window.glob.appContext = appContext; // for debugging
|
||||
window.glob.froca = froca;
|
||||
window.glob.treeCache = froca; // compatibility for CKEditor builds for a while
|
||||
@ -64,7 +62,7 @@ function setupGlobs() {
|
||||
});
|
||||
|
||||
for (const appCssNoteId of glob.appCssNoteIds || []) {
|
||||
libraryLoader.requireCss(`api/notes/download/${appCssNoteId}`, false);
|
||||
requireCss(`api/notes/download/${appCssNoteId}`, false);
|
||||
}
|
||||
|
||||
utils.initHelpButtons($(window));
|
||||
@ -76,6 +74,18 @@ function setupGlobs() {
|
||||
});
|
||||
}
|
||||
|
||||
async function requireCss(url: string, prependAssetPath = true) {
|
||||
const cssLinks = Array.from(document.querySelectorAll("link")).map((el) => el.href);
|
||||
|
||||
if (!cssLinks.some((l) => l.endsWith(url))) {
|
||||
if (prependAssetPath) {
|
||||
url = `${window.glob.assetPath}/${url}`;
|
||||
}
|
||||
|
||||
$("head").append($('<link rel="stylesheet" type="text/css" />').attr("href", url));
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
setupGlobs
|
||||
};
|
||||
|
@ -1,68 +0,0 @@
|
||||
export interface Library {
|
||||
js?: string[] | (() => string[]);
|
||||
css?: string[];
|
||||
}
|
||||
|
||||
const KATEX: Library = {
|
||||
js: ["node_modules/katex/dist/katex.min.js", "node_modules/katex/dist/contrib/mhchem.min.js", "node_modules/katex/dist/contrib/auto-render.min.js"],
|
||||
css: ["node_modules/katex/dist/katex.min.css"]
|
||||
};
|
||||
|
||||
async function requireLibrary(library: Library) {
|
||||
if (library.css) {
|
||||
library.css.map((cssUrl) => requireCss(cssUrl));
|
||||
}
|
||||
|
||||
if (library.js) {
|
||||
for (const scriptUrl of await unwrapValue(library.js)) {
|
||||
await requireScript(scriptUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function unwrapValue<T>(value: T | (() => T) | Promise<T>) {
|
||||
if (value && typeof value === "object" && "then" in value) {
|
||||
return (await (value as Promise<() => T>))();
|
||||
}
|
||||
|
||||
if (typeof value === "function") {
|
||||
return (value as () => T)();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
// we save the promises in case of the same script being required concurrently multiple times
|
||||
const loadedScriptPromises: Record<string, JQuery.jqXHR> = {};
|
||||
|
||||
async function requireScript(url: string) {
|
||||
url = `${window.glob.assetPath}/${url}`;
|
||||
|
||||
if (!loadedScriptPromises[url]) {
|
||||
loadedScriptPromises[url] = $.ajax({
|
||||
url: url,
|
||||
dataType: "script",
|
||||
cache: true
|
||||
});
|
||||
}
|
||||
|
||||
await loadedScriptPromises[url];
|
||||
}
|
||||
|
||||
async function requireCss(url: string, prependAssetPath = true) {
|
||||
const cssLinks = Array.from(document.querySelectorAll("link")).map((el) => el.href);
|
||||
|
||||
if (!cssLinks.some((l) => l.endsWith(url))) {
|
||||
if (prependAssetPath) {
|
||||
url = `${window.glob.assetPath}/${url}`;
|
||||
}
|
||||
|
||||
$("head").append($('<link rel="stylesheet" type="text/css" />').attr("href", url));
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
requireCss,
|
||||
requireLibrary,
|
||||
KATEX
|
||||
};
|
5
apps/client/src/services/math.ts
Normal file
5
apps/client/src/services/math.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import katex from "katex";
|
||||
import "katex/contrib/mhchem";
|
||||
import "katex/dist/katex.min.css";
|
||||
export { default as renderMathInElement } from "katex/contrib/auto-render";
|
||||
export default katex;
|
@ -1,3 +1,5 @@
|
||||
import "jquery";
|
||||
import "jquery-hotkeys";
|
||||
import utils from "./services/utils.js";
|
||||
import ko from "knockout";
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
|
@ -1,4 +1,5 @@
|
||||
import "./stylesheets/bootstrap.scss";
|
||||
import "normalize.css";
|
||||
import "@triliumnext/ckeditor5/content.css";
|
||||
|
||||
/**
|
||||
* Fetch note with given ID from backend
|
||||
|
4
apps/client/src/types-assets.d.ts
vendored
4
apps/client/src/types-assets.d.ts
vendored
@ -3,9 +3,7 @@ declare module "*.png" {
|
||||
export default path;
|
||||
}
|
||||
|
||||
declare module "*.json?external" {
|
||||
declare module "@triliumnext/ckeditor5/emoji_definitions/en.json?url" {
|
||||
var path: string;
|
||||
export default path;
|
||||
}
|
||||
|
||||
declare module "script-loader!mark.js/dist/jquery.mark.min.js";
|
||||
|
7
apps/client/src/types-lib.d.ts
vendored
7
apps/client/src/types-lib.d.ts
vendored
@ -24,3 +24,10 @@ declare module "draggabilly" {
|
||||
declare module "@mind-elixir/node-menu" {
|
||||
export default mindmap;
|
||||
}
|
||||
|
||||
declare module "katex/contrib/auto-render" {
|
||||
var renderMathInElement: (element: HTMLElement, options: {
|
||||
trust: boolean;
|
||||
}) => void;
|
||||
export default renderMathInElement;
|
||||
}
|
||||
|
12
apps/client/src/types.d.ts
vendored
12
apps/client/src/types.d.ts
vendored
@ -22,7 +22,6 @@ interface CustomGlobals {
|
||||
getReferenceLinkTitle: (href: string) => Promise<string>;
|
||||
getReferenceLinkTitleSync: (href: string) => string;
|
||||
getActiveContextNote: () => FNote | null;
|
||||
requireLibrary: typeof library_loader.requireLibrary;
|
||||
ESLINT: Library;
|
||||
appContext: AppContext;
|
||||
froca: Froca;
|
||||
@ -123,17 +122,6 @@ declare global {
|
||||
var require: RequireMethod;
|
||||
var __non_webpack_require__: RequireMethod | undefined;
|
||||
|
||||
// Libraries
|
||||
var renderMathInElement: (element: HTMLElement, options: {
|
||||
trust: boolean;
|
||||
}) => void;
|
||||
|
||||
var katex: {
|
||||
renderToString(text: string, opts: {
|
||||
throwOnError: boolean
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Panzoom
|
||||
*/
|
||||
|
@ -3,7 +3,6 @@ import utils from "../../services/utils.js";
|
||||
import server from "../../services/server.js";
|
||||
import toastService from "../../services/toast.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import libraryLoader from "../../services/library_loader.js";
|
||||
import openService from "../../services/open.js";
|
||||
import protectedSessionHolder from "../../services/protected_session_holder.js";
|
||||
import BasicWidget from "../basic_widget.js";
|
||||
@ -12,6 +11,7 @@ import options from "../../services/options.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { NoteType } from "../../entities/fnote.js";
|
||||
import { Dropdown, Modal } from "bootstrap";
|
||||
import { renderMathInElement } from "../../services/math.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="revisions-dialog modal fade mx-auto" tabindex="-1" role="dialog">
|
||||
@ -315,8 +315,6 @@ export default class RevisionsDialog extends BasicWidget {
|
||||
this.$content.html(`<div class="ck-content">${fullRevision.content}</div>`);
|
||||
|
||||
if (this.$content.find("span.math-tex").length > 0) {
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
|
||||
renderMathInElement(this.$content[0], { trust: true });
|
||||
}
|
||||
} else if (revisionItem.type === "code") {
|
||||
|
@ -21,7 +21,7 @@ export default class FindInHtml {
|
||||
}
|
||||
|
||||
async performFind(searchTerm: string, matchCase: boolean, wholeWord: boolean) {
|
||||
await import("script-loader!mark.js/dist/jquery.mark.min.js");
|
||||
await import("mark.js");
|
||||
|
||||
const $content = await this.parent?.noteContext?.getContentElement();
|
||||
|
||||
@ -42,7 +42,7 @@ export default class FindInHtml {
|
||||
const containerTop = scrollingContainer?.getBoundingClientRect().top ?? 0;
|
||||
const closestIndex = this.$results.toArray().findIndex(el => el.getBoundingClientRect().top >= containerTop);
|
||||
this.currentIndex = closestIndex >= 0 ? closestIndex : 0;
|
||||
|
||||
|
||||
await this.jumpTo();
|
||||
|
||||
res({
|
||||
|
@ -11,8 +11,8 @@ import RightPanelWidget from "./right_panel_widget.js";
|
||||
import options from "../services/options.js";
|
||||
import OnClickButtonWidget from "./buttons/onclick_button.js";
|
||||
import appContext, { type EventData } from "../components/app_context.js";
|
||||
import libraryLoader from "../services/library_loader.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
import katex from "../services/math.js";
|
||||
|
||||
const TPL = /*html*/`<div class="highlights-list-widget">
|
||||
<style>
|
||||
@ -175,7 +175,6 @@ export default class HighlightsListWidget extends RightPanelWidget {
|
||||
} catch (e) {
|
||||
if (e instanceof ReferenceError && e.message.includes("katex is not defined")) {
|
||||
// Load KaTeX if it is not already loaded
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
try {
|
||||
rendered = katex.renderToString(latexCode, {
|
||||
throwOnError: false
|
||||
|
@ -27,6 +27,11 @@ import type { AttributeRow, BranchRow } from "../services/load_results.js";
|
||||
import type { SetNoteOpts } from "../components/note_context.js";
|
||||
import type { TouchBarItem } from "../components/touch_bar.js";
|
||||
import type { TreeCommandNames } from "../menus/tree_context_menu.js";
|
||||
import "jquery.fancytree";
|
||||
import "jquery.fancytree/dist/modules/jquery.fancytree.dnd5.js";
|
||||
import "jquery.fancytree/dist/modules/jquery.fancytree.clones.js";
|
||||
import "jquery.fancytree/dist/modules/jquery.fancytree.filter.js";
|
||||
import "../stylesheets/tree.css";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="tree-wrapper">
|
||||
|
@ -19,7 +19,7 @@ import RightPanelWidget from "./right_panel_widget.js";
|
||||
import options from "../services/options.js";
|
||||
import OnClickButtonWidget from "./buttons/onclick_button.js";
|
||||
import appContext, { type EventData } from "../components/app_context.js";
|
||||
import libraryLoader from "../services/library_loader.js";
|
||||
import katex from "../services/math.js";
|
||||
import type FNote from "../entities/fnote.js";
|
||||
|
||||
const TPL = /*html*/`<div class="toc-widget">
|
||||
@ -55,7 +55,7 @@ const TPL = /*html*/`<div class="toc-widget">
|
||||
display: flex;
|
||||
position: relative;
|
||||
list-style: none;
|
||||
align-items: center;
|
||||
align-items: center;
|
||||
padding-left: 7px;
|
||||
cursor: pointer;
|
||||
text-align: justify;
|
||||
@ -254,7 +254,6 @@ export default class TocWidget extends RightPanelWidget {
|
||||
} catch (e) {
|
||||
if (e instanceof ReferenceError && e.message.includes("katex is not defined")) {
|
||||
// Load KaTeX if it is not already loaded
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
try {
|
||||
rendered = katex.renderToString(latexCode, {
|
||||
throwOnError: false
|
||||
@ -297,13 +296,13 @@ export default class TocWidget extends RightPanelWidget {
|
||||
let curLevel = 2;
|
||||
const $ols = [$toc];
|
||||
let $previousLi: JQuery<HTMLElement> | undefined;
|
||||
|
||||
|
||||
if (!(this.noteContext?.viewScope?.tocCollapsedHeadings instanceof Set)) {
|
||||
this.noteContext!.viewScope!.tocCollapsedHeadings = new Set<string>();
|
||||
}
|
||||
const tocCollapsedHeadings = this.noteContext!.viewScope!.tocCollapsedHeadings as Set<string>;
|
||||
const validHeadingKeys = new Set<string>(); // Used to clean up obsolete entries in tocCollapsedHeadings
|
||||
|
||||
|
||||
let headingCount = 0;
|
||||
for (let m = null, headingIndex = 0; (m = headingTagsRegex.exec(html)) !== null; headingIndex++) {
|
||||
//
|
||||
@ -426,7 +425,7 @@ export default class TocWidget extends RightPanelWidget {
|
||||
const willCollapse = !$previousLi.hasClass("collapsed");
|
||||
$previousLi.addClass("animating");
|
||||
|
||||
if (willCollapse) { // Collapse
|
||||
if (willCollapse) { // Collapse
|
||||
$ol.css("maxHeight", `${$ol.prop("scrollHeight")}px`);
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
|
@ -132,7 +132,7 @@ export default class ExcalidrawTypeWidget extends TypeWidget {
|
||||
|
||||
// currently required by excalidraw, in order to allows self-hosting fonts locally.
|
||||
// this avoids making excalidraw load the fonts from an external CDN.
|
||||
(window as any).EXCALIDRAW_ASSET_PATH = `${window.location.origin}/${asset_path}/app-dist/excalidraw/`;
|
||||
(window as any).EXCALIDRAW_ASSET_PATH = `${new URL(import.meta.url).origin}/node_modules/@excalidraw/excalidraw/dist/prod`;
|
||||
|
||||
// temporary vars
|
||||
this.currentNoteId = "";
|
||||
|
@ -4,7 +4,7 @@ import { getHighlightJsNameForMime } from "../../../services/mime_types.js";
|
||||
import options from "../../../services/options.js";
|
||||
import { ensureMimeTypesForHighlighting, isSyntaxHighlightEnabled } from "../../../services/syntax_highlight.js";
|
||||
import utils from "../../../services/utils.js";
|
||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?external";
|
||||
import emojiDefinitionsUrl from "@triliumnext/ckeditor5/emoji_definitions/en.json?url";
|
||||
|
||||
const TEXT_FORMATTING_GROUP = {
|
||||
label: "Text formatting",
|
||||
@ -100,7 +100,7 @@ export function buildConfig() {
|
||||
allowedProtocols: ALLOWED_PROTOCOLS
|
||||
},
|
||||
emoji: {
|
||||
definitionsUrl: emojiDefinitionsUrl
|
||||
definitionsUrl: new URL(import.meta.url).origin + emojiDefinitionsUrl
|
||||
},
|
||||
syntaxHighlighting: {
|
||||
loadHighlightJs: async () => {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { t } from "../../services/i18n.js";
|
||||
import libraryLoader from "../../services/library_loader.js";
|
||||
import noteAutocompleteService, { type Suggestion } from "../../services/note_autocomplete.js";
|
||||
import mimeTypesService from "../../services/mime_types.js";
|
||||
import utils, { hasTouchBar } from "../../services/utils.js";
|
||||
@ -310,7 +309,9 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
||||
math: {
|
||||
engine: "katex",
|
||||
outputType: "span", // or script
|
||||
lazyLoad: async () => await libraryLoader.requireLibrary(libraryLoader.KATEX),
|
||||
lazyLoad: async () => {
|
||||
(window as any).katex = (await import("../../services/math.js")).default
|
||||
},
|
||||
forceOutputType: false, // forces output to use outputType
|
||||
enablePreview: true // Enable preview view
|
||||
},
|
||||
|
@ -1,11 +1,11 @@
|
||||
import AbstractTextTypeWidget from "./abstract_text_type_widget.js";
|
||||
import libraryLoader from "../../services/library_loader.js";
|
||||
import { applySyntaxHighlight } from "../../services/syntax_highlight.js";
|
||||
import type FNote from "../../entities/fnote.js";
|
||||
import type { CommandListenerData, EventData } from "../../components/app_context.js";
|
||||
import { getLocaleById } from "../../services/i18n.js";
|
||||
import appContext from "../../components/app_context.js";
|
||||
import { getMermaidConfig } from "../../services/mermaid.js";
|
||||
import { renderMathInElement } from "../../services/math.js";
|
||||
|
||||
const TPL = /*html*/`
|
||||
<div class="note-detail-readonly-text note-detail-printable" tabindex="100">
|
||||
@ -121,8 +121,6 @@ export default class ReadOnlyTextTypeWidget extends AbstractTextTypeWidget {
|
||||
});
|
||||
|
||||
if (this.$content.find("span.math-tex").length > 0) {
|
||||
await libraryLoader.requireLibrary(libraryLoader.KATEX);
|
||||
|
||||
renderMathInElement(this.$content[0], { trust: true });
|
||||
}
|
||||
|
||||
|
@ -215,7 +215,7 @@ class ListOrGridView extends ViewMode {
|
||||
|
||||
const highlightedTokens = this.parentNote.highlightedTokens || [];
|
||||
if (highlightedTokens.length > 0) {
|
||||
await import("script-loader!mark.js/dist/jquery.mark.min.js");
|
||||
await import("mark.js");
|
||||
|
||||
const regex = highlightedTokens.map((token) => utils.escapeRegExp(token)).join("|");
|
||||
|
||||
|
@ -1,21 +1,94 @@
|
||||
|
||||
/// <reference types='vitest' />
|
||||
import { join, resolve } from 'path';
|
||||
import { defineConfig } from 'vite';
|
||||
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
||||
import asset_path from './src/asset_path';
|
||||
|
||||
const assets = [ "assets", "stylesheets", "libraries", "fonts", "translations" ];
|
||||
|
||||
export default defineConfig(() => ({
|
||||
root: __dirname,
|
||||
cacheDir: '../../node_modules/.vite/apps/client',
|
||||
plugins: [],
|
||||
test: {
|
||||
watch: false,
|
||||
globals: true,
|
||||
setupFiles: ["./src/test/setup.ts"],
|
||||
environment: "happy-dom",
|
||||
include: ["src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
|
||||
reporters: ["default"],
|
||||
coverage: {
|
||||
reportsDirectory: './test-output/vitest/coverage',
|
||||
provider: 'v8' as const,
|
||||
reporter: [ "text", "html" ]
|
||||
base: "/" + asset_path,
|
||||
server: {
|
||||
port: 4200,
|
||||
host: 'localhost',
|
||||
},
|
||||
preview: {
|
||||
port: 4300,
|
||||
host: 'localhost',
|
||||
},
|
||||
plugins: [
|
||||
viteStaticCopy({
|
||||
targets: assets.map((asset) => ({
|
||||
src: `src/${asset}/**/*`,
|
||||
dest: asset
|
||||
}))
|
||||
}),
|
||||
viteStaticCopy({
|
||||
structured: true,
|
||||
targets: [
|
||||
{
|
||||
src: "node_modules/@excalidraw/excalidraw/dist/prod/fonts/*",
|
||||
dest: "",
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: [
|
||||
// Force the use of dist in development mode because upstream ESM is broken (some hybrid between CJS and ESM, will be improved in upcoming versions).
|
||||
{
|
||||
find: "@triliumnext/highlightjs",
|
||||
replacement: resolve(__dirname, "node_modules/@triliumnext/highlightjs/dist")
|
||||
}
|
||||
]
|
||||
},
|
||||
// Uncomment this if you are using workers.
|
||||
// worker: {
|
||||
// plugins: [ nxViteTsPaths() ],
|
||||
// },
|
||||
build: {
|
||||
target: "esnext",
|
||||
outDir: './dist',
|
||||
emptyOutDir: true,
|
||||
reportCompressedSize: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
desktop: join(__dirname, "src", "desktop.ts"),
|
||||
mobile: join(__dirname, "src", "mobile.ts"),
|
||||
login: join(__dirname, "src", "login.ts"),
|
||||
setup: join(__dirname, "src", "setup.ts"),
|
||||
share: join(__dirname, "src", "share.ts"),
|
||||
set_password: join(__dirname, "src", "set_password.ts"),
|
||||
runtime: join(__dirname, "src", "runtime.ts")
|
||||
},
|
||||
output: {
|
||||
entryFileNames: "src/[name].js",
|
||||
chunkFileNames: "src/[name].js",
|
||||
assetFileNames: "src/[name].[ext]"
|
||||
},
|
||||
onwarn(warning, rollupWarn) {
|
||||
if (warning.code === "MODULE_LEVEL_DIRECTIVE") {
|
||||
return;
|
||||
}
|
||||
rollupWarn(warning);
|
||||
}
|
||||
}
|
||||
},
|
||||
optimizeDeps: {
|
||||
exclude: [
|
||||
"@triliumnext/highlightjs"
|
||||
]
|
||||
},
|
||||
css: {
|
||||
preprocessorOptions: {
|
||||
scss: {
|
||||
quietDeps: true
|
||||
}
|
||||
}
|
||||
},
|
||||
commonjsOptions: {
|
||||
transformMixedEsModules: true,
|
||||
}
|
||||
}));
|
||||
|
@ -1,128 +0,0 @@
|
||||
|
||||
const { composePlugins, withNx, withWeb } = require('@nx/webpack');
|
||||
const { join } = require('path');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
|
||||
module.exports = composePlugins(
|
||||
withNx({
|
||||
tsConfig: join(__dirname, './tsconfig.app.json'),
|
||||
compiler: "tsc",
|
||||
main: join(__dirname, "./src/index.ts"),
|
||||
additionalEntryPoints: [
|
||||
{
|
||||
entryName: "desktop",
|
||||
entryPath: join(__dirname, "./src/desktop.ts")
|
||||
},
|
||||
{
|
||||
entryName: "mobile",
|
||||
entryPath: join(__dirname, "./src/mobile.ts")
|
||||
},
|
||||
{
|
||||
entryName: "login",
|
||||
entryPath: join(__dirname, "./src/login.ts")
|
||||
},
|
||||
{
|
||||
entryName: "setup",
|
||||
entryPath: join(__dirname, "./src/setup.ts")
|
||||
},
|
||||
{
|
||||
entryName: "share",
|
||||
entryPath: join(__dirname, "./src/share.ts")
|
||||
},
|
||||
{
|
||||
// TriliumNextTODO: integrate set_password into setup entry point/view
|
||||
entryName: "set_password",
|
||||
entryPath: join(__dirname, "./src/set_password.ts")
|
||||
}
|
||||
],
|
||||
externalDependencies: [
|
||||
"electron"
|
||||
],
|
||||
baseHref: '/',
|
||||
outputHashing: false,
|
||||
optimization: process.env['NODE_ENV'] === 'production'
|
||||
}),
|
||||
withWeb({
|
||||
styles: [],
|
||||
stylePreprocessorOptions: {
|
||||
sassOptions: {
|
||||
quietDeps: true
|
||||
}
|
||||
},
|
||||
}),
|
||||
(config) => {
|
||||
config.output = {
|
||||
path: join(__dirname, 'dist')
|
||||
};
|
||||
|
||||
config.devServer = {
|
||||
port: 4200,
|
||||
client: {
|
||||
overlay: {
|
||||
errors: true,
|
||||
warnings: false,
|
||||
runtimeErrors: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config.resolve.fallback = {
|
||||
path: false,
|
||||
fs: false,
|
||||
util: false
|
||||
};
|
||||
|
||||
const assets = [ "assets", "stylesheets", "libraries", "fonts", "translations" ]
|
||||
config.plugins.push(new CopyPlugin({
|
||||
patterns: assets.map((asset) => ({
|
||||
from: join(__dirname, "src", asset),
|
||||
to: asset
|
||||
}))
|
||||
}));
|
||||
|
||||
inlineCss(config);
|
||||
inlineSvg(config);
|
||||
externalJson(config);
|
||||
|
||||
return config;
|
||||
}
|
||||
);
|
||||
|
||||
function inlineSvg(config) {
|
||||
if (!config.module?.rules) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Alter Nx's asset rule to avoid inlining SVG if they have ?raw prepended.
|
||||
const existingRule = config.module.rules.find((r) => r.test.toString() === /\.svg$/.toString());
|
||||
existingRule.resourceQuery = { not: [/raw/] };
|
||||
|
||||
// Add a rule for prepending ?raw SVGs.
|
||||
config.module.rules.push({
|
||||
resourceQuery: /raw/,
|
||||
type: 'asset/source',
|
||||
});
|
||||
}
|
||||
|
||||
function inlineCss(config) {
|
||||
if (!config.module?.rules) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Alter Nx's asset rule to avoid inlining SVG if they have ?raw prepended.
|
||||
console.log(config.module.rules.map((r) => r.test.toString()));
|
||||
const existingRule = config.module.rules.find((r) => r.test.toString().startsWith("/\\.css"));
|
||||
existingRule.resourceQuery = { not: [/raw/] };
|
||||
}
|
||||
|
||||
function externalJson(config) {
|
||||
if (!config.module?.rules) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add a rule for prepending ?external.
|
||||
config.module.rules.push({
|
||||
resourceQuery: /external/,
|
||||
type: 'asset/resource',
|
||||
});
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
TRILIUM_ENV=production
|
||||
TRILIUM_DATA_DIR=./apps/server/data
|
||||
TRILIUM_DATA_DIR=./apps/server/data
|
||||
TRILIUM_PORT=8082
|
@ -4,13 +4,10 @@
|
||||
"description": "The server-side component of TriliumNext, which exposes the client via the web, allows for sync and provides a REST API for both internal and external use.",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"better-sqlite3": "11.10.0",
|
||||
"jquery.fancytree": "2.38.5",
|
||||
"jquery-hotkeys": "0.2.2"
|
||||
"better-sqlite3": "11.10.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@electron/remote": "2.1.2",
|
||||
"@excalidraw/excalidraw": "0.18.0",
|
||||
"@types/archiver": "6.0.3",
|
||||
"@types/better-sqlite3": "7.6.13",
|
||||
"@types/cls-hooked": "4.3.9",
|
||||
@ -41,12 +38,7 @@
|
||||
"@types/turndown": "5.0.5",
|
||||
"@types/ws": "8.18.1",
|
||||
"@types/xml2js": "0.4.14",
|
||||
"autocomplete.js": "0.38.1",
|
||||
"boxicons": "2.1.4",
|
||||
"express-http-proxy": "2.1.1",
|
||||
"jquery": "3.7.1",
|
||||
"katex": "0.16.22",
|
||||
"normalize.css": "8.0.1",
|
||||
"@anthropic-ai/sdk": "0.51.0",
|
||||
"@braintree/sanitize-url": "7.1.1",
|
||||
"@triliumnext/commons": "workspace:*",
|
||||
|
@ -5,7 +5,7 @@ import cookieParser from "cookie-parser";
|
||||
import helmet from "helmet";
|
||||
import compression from "compression";
|
||||
import config from "./services/config.js";
|
||||
import utils, { getResourceDir } from "./services/utils.js";
|
||||
import utils, { getResourceDir, isDev } from "./services/utils.js";
|
||||
import assets from "./routes/assets.js";
|
||||
import routes from "./routes/routes.js";
|
||||
import custom from "./routes/custom.js";
|
||||
@ -63,7 +63,7 @@ export default async function buildApp() {
|
||||
console.log("Database not initialized yet. LLM features will be initialized after setup.");
|
||||
}
|
||||
|
||||
const publicDir = path.join(getResourceDir(), "public");
|
||||
const publicDir = isDev ? path.join(getResourceDir(), "../dist/public") : path.join(getResourceDir(), "public");
|
||||
const publicAssetsDir = path.join(publicDir, "assets");
|
||||
const assetsDir = RESOURCE_DIR;
|
||||
|
||||
|
@ -7,8 +7,6 @@
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, viewport-fit=cover" />
|
||||
<link rel="manifest" crossorigin="use-credentials" href="manifest.webmanifest">
|
||||
<% // TriliumNextTODO: move the css file to ${assetPath}/stylesheets/ %>
|
||||
<link rel="stylesheet" href="<%= appPath %>/desktop.css">
|
||||
<title>TriliumNext Notes</title>
|
||||
</head>
|
||||
<body class="desktop heading-style-<%= headingStyle %> layout-<%= layoutOrientation %> platform-<%= platform %> <%= isElectron ? 'electron' : '' %> <%= hasNativeTitleBar ? 'native-titlebar' : '' %> <%= hasBackgroundEffects ? 'background-effects' : '' %>">
|
||||
@ -34,17 +32,7 @@
|
||||
<!-- Required for correct loading of scripts in Electron -->
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
|
||||
|
||||
<!-- Include Fancytree library and skip -->
|
||||
<link href="<%= assetPath %>/stylesheets/tree.css" rel="stylesheet">
|
||||
<script src="<%= assetPath %>/node_modules/jquery.fancytree/dist/jquery.fancytree-all-deps.min.js"></script>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/jquery-hotkeys/jquery-hotkeys.js"></script>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/autocomplete.js/dist/autocomplete.jquery.min.js"></script>
|
||||
|
||||
<link href="<%= appPath %>/bootstrap.css" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/ckeditor-theme.css" rel="stylesheet">
|
||||
<link href="api/fonts" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/theme-light.css" rel="stylesheet">
|
||||
@ -64,14 +52,8 @@
|
||||
<link href="<%= assetPath %>/stylesheets/style.css" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/print.css" rel="stylesheet" media="print">
|
||||
|
||||
<script>
|
||||
$("body").show();
|
||||
</script>
|
||||
|
||||
<script src="<%= appPath %>/runtime.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/desktop.js" crossorigin type="module"></script>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<%= assetPath %>/node_modules/boxicons/css/boxicons.min.css">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -13,7 +13,7 @@
|
||||
}
|
||||
</style>
|
||||
<% // TriliumNextTODO: move the css file to ${assetPath}/stylesheets/ %>
|
||||
<link rel="stylesheet" href="<%= appPath %>/login.css">
|
||||
<link rel="stylesheet" href="<%= appPath %>/bootstrap.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-light.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/style.css">
|
||||
|
@ -10,9 +10,6 @@
|
||||
<title>TriliumNext Notes</title>
|
||||
<link rel="manifest" crossorigin="use-credentials" href="manifest.webmanifest">
|
||||
|
||||
<% // TriliumNextTODO: move the css file to ${assetPath}/stylesheets/ %>
|
||||
<link rel="stylesheet" href="<%= appPath %>/mobile.css">
|
||||
|
||||
<style>
|
||||
.lds-roller {
|
||||
display: inline-block;
|
||||
@ -111,17 +108,11 @@
|
||||
|
||||
<%- include("./partials/windowGlobal.ejs", locals) %>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/autocomplete.js/dist/autocomplete.jquery.min.js"></script>
|
||||
|
||||
<link href="<%= assetPath %>/stylesheets/tree.css" rel="stylesheet">
|
||||
<script src="<%= assetPath %>/node_modules/jquery.fancytree/dist/jquery.fancytree-all-deps.min.js"></script>
|
||||
|
||||
<script src="<%= appPath %>/runtime.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/mobile.js" crossorigin type="module"></script>
|
||||
|
||||
<link href="api/fonts" rel="stylesheet">
|
||||
<link rel="stylesheet" href="<%= appPath %>/bootstrap.css">
|
||||
<link href="<%= assetPath %>/stylesheets/ckeditor-theme.css" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/theme-light.css" rel="stylesheet">
|
||||
<% if (themeCssUrl) { %>
|
||||
@ -130,7 +121,5 @@
|
||||
<link href="<%= assetPath %>/stylesheets/style.css" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/print.css" rel="stylesheet" media="print">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="<%= assetPath %>/node_modules/boxicons/css/boxicons.min.css">
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
@ -7,7 +7,7 @@
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="<%= assetPath %>/images/app-icons/ios/apple-touch-icon.png">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<% // TriliumNextTODO: move the css file to ${assetPath}/stylesheets/ %>
|
||||
<link rel="stylesheet" href="<%= appPath %>/set_password.css">
|
||||
<link rel="stylesheet" href="<%= appPath %>/bootstrap.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-light.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/theme-next.css">
|
||||
<link rel="stylesheet" href="<%= assetPath %>/stylesheets/style.css">
|
||||
|
@ -7,7 +7,7 @@
|
||||
<title><%= t("setup.title") %></title>
|
||||
|
||||
<% // TriliumNextTODO: move the css file to ${assetPath}/stylesheets/ %>
|
||||
<link rel="stylesheet" href="<%= appPath %>/setup.css">
|
||||
<link rel="stylesheet" href="<%= appPath %>/bootstrap.css">
|
||||
|
||||
<style>
|
||||
.lds-ring {
|
||||
@ -168,9 +168,6 @@
|
||||
<!-- Required for correct loading of scripts in Electron -->
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
|
||||
<script src="<%= assetPath %>/node_modules/jquery/dist/jquery.min.js"></script>
|
||||
<script src="<%= assetPath %>/node_modules/jquery-hotkeys/jquery-hotkeys.js"></script>
|
||||
|
||||
<script src="<%= appPath %>/runtime.js" crossorigin type="module"></script>
|
||||
<script src="<%= appPath %>/setup.js" crossorigin type="module"></script>
|
||||
<link href="<%= assetPath %>/stylesheets/theme-light.css" rel="stylesheet" />
|
||||
|
@ -12,13 +12,9 @@
|
||||
<% } else { %>
|
||||
<link rel="shortcut icon" href="../favicon.ico">
|
||||
<% } %>
|
||||
<script src="../<%= appPath %>/share.js"></script>
|
||||
<script src="<%= appPath %>/share.js" type="module"></script>
|
||||
<% if (!note.isLabelTruthy("shareOmitDefaultCss")) { %>
|
||||
<link href="../<%= assetPath %>/node_modules/normalize.css/normalize.css" rel="stylesheet">
|
||||
<link href="../<%= assetPath %>/stylesheets/share.css" rel="stylesheet">
|
||||
<% } %>
|
||||
<% if (note.type === 'text' || note.type === 'book') { %>
|
||||
<link href="../<%= assetPath %>/libraries/ckeditor/ckeditor-content.css" rel="stylesheet">
|
||||
<link href="<%= assetPath %>/stylesheets/share.css" rel="stylesheet">
|
||||
<% } %>
|
||||
<% for (const cssRelation of note.getRelations("shareCss")) { %>
|
||||
<link href="api/notes/<%= cssRelation.value %>/download" rel="stylesheet">
|
||||
|
@ -1,11 +1,10 @@
|
||||
import assetPath from "../services/asset_path.js";
|
||||
import { assetUrlFragment } from "../services/asset_path.js";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import express from "express";
|
||||
import { getResourceDir, isDev } from "../services/utils.js";
|
||||
import type serveStatic from "serve-static";
|
||||
import proxy from "express-http-proxy";
|
||||
import contentCss from "@triliumnext/ckeditor5/content.css";
|
||||
|
||||
const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOptions<express.Response<unknown, Record<string, unknown>>>) => {
|
||||
if (!isDev) {
|
||||
@ -21,75 +20,29 @@ async function register(app: express.Application) {
|
||||
const srcRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const resourceDir = getResourceDir();
|
||||
|
||||
app.use(`/${assetPath}/libraries/ckeditor/ckeditor-content.css`, (req, res) => res.contentType("text/css").send(contentCss));
|
||||
|
||||
if (isDev) {
|
||||
const publicUrl = process.env.TRILIUM_PUBLIC_SERVER;
|
||||
if (!publicUrl) {
|
||||
throw new Error("Missing TRILIUM_PUBLIC_SERVER");
|
||||
}
|
||||
|
||||
const clientProxy = proxy(publicUrl);
|
||||
app.use(`/${assetPath}/app/doc_notes`, persistentCacheStatic(path.join(srcRoot, "assets", "doc_notes")));
|
||||
app.use(`/${assetPath}/app`, clientProxy);
|
||||
app.use(`/${assetPath}/app-dist`, clientProxy);
|
||||
app.use(`/${assetPath}/stylesheets`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/stylesheets" + req.url
|
||||
app.use("/" + assetUrlFragment + `/@fs`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/" + assetUrlFragment + `/@fs` + req.url
|
||||
}));
|
||||
app.use(`/${assetPath}/libraries`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/libraries" + req.url
|
||||
}));
|
||||
app.use(`/${assetPath}/fonts`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/fonts" + req.url
|
||||
}));
|
||||
app.use(`/${assetPath}/translations`, proxy(publicUrl, {
|
||||
proxyReqPathResolver: (req) => "/translations" + req.url
|
||||
}));
|
||||
app.use(`/${assetPath}/images`, persistentCacheStatic(path.join(srcRoot, "assets", "images")));
|
||||
} else {
|
||||
const clientStaticCache = persistentCacheStatic(path.join(resourceDir, "public"));
|
||||
app.use(`/${assetPath}/app`, clientStaticCache);
|
||||
app.use(`/${assetPath}/app-dist`, clientStaticCache);
|
||||
app.use(`/${assetPath}/stylesheets`, persistentCacheStatic(path.join(resourceDir, "public", "stylesheets")));
|
||||
app.use(`/${assetPath}/libraries`, persistentCacheStatic(path.join(resourceDir, "public", "libraries")));
|
||||
app.use(`/${assetPath}/fonts`, persistentCacheStatic(path.join(resourceDir, "public", "fonts")));
|
||||
app.use(`/${assetPath}/translations/`, persistentCacheStatic(path.join(resourceDir, "public", "translations")));
|
||||
app.use(`/${assetPath}/images`, persistentCacheStatic(path.join(resourceDir, "assets", "images")));
|
||||
app.use(`/${assetPath}/app-dist/doc_notes`, persistentCacheStatic(path.join(resourceDir, "assets", "doc_notes")));
|
||||
app.use(`/${assetPath}/app-dist/excalidraw/fonts`, persistentCacheStatic(path.join(resourceDir, "node_modules/@excalidraw/excalidraw/dist/prod/fonts")));
|
||||
app.use(`/${assetUrlFragment}/src`, persistentCacheStatic(path.join(resourceDir, "public", "src")));
|
||||
app.use(`/${assetUrlFragment}/stylesheets`, persistentCacheStatic(path.join(resourceDir, "public", "stylesheets")));
|
||||
app.use(`/${assetUrlFragment}/libraries`, persistentCacheStatic(path.join(resourceDir, "public", "libraries")));
|
||||
app.use(`/${assetUrlFragment}/fonts`, persistentCacheStatic(path.join(resourceDir, "public", "fonts")));
|
||||
app.use(`/${assetUrlFragment}/translations/`, persistentCacheStatic(path.join(resourceDir, "public", "translations")));
|
||||
app.use(`/${assetUrlFragment}/images`, persistentCacheStatic(path.join(resourceDir, "assets", "images")));
|
||||
app.use(`/node_modules/`, persistentCacheStatic(path.join(resourceDir, "public/node_modules")));
|
||||
}
|
||||
app.use(`/${assetUrlFragment}/doc_notes`, persistentCacheStatic(path.join(resourceDir, "assets", "doc_notes")));
|
||||
app.use(`/assets/vX/fonts`, express.static(path.join(srcRoot, "public/fonts")));
|
||||
app.use(`/assets/vX/images`, express.static(path.join(srcRoot, "..", "images")));
|
||||
app.use(`/assets/vX/stylesheets`, express.static(path.join(srcRoot, "public/stylesheets")));
|
||||
app.use(`/${assetPath}/libraries`, persistentCacheStatic(path.join(srcRoot, "public/libraries")));
|
||||
app.use(`/${assetUrlFragment}/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(`/node_modules/@excalidraw/excalidraw/dist/fonts/`, express.static(path.join(nodeModulesDir, "@excalidraw/excalidraw/dist/prod/fonts/")));
|
||||
app.use(`/${assetPath}/node_modules/@excalidraw/excalidraw/dist/fonts/`, persistentCacheStatic(path.join(nodeModulesDir, "@excalidraw/excalidraw/dist/prod/fonts/")));
|
||||
|
||||
// KaTeX
|
||||
app.use(`/${assetPath}/node_modules/katex/dist/katex.min.js`, persistentCacheStatic(path.join(nodeModulesDir, "katex/dist/katex.min.js")));
|
||||
app.use(`/${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js`, persistentCacheStatic(path.join(nodeModulesDir, "katex/dist/contrib/mhchem.min.js")));
|
||||
app.use(`/${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js`, persistentCacheStatic(path.join(nodeModulesDir, "katex/dist/contrib/auto-render.min.js")));
|
||||
// expose the whole dist folder
|
||||
app.use(`/node_modules/katex/dist/`, express.static(path.join(nodeModulesDir, "katex/dist/")));
|
||||
app.use(`/${assetPath}/node_modules/katex/dist/`, persistentCacheStatic(path.join(nodeModulesDir, "katex/dist/")));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/boxicons/css/`, persistentCacheStatic(path.join(nodeModulesDir, "boxicons/css/")));
|
||||
app.use(`/${assetPath}/node_modules/boxicons/fonts/`, persistentCacheStatic(path.join(nodeModulesDir, "boxicons/fonts/")));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/jquery/dist/`, persistentCacheStatic(path.join(nodeModulesDir, "jquery/dist/")));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/jquery-hotkeys/`, persistentCacheStatic(path.join(nodeModulesDir, "jquery-hotkeys/")));
|
||||
|
||||
// Deprecated, https://www.npmjs.com/package/autocomplete.js?activeTab=readme
|
||||
app.use(`/${assetPath}/node_modules/autocomplete.js/dist/`, persistentCacheStatic(path.join(nodeModulesDir, "autocomplete.js/dist/")));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/normalize.css/`, persistentCacheStatic(path.join(nodeModulesDir, "normalize.css/")));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/jquery.fancytree/dist/`, persistentCacheStatic(path.join(nodeModulesDir, "jquery.fancytree/dist/")));
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@ -14,15 +14,12 @@ describe("Login Route test", () => {
|
||||
|
||||
it("should return the login page, when using a GET request", async () => {
|
||||
|
||||
// RegExp for login page specific string in HTML: e.g. "assets/v0.92.7/app/login.css"
|
||||
const loginCssRegexp = /assets\/v[0-9.a-z]+\/app\/login\.css/;
|
||||
|
||||
// RegExp for login page specific string in HTML
|
||||
const res = await supertest(app)
|
||||
.get("/login")
|
||||
.expect(200)
|
||||
|
||||
|
||||
expect(loginCssRegexp.test(res.text)).toBe(true);
|
||||
expect(res.text).toMatch(/assets\/v[0-9.a-z]+\/src\/login\.js/);
|
||||
|
||||
});
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
import assetPath from "./asset_path.js";
|
||||
import { isDev } from "./utils.js";
|
||||
|
||||
export default isDev ? assetPath + "/app" : assetPath + "/app-dist";
|
||||
export default assetPath + "/src";
|
||||
|
@ -1,3 +1,7 @@
|
||||
import packageJson from "../../package.json" with { type: "json" };
|
||||
import { isDev } from "./utils";
|
||||
|
||||
export default `assets/v${packageJson.version}`;
|
||||
export const assetUrlFragment = `assets/v${packageJson.version}`;
|
||||
const assetPath = isDev ? `http://localhost:4200/${assetUrlFragment}` : assetUrlFragment;
|
||||
|
||||
export default assetPath;
|
||||
|
@ -14,7 +14,7 @@ import log from "../services/log.js";
|
||||
import type SNote from "./shaca/entities/snote.js";
|
||||
import type SBranch from "./shaca/entities/sbranch.js";
|
||||
import type SAttachment from "./shaca/entities/sattachment.js";
|
||||
import utils, { safeExtractMessageAndStackFromError } from "../services/utils.js";
|
||||
import utils, { isDev, safeExtractMessageAndStackFromError } from "../services/utils.js";
|
||||
import options from "../services/options.js";
|
||||
|
||||
function getSharedSubTreeRoot(note: SNote): { note?: SNote; branch?: SBranch } {
|
||||
@ -159,7 +159,16 @@ function register(router: Router) {
|
||||
const { header, content, isEmpty } = contentRenderer.getContent(note);
|
||||
const subRoot = getSharedSubTreeRoot(note);
|
||||
const showLoginInShareTheme = options.getOption("showLoginInShareTheme");
|
||||
const opts = { note, header, content, isEmpty, subRoot, assetPath, appPath, showLoginInShareTheme };
|
||||
const opts = {
|
||||
note,
|
||||
header,
|
||||
content,
|
||||
isEmpty,
|
||||
subRoot,
|
||||
assetPath: isDev ? assetPath : `../${assetPath}`,
|
||||
appPath: isDev ? appPath : `../${appPath}`,
|
||||
showLoginInShareTheme
|
||||
};
|
||||
let useDefaultView = true;
|
||||
|
||||
// Check if the user has their own template
|
||||
|
@ -13,16 +13,6 @@ function buildFilesToCopy() {
|
||||
});
|
||||
|
||||
const nodePaths = [
|
||||
"@excalidraw/excalidraw/dist/prod/fonts/",
|
||||
"katex/dist",
|
||||
"boxicons/css",
|
||||
"boxicons/fonts",
|
||||
"jquery/dist",
|
||||
"jquery-hotkeys",
|
||||
"autocomplete.js/dist",
|
||||
"normalize.css/normalize.css",
|
||||
"jquery.fancytree/dist",
|
||||
|
||||
// Required as they are native dependencies and cannot be well bundled.
|
||||
"better-sqlite3",
|
||||
"bindings",
|
||||
|
@ -55,6 +55,7 @@
|
||||
"eslint": "^9.8.0",
|
||||
"eslint-config-prettier": "^10.0.0",
|
||||
"eslint-plugin-playwright": "^2.0.0",
|
||||
"happy-dom": "~9.20.3",
|
||||
"jiti": "2.4.2",
|
||||
"jsdom": "~26.1.0",
|
||||
"jsonc-eslint-parser": "^2.1.0",
|
||||
|
756
pnpm-lock.yaml
generated
756
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user