Files
mathew/frontend/nuxt.config.ts
Aran Roig e2c2c66d7f
Some checks failed
Build and Deploy Lean / build (push) Failing after 16m44s
Build and Deploy Nuxt / build (push) Failing after 48s
Vibecoded CI/CD
2026-10-06 00:23:17 +02:00

130 lines
6.2 KiB
TypeScript

// https://nuxt.com/docs/api/configuration/nuxt-config
/* The desktop build — the same wiki in an app window (Tauri, see src-tauri/).
A window has no Nuxt server and no nginx behind it, so the wiki is written
out as plain files for the system webview to read off disk and every address
it calls has to be absolute. `desktop/build.mjs` sets the flag; the Tauri CLI
carries TAURI_ENV_* into its own build hooks, so `tauri build` reaches this
branch without anyone remembering to export anything. The web build takes
none of it: same config file, different shape of output. */
const desktop = process.env.MATHEW_DESKTOP === '1' || !!process.env.TAURI_ENV_PLATFORM
/* Where a desktop build takes its wiki from. Baked in at build — the app has
no origin of its own to route `/api` through — and overridable for anyone
building against another wiki: NUXT_PUBLIC_API_BASE (a staging wiki, this
machine), and NUXT_PUBLIC_LEAN_URL for a Lean server the app can actually
reach. Lean's default stays empty on purpose: a window on a random laptop
has no localhost:8080 to find, and /lean says so plainly rather than
reaching for a server that is not there. */
const apiDefault = desktop ? 'https://mathew.aranroig.com' : 'http://localhost:5000'
const leanDefault = desktop ? '' : 'http://localhost:8080'
export default defineNuxtConfig({
compatibilityDate: '2025-07-15',
devtools: { enabled: true },
modules: ['@nuxtjs/i18n'],
css: ['katex/dist/katex.min.css', '~/assets/css/main.scss'],
/* The interface language (app -> t('...'), catalogues in i18n/locales/).
It is a preference, never part of the address — /wiki/<lang>/<slug>
speaks of the *article's* language, so the UI stays unprefixed.
On a first load the saved choice comes from the `mathew-locale` cookie
(which the server can read, so pages render in the right language before
any script runs), then the browser's own. A signed-in account's stored
choice is applied over these at startup — see app/plugins/auth.ts. */
i18n: {
strategy: 'no_prefix',
defaultLocale: 'en',
locales: [
{ code: 'en', language: 'en-US', name: 'English', file: 'en.json' },
{ code: 'es', language: 'es-ES', name: 'Español', file: 'es.json' },
{ code: 'ca', language: 'ca-ES', name: 'Català', file: 'ca.json' },
{ code: 'fr', language: 'fr-FR', name: 'Français', file: 'fr.json' },
{ code: 'de', language: 'de-DE', name: 'Deutsch', file: 'de.json' },
],
// The catalogues are small; bundling them keeps locale switches instant
lazy: false,
// Messages carry their own markup (<code> in the API banner, the hero
// gradient, demo words in the cheatsheet), rendered with v-html
compilation: { strictMessage: false },
detectBrowserLanguage: {
useCookie: true,
cookieKey: 'mathew-locale',
fallbackLocale: 'en',
},
},
/* A page of the web is drawn on the server; a window on the machine cannot
be — the webview draws these same pages itself, from the bundle. The book,
the middleware and the popups all run client-side either way, so nothing
but where HTML first comes from changes. */
ssr: !desktop,
runtimeConfig: {
public: {
// Where the UI calls the API. The Docker image sets this to "" so the
// browser calls /api on its own origin and nginx routes it to the
// backend; dev keeps the absolute localhost address, and the desktop
// build the public wiki it ships pointed at.
apiBase: process.env.NUXT_PUBLIC_API_BASE ?? apiDefault,
// Where the Lean editor server (lean4web — see lean/) lives: /lean
// frames this address. It is the browser's own way in, not the
// server's — the iframe talks to its own origin from there on.
leanUrl: process.env.NUXT_PUBLIC_LEAN_URL ?? leanDefault,
},
},
/* The desktop bundle: files under dist-desktop/ and nothing to run. Written
there rather than into .output/ so a desktop build never overwrites the
server bundle a web build left, and `frontendDist` in tauri.conf.json has
a directory of its own to read. */
...(desktop
? { nitro: { preset: 'static', output: { dir: 'dist-desktop' } } }
: {}),
// The Nuxt server's own API calls (SSR) are relative once apiBase is "",
// and land on this Nitro route, which forwards them to the backend. The
// Docker image bakes NUXT_API_PROXY_TARGET=https://mathew.aranroig.com in
// at build; nginx routes that address on to the backend. A desktop build has
// no Nuxt server to answer this, and no reason for one: the app calls the
// API by its own absolute address.
routeRules: desktop
? {}
: { '/api/**': { proxy: `${process.env.NUXT_API_PROXY_TARGET || 'http://localhost:5000'}/api/**` } },
app: {
head: {
meta: [
{
name: 'description',
content: 'A modern, collaborative wiki for mathematical concepts — written in Markdown, rendered with LaTeX.',
},
{ name: 'theme-color', media: '(prefers-color-scheme: light)', content: '#f7f8fb' },
{ name: 'theme-color', media: '(prefers-color-scheme: dark)', content: '#0a0c12' },
],
script: desktop
? [
/* The same pre-paint, from a file: a window is a host one may
sensibly hold to a `script-src 'self'` Content Security Policy,
and code written into the HTML would not survive one.
public/preboot.js carries this exact code — keep the pair in
step. (src-tauri/ sets no policy yet; keeping this one in a
file is what makes turning it on a config line, not a page
rewrite.) */
{ tagPosition: 'head', src: '/preboot.js' },
]
: [
{
// Apply saved theme & accent before first paint to avoid a flash
tagPosition: 'head',
innerHTML:
"(function(){try{var d=document.documentElement;var s=localStorage.getItem('mathew-theme');var t=s||(window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches?'dark':'light');d.setAttribute('data-theme',t);var a=localStorage.getItem('mathew-accent');if(a&&a!=='violet')d.setAttribute('data-accent',a);}catch(e){}})();",
},
],
},
},
})