c9e22ec117
Make the marketing site deployable standalone from apps/website (the repo has no root package.json, so the build must run in this subdir — set Base Directory to apps/website in Coolify). - Add a multi-stage Dockerfile (pnpm build -> node .output/server/index.mjs, port 3000, NUXT_PUBLIC_SITE_URL default) + .dockerignore. - Add a "start" script for the Nixpacks path (Nuxt SSR has no default start). - Guard the bind-mount-only /shared-packages components dir with existsSync so standalone builds don't warn on the missing path (the site uses no shared component).
116 lines
4.6 KiB
TypeScript
116 lines
4.6 KiB
TypeScript
// Nuxt 4 configuration for the Dezky public marketing site (dezky.eu).
|
|
//
|
|
// Unlike apps/portal and apps/operator this surface is fully public — no
|
|
// OIDC, no sessions, no platform-api coupling. It can be statically
|
|
// generated (`pnpm generate`) and served from a CDN/edge independently of
|
|
// the Docker app stack. Locally it runs behind Traefik at dezky.local /
|
|
// www.dezky.local with the same mkcert TLS as the rest of the platform.
|
|
|
|
import { existsSync } from 'node:fs'
|
|
|
|
const siteUrl = process.env.NUXT_PUBLIC_SITE_URL
|
|
|| (process.env.NODE_ENV === 'production' ? 'https://dezky.eu' : 'http://localhost:3000')
|
|
|
|
export default defineNuxtConfig({
|
|
compatibilityDate: '2026-01-01',
|
|
devtools: { enabled: true },
|
|
|
|
modules: ['@nuxtjs/i18n'],
|
|
|
|
css: ['~/assets/styles/tokens.css', '~/assets/styles/base.css'],
|
|
|
|
// Auto-import from the shared packages/ui workspace in addition to the
|
|
// app's own components/. /shared-packages is bind-mounted in
|
|
// docker-compose.yml — outside containers the same files live at
|
|
// <repo>/packages/ui/components/. The local dir keeps the default
|
|
// directory-based prefix; the shared dir uses no prefix so a shared
|
|
// CountrySelect.vue is just <CountrySelect>. Mirrors portal/operator.
|
|
components: [
|
|
'~/components',
|
|
// The shared @dezky/ui dir is bind-mounted in the Docker dev stack; include
|
|
// it only when present so standalone builds (e.g. Coolify) don't warn on
|
|
// the missing absolute path. The marketing site uses no shared component.
|
|
...(existsSync('/shared-packages/ui/components')
|
|
? [{ path: '/shared-packages/ui/components', pathPrefix: false }]
|
|
: []),
|
|
],
|
|
|
|
app: {
|
|
head: {
|
|
// <html lang>/dir + hreflang alternates are managed by @nuxtjs/i18n
|
|
// (useLocaleHead in app.vue). Static favicons + theme-color live here.
|
|
link: [
|
|
{ rel: 'icon', type: 'image/svg+xml', href: '/favicon.svg' },
|
|
{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32.png' },
|
|
{ rel: 'apple-touch-icon', href: '/apple-touch-icon.png' },
|
|
{ rel: 'preconnect', href: 'https://fonts.googleapis.com' },
|
|
{ rel: 'preconnect', href: 'https://fonts.gstatic.com', crossorigin: '' },
|
|
{
|
|
rel: 'stylesheet',
|
|
href: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Inter+Tight:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600;700&display=swap',
|
|
},
|
|
],
|
|
// theme-color + favicons are static; the OG/Twitter/canonical SEO is set
|
|
// in app.vue via useSeoMeta so og:url/og:image are absolute against the
|
|
// env-aware siteUrl (runtimeConfig below) and og:url is per-route.
|
|
meta: [
|
|
{ name: 'theme-color', content: '#FAFAF7' },
|
|
],
|
|
// Umami — privacy-friendly, cookieless analytics (matches the cookie
|
|
// policy; no consent banner needed). data-domains limits tracking to the
|
|
// production hostnames so localhost/dev traffic doesn't pollute stats.
|
|
script: [
|
|
{
|
|
src: 'https://umami.coolify.lastcloud.io/script.js',
|
|
defer: true,
|
|
'data-website-id': '639dcd4c-1cb3-4edb-a2a2-6e9cf69348d4',
|
|
'data-domains': 'dezky.eu,www.dezky.eu',
|
|
},
|
|
],
|
|
},
|
|
},
|
|
|
|
// Public site URL used to build absolute canonical / OG / sitemap URLs.
|
|
// Defaults to localhost in dev (so local share-image previews work) and
|
|
// the production domain otherwise; override with NUXT_PUBLIC_SITE_URL.
|
|
runtimeConfig: {
|
|
public: {
|
|
siteUrl,
|
|
},
|
|
},
|
|
|
|
// Bilingual: English is the default (no prefix); Danish lives under /da.
|
|
// Both are server-rendered and indexed with hreflang alternates. First-time
|
|
// visitors are auto-detected (cookie-remembered) on the root path only.
|
|
i18n: {
|
|
defaultLocale: 'en',
|
|
strategy: 'prefix_except_default',
|
|
baseUrl: siteUrl,
|
|
locales: [
|
|
{ code: 'en', language: 'en', name: 'English' },
|
|
{ code: 'da', language: 'da-DK', name: 'Dansk' },
|
|
],
|
|
detectBrowserLanguage: {
|
|
useCookie: true,
|
|
cookieKey: 'i18n_redirected',
|
|
redirectOn: 'root',
|
|
fallbackLocale: 'en',
|
|
alwaysRedirect: false,
|
|
},
|
|
},
|
|
|
|
vite: {
|
|
server: {
|
|
// Vite 7 added a strict host check; allow the Traefik-fronted hostnames
|
|
// this site is served on in dev.
|
|
allowedHosts: ['dezky.local', 'www.dezky.local'],
|
|
// HMR/DevTools websocket. Default (localhost:3000 dev) lets Vite infer
|
|
// ws on the page host/port. When served behind Traefik TLS at
|
|
// dezky.local, set DEZKY_TRAEFIK=1 so the client connects via wss:443.
|
|
hmr: process.env.DEZKY_TRAEFIK === '1'
|
|
? { protocol: 'wss', clientPort: 443 }
|
|
: undefined,
|
|
},
|
|
},
|
|
})
|