mirror of
https://github.com/oxynote/oxynote.git
synced 2026-10-17 10:59:20 +02:00
250 lines
6.8 KiB
TypeScript
250 lines
6.8 KiB
TypeScript
import tailwindcss from "@tailwindcss/vite"
|
|
import { blockIconList } from "./app/utils/block-icon"
|
|
import { selectableIconList } from "./app/utils/icon"
|
|
|
|
// DESKTOP_BUILD selects how `__DESKTOP_BUILD__` is materialized in the bundle:
|
|
// - "1" : pure desktop build (production renderer). __DESKTOP_BUILD__ is
|
|
// the literal `true` and web branches DCE away.
|
|
// - "hybrid" : dev-only, used by `start:dev:desktop`. One Nuxt dev server is
|
|
// hit by both the electron renderer and the system browser
|
|
// opened for OAuth. Both branches stay in the bundle and
|
|
// __DESKTOP_BUILD__ becomes a runtime probe for the preload
|
|
// bridges so each context picks the right path.
|
|
// - "0" : pure web build. __DESKTOP_BUILD__ is the literal `false`.
|
|
// - unset : same as "0".
|
|
const desktopBuildMode = (process.env.DESKTOP_BUILD ?? "0") as
|
|
"0" | "1" | "hybrid"
|
|
const isDesktopBuild = desktopBuildMode === "1" || desktopBuildMode === "hybrid"
|
|
const isHybridDesktopBuild = desktopBuildMode === "hybrid"
|
|
|
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: "2025-07-15",
|
|
ssr: !isDesktopBuild,
|
|
|
|
vite: {
|
|
define: {
|
|
// In pure builds Vite substitutes a literal boolean so unused
|
|
// branches DCE away. In hybrid mode the substituted text is a
|
|
// runtime probe of `window.__isElectron` (set by the preload), so
|
|
// the electron renderer and the system browser served by the same
|
|
// dev server each take the right branch from the same bundle.
|
|
__DESKTOP_BUILD__: isHybridDesktopBuild
|
|
? `(typeof window !== "undefined" && window.__isElectron === true)`
|
|
: JSON.stringify(isDesktopBuild),
|
|
},
|
|
plugins: [tailwindcss()],
|
|
optimizeDeps: {
|
|
include: [
|
|
"@better-auth/electron/proxy",
|
|
"@pinia/colada-plugin-auto-refetch",
|
|
"@tiptap/core",
|
|
"@tiptap/extension-file-handler",
|
|
"@tiptap/extension-list",
|
|
"@tiptap/vue-3",
|
|
"better-auth/client/plugins",
|
|
"better-auth/vue",
|
|
"class-variance-authority",
|
|
"clsx",
|
|
"fast-deep-equal",
|
|
"nanoid",
|
|
"reka-ui",
|
|
"safe-stable-stringify",
|
|
"slugify",
|
|
"tailwind-merge",
|
|
"vue-sonner",
|
|
],
|
|
},
|
|
},
|
|
|
|
nitro: {
|
|
// https://content.nuxt.com/docs/deploy/cloudflare-pages
|
|
// NITRO_PRESET only applies to web builds — e.g. `node-server` for the
|
|
// self-hosted docker image. Desktop builds are always static.
|
|
preset: isDesktopBuild
|
|
? "static"
|
|
: (process.env.NITRO_PRESET ?? "cloudflare_pages"),
|
|
// NITRO_MINIFY=true terser-minifies the server bundle; the
|
|
// production docker image sets it to halve the shipped output.
|
|
// Unset keeps each preset's own default.
|
|
minify: process.env.NITRO_MINIFY === "true" ? true : undefined,
|
|
},
|
|
|
|
modules: [
|
|
"@nuxt/eslint",
|
|
"@nuxt/fonts",
|
|
"@nuxt/icon",
|
|
"shadcn-nuxt",
|
|
"@vueuse/nuxt",
|
|
"@nuxtjs/i18n",
|
|
"@pinia/nuxt",
|
|
"@pinia/colada-nuxt",
|
|
"@sentry/nuxt/module",
|
|
],
|
|
|
|
css: [
|
|
"~/assets/css/main.css",
|
|
"vue-sonner/style.css",
|
|
"vue-virtual-scroller/dist/vue-virtual-scroller.css",
|
|
],
|
|
|
|
devtools: { enabled: false },
|
|
|
|
eslint: {
|
|
config: {
|
|
typescript: {
|
|
tsconfigPath: "tsconfig.json",
|
|
},
|
|
},
|
|
},
|
|
|
|
typescript: {
|
|
typeCheck: true,
|
|
tsConfig: {
|
|
compilerOptions: {
|
|
sourceMap: true,
|
|
removeComments: true,
|
|
noUnusedLocals: true,
|
|
noUnusedParameters: true,
|
|
noFallthroughCasesInSwitch: true,
|
|
noImplicitAny: true,
|
|
forceConsistentCasingInFileNames: true,
|
|
noUncheckedIndexedAccess: true,
|
|
noImplicitOverride: true,
|
|
verbatimModuleSyntax: true,
|
|
allowUnreachableCode: false,
|
|
},
|
|
},
|
|
},
|
|
|
|
runtimeConfig: {
|
|
// server-only SSR overrides. When the app runs inside a container, the
|
|
// public localhost URLs are unreachable from the server side — these
|
|
// point SSR fetches at the backend services directly and fall back to
|
|
// the public URLs when unset.
|
|
coreAPIInternalHttpURL: "",
|
|
authRealtimeAPIInternalHttpURL: "",
|
|
public: {
|
|
sentryDSN: "",
|
|
appBaseURL: "",
|
|
linkToMoreInfoAboutProduct: "",
|
|
authRealtimeAPIBaseHttpURL: "",
|
|
authRealtimeAPIBaseWsURL: "",
|
|
coreAPIBaseHttpURL: "",
|
|
coreAPIBaseWsURL: "",
|
|
termsOfServiceURL: "",
|
|
privacyPolicyURL: "",
|
|
docsURL: "",
|
|
postgresqlReadOnlyUserSetupGuideURL: "",
|
|
mysqlReadOnlyUserSetupGuideURL: "",
|
|
mariadbReadOnlyUserSetupGuideURL: "",
|
|
prometheusQueryGuideURL: "",
|
|
postgresqlQueryGuideURL: "",
|
|
mysqlQueryGuideURL: "",
|
|
mariadbQueryGuideURL: "",
|
|
},
|
|
},
|
|
|
|
app: {
|
|
head: {
|
|
title: "Oxynote", // default title (can be overridden in pages/components)
|
|
meta: [{ name: "apple-mobile-web-app-title", content: "Oxynote" }],
|
|
link: [
|
|
{
|
|
rel: "icon",
|
|
type: "image/png",
|
|
href: "/favicon-96x96.png",
|
|
sizes: "96x96",
|
|
},
|
|
{ rel: "icon", type: "image/svg+xml", href: "/favicon.svg" },
|
|
{ rel: "shortcut icon", href: "/favicon.ico" },
|
|
{
|
|
rel: "apple-touch-icon",
|
|
sizes: "180x180",
|
|
href: "/apple-touch-icon.png",
|
|
},
|
|
{ rel: "manifest", href: "/site.webmanifest" },
|
|
],
|
|
},
|
|
},
|
|
|
|
fonts: {
|
|
defaults: {
|
|
weights: [400, 500, 600, 700],
|
|
},
|
|
},
|
|
|
|
icon: {
|
|
mode: "css",
|
|
cssLayer: "base",
|
|
clientBundle: {
|
|
// the document title icons are a fifth of the startup download,
|
|
// so the web build leaves them out and the server resolves each
|
|
// one on first use: inlined for SSR, fetched in batches after
|
|
// client-side navigation. The desktop build has no server to ask
|
|
// and loads from disk, so it bundles them and stays offline-safe
|
|
icons: [
|
|
// the block icons are named in a .ts file, which the scan
|
|
// below does not read
|
|
...blockIconList(),
|
|
...(isDesktopBuild ? selectableIconList() : []),
|
|
],
|
|
scan: true,
|
|
sizeLimitKb: 256,
|
|
},
|
|
customCollections: [
|
|
{
|
|
prefix: "custom-icons",
|
|
dir: "./app/assets/custom-icons",
|
|
},
|
|
],
|
|
},
|
|
|
|
i18n: {
|
|
defaultLocale: "en",
|
|
strategy: "no_prefix",
|
|
locales: [
|
|
{
|
|
code: "en",
|
|
language: "en-US",
|
|
// all files are combined in one big i18n file, so all of them
|
|
// need to have a root namespace object, like: "sidebar: {...}"
|
|
files: [
|
|
"en/general.json",
|
|
"en/sidebar.json",
|
|
"en/editor.json",
|
|
"en/onboarding.json",
|
|
"en/settings.json",
|
|
"en/shortcuts.json",
|
|
"en/notification.json",
|
|
"en/apps.json",
|
|
"en/oauth.json",
|
|
],
|
|
},
|
|
],
|
|
},
|
|
|
|
shadcn: {
|
|
prefix: "ShadcnUi",
|
|
// https://github.com/unovue/shadcn-vue/issues/763#issuecomment-2349290087
|
|
componentDir: "./app/components/shadcn/ui",
|
|
},
|
|
|
|
sentry: {
|
|
org: "oxynote",
|
|
project: "bifrost",
|
|
authToken: process.env.SENTRY_AUTH_TOKEN,
|
|
telemetry: false,
|
|
},
|
|
|
|
// hidden sourcemaps exist only for the Sentry upload. Skip generating
|
|
// them when no auth token is present (e.g. self-hosted docker builds) —
|
|
// they roughly double the build's memory footprint.
|
|
sourcemap: process.env.SENTRY_AUTH_TOKEN
|
|
? {
|
|
client: "hidden",
|
|
server: "hidden",
|
|
}
|
|
: false,
|
|
})
|