mirror of
https://github.com/TriliumNext/Trilium.git
synced 2026-10-11 22:49:56 +00:00
The share theme had a build of its own (esbuild, `packages/share-theme/scripts/build.ts`) whose
`dist/` the server, desktop, edit-docs, build-docs and standalone builds copied. It could share
nothing with the app: the previous commit had to load the client's mermaid through a dedicated
`share_mermaid` entry and a manifest to avoid shipping it twice. Any further library the share
pages want from the app (FullCalendar for collections) would need the same machinery.
`shareTheme()` in `apps/client/vite-plugins.mts` now builds the theme as part of the app, in both
the client and the standalone build:
- `scripts.js` is emitted as a chunk of the app's build, into `src/` beside the app's chunks, so
the two share what both import. Mermaid is a plain `import("mermaid")` again; the
`share_mermaid` entry, its manifest and the `/share/assets/client/` route are gone.
- `scripts.css` comes from a build of its own. In the app's build, the stylesheets the theme
shares with the app (tabs, multicolumn, collapsible blocks, to-do lists) land in shared chunks,
which put them before `ck-content.css` and changed the cascade. Built alone with
`cssCodeSplit: false`, the stylesheet keeps the order `index.ts` imports in: a rule-by-rule
comparison with the esbuild output shows the same rules in the same order, apart from
lightningcss rewrites and six heading rules it drops as overridden.
- `tree.js` also builds alone, so it stays one file: the first paint waits for it, and the app's
build would move what it shares with `scripts.js` into a chunk.
- Both separate builds target `chrome96`, as the esbuild build did, so `scripts.css` keeps
`max-width` media queries rather than range syntax. `scripts.js` and its chunks use the
client's `esnext`, as the shared mermaid already did.
- `src/share_theme.json` lists the files a page can load and, apart, the files only mermaid
loads (130 files, 5 MB). The static export copies the first set always and the second only
for a subtree with a diagram (`getShareThemeExportFiles()`). The stylesheets of the chunks
`scripts.js` imports statically are in `scripts.css`, so they are listed only when a chunk
loaded on demand imports them, since Vite's preload helper requests them then.
Serving:
- The server maps `/share/assets/` to the client build's `src/`. In development, the client's Vite
middleware answers `scripts.js` and `tree.js` from source and `scripts.css` empty, since Vite
injects the styles from the modules; a script or style change no longer needs
`pnpm --filter share-theme dev`.
- A static host cannot map `/share/assets/` to `src/`, so the standalone build also writes the
three files to `share/assets/`, `scripts.js` and `scripts.css` as one-line stubs importing their
namesakes in `src/`.
- A share-theme export needs the client build: a development server without one now fails with
a message instead of exporting without mermaid, and standalone's development server, which
builds no share theme, says it needs a production build.
The eager load of a page is 19 KB of JavaScript (14 KB before), as the shared chunks bring
Vite's preload helper; the stylesheet is 94 KB (91 KB).
The share theme's own scripts, `esbuild` and `sass` go, along with `share-theme` in `prepare`,
the `triggerBuildAndCopyTo` calls and their `script` parameter, and the copy of `dist/` in the
Nix build-docs package.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
177 lines
6.1 KiB
TypeScript
177 lines
6.1 KiB
TypeScript
/// <reference types='vitest' />
|
|
import { codecovVitePlugin } from '@codecov/vite-plugin';
|
|
import prefresh from '@prefresh/vite';
|
|
import { join } from 'path';
|
|
import { defineConfig } from 'vite';
|
|
import { viteStaticCopy } from 'vite-plugin-static-copy'
|
|
|
|
import { shareTheme, stripUniverEmojiData, stripUniverHyphenation } from './vite-plugins.mjs';
|
|
|
|
const assets = [ "assets", "stylesheets", "fonts", "translations" ];
|
|
|
|
const isDev = process.env.NODE_ENV === "development";
|
|
let plugins: any = [];
|
|
|
|
if (isDev) {
|
|
plugins = [
|
|
// Prefresh keeps a growing list of vnodes per component type and scans it on every diff, so
|
|
// a view with thousands of instances of one component slows to a stop. Set TRILIUM_NO_HMR to
|
|
// work on such a view; components then reload with the page instead of in place.
|
|
...(process.env.TRILIUM_NO_HMR ? [] : [ prefresh() ]),
|
|
stripUniverHyphenation(),
|
|
stripUniverEmojiData(),
|
|
...shareTheme()
|
|
];
|
|
} else {
|
|
plugins = [
|
|
stripUniverHyphenation(),
|
|
stripUniverEmojiData(),
|
|
...shareTheme(),
|
|
viteStaticCopy({
|
|
targets: assets.map((asset) => ({
|
|
src: `src/${asset}/**/*`,
|
|
dest: asset,
|
|
rename: { stripBase: 2 }
|
|
}))
|
|
}),
|
|
viteStaticCopy({
|
|
targets: [
|
|
{
|
|
src: "../../node_modules/@excalidraw/excalidraw/dist/prod/fonts/**/*",
|
|
dest: "",
|
|
}
|
|
]
|
|
}),
|
|
// Put the Codecov vite plugin after all other plugins
|
|
codecovVitePlugin({
|
|
enableBundleAnalysis: process.env.CODECOV_TOKEN !== undefined,
|
|
bundleName: "client",
|
|
uploadToken: process.env.CODECOV_TOKEN
|
|
})
|
|
]
|
|
}
|
|
|
|
export default defineConfig(() => ({
|
|
root: import.meta.dirname,
|
|
cacheDir: '../../.cache/vite',
|
|
base: "",
|
|
plugins,
|
|
// Use oxc for JSX transformation (Vite 8+ replaced the deprecated `esbuild` option with `oxc`)
|
|
oxc: {
|
|
jsx: {
|
|
runtime: 'automatic',
|
|
importSource: 'preact',
|
|
development: isDev
|
|
}
|
|
},
|
|
css: {
|
|
transformer: 'lightningcss',
|
|
devSourcemap: isDev
|
|
},
|
|
server: {
|
|
watch: {
|
|
ignored: ["**/test-output/**"]
|
|
}
|
|
},
|
|
resolve: {
|
|
alias: [
|
|
{
|
|
find: "react",
|
|
replacement: "preact/compat"
|
|
},
|
|
{
|
|
find: "react-dom",
|
|
replacement: "preact/compat"
|
|
}
|
|
],
|
|
dedupe: [
|
|
"react",
|
|
"react-dom",
|
|
"preact",
|
|
"preact/compat",
|
|
"preact/hooks"
|
|
]
|
|
},
|
|
optimizeDeps: {
|
|
include: [
|
|
"ckeditor5",
|
|
"mathlive"
|
|
]
|
|
},
|
|
build: {
|
|
target: "esnext",
|
|
outDir: './dist',
|
|
emptyOutDir: true,
|
|
reportCompressedSize: true,
|
|
sourcemap: false,
|
|
rollupOptions: {
|
|
input: {
|
|
index: join(import.meta.dirname, "index.html"),
|
|
runtime: join(import.meta.dirname, "src", "runtime.ts"),
|
|
print: join(import.meta.dirname, "src", "print.tsx")
|
|
},
|
|
output: {
|
|
entryFileNames: (chunk) => {
|
|
// We enforce a hash in the main index file to avoid caching issues, this only works because we have the HTML entry point.
|
|
if (chunk.name === "index" || chunk.name === "print") {
|
|
return "src/[name]-[hash].js";
|
|
}
|
|
|
|
// For EJS-rendered pages (e.g. login) we need to have a stable name.
|
|
return "src/[name].js";
|
|
},
|
|
chunkFileNames: "src/[name]-[hash].js",
|
|
assetFileNames: "src/[name]-[hash].[ext]"
|
|
},
|
|
onwarn(warning, rollupWarn) {
|
|
if (warning.code === "MODULE_LEVEL_DIRECTIVE") {
|
|
return;
|
|
}
|
|
rollupWarn(warning);
|
|
}
|
|
}
|
|
},
|
|
test: {
|
|
environment: "happy-dom",
|
|
// Vitest skips CSS processing by default, which would hand `?inline` importers an empty
|
|
// string. The presentation themes are SCSS compiled through that path, so their specs need
|
|
// it on to assert against real rules.
|
|
css: { include: [/\.scss(\?|$)/] },
|
|
setupFiles: [
|
|
"./src/test/setup.ts"
|
|
],
|
|
server: {
|
|
deps: {
|
|
// The plugin reads `rrule` through a namespace import, which Node resolves to the
|
|
// package's CommonJS build with no named exports. Bundling it applies Vite's interop.
|
|
inline: ["@fullcalendar/rrule"]
|
|
}
|
|
},
|
|
reporters: [
|
|
"verbose",
|
|
["html", { outputFile: "./test-output/vitest/html/index.html" }],
|
|
["junit", { outputFile: "./test-output/vitest/junit.xml", addFileAttribute: true }]
|
|
],
|
|
coverage: {
|
|
reportsDirectory: "./test-output/vitest/coverage",
|
|
provider: "v8" as const,
|
|
// Codecov resolves an lcov `SF:` path by matching it against the repo's file list.
|
|
// Vitest defaults the lcov reporter's `projectRoot` to the Vite `root`, which would
|
|
// emit app-relative paths (`src/…`); the shallow ones are ambiguous in this monorepo
|
|
// and get attributed to whichever project wins the match. Anchor to the repo root so
|
|
// every path is unambiguous.
|
|
reporter: ["text", "html", ["lcov", { projectRoot: join(import.meta.dirname, "../..") }]],
|
|
include: ["src/**/*.{ts,tsx}"],
|
|
// Benchmarks are measured by `vitest bench`, which the test run never invokes, so a
|
|
// `*.bench.ts` left in scope reports as wholly uncovered source.
|
|
exclude: ["**/*.{test,spec}.{ts,mts,cts,tsx,js,jsx}", "**/*.bench.{ts,mts,cts,tsx}", "**/*.d.ts"]
|
|
},
|
|
},
|
|
commonjsOptions: {
|
|
transformMixedEsModules: true,
|
|
},
|
|
define: {
|
|
"process.env.IS_PREACT": JSON.stringify("true"),
|
|
}
|
|
}));
|