alby-hub/frontend/vite.config.ts
Roland d2cebc5c6f
fix: replace react-lottie with lottie-react for Vite 8 compatibility (#2546)
Vite 8 changed CJS default-import interop: with "type": "module" set,
a default import of a CJS dependency now resolves to the whole
module.exports object instead of its .default export. react-lottie is
CJS-only, so <Lottie> received an object as the element type and
crashed LottieLoading/LottieSuccess with "Element type is invalid".

Swap to the maintained, ESM-built lottie-react, aliasing it to its ES
build since its browser field points at a UMD build with the same
interop hazard. No other dependency is affected by the interop change.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-12 23:52:50 +07:00

130 lines
4 KiB
TypeScript

import tailwindcss from "@tailwindcss/vite";
import react from "@vitejs/plugin-react-swc";
import path from "path";
import { defineConfig, Plugin } from "vite";
import { VitePWA } from "vite-plugin-pwa";
export default defineConfig(({ command }) => ({
plugins: [
react(),
tailwindcss(),
VitePWA({
registerType: "autoUpdate",
// disable service worker - Alby Hub cannot be used offline (and also breaks oauth callback)
injectRegister: false,
includeAssets: [
"favicon.ico",
"robots.txt",
"icon-192.png",
"icon-512.png",
],
useCredentials: true, // because the manifest might sit behind authentication
manifest: {
short_name: "Alby Hub",
name: "Alby Hub",
icons: [
{
src: "icon-192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "icon-512.png",
sizes: "512x512",
type: "image/png",
},
{
src: "icon-1024.png",
sizes: "1024x1024",
type: "image/png",
},
],
start_url: ".",
display: "standalone",
theme_color: "#000000",
background_color: "#ffffff",
},
workbox: {
maximumFileSizeToCacheInBytes: 3000000, // 3MB
},
}),
...(command === "serve" ? [insertDevCSPPlugin] : [insertProdCSPPlugin]),
],
server: {
port: process.env.VITE_PORT ? parseInt(process.env.VITE_PORT) : undefined,
proxy: {
"/api": {
target: process.env.VITE_API_URL || "http://localhost:8080",
secure: false,
},
"/logout": {
target: process.env.VITE_API_URL || "http://localhost:8080",
secure: false,
},
},
},
resolve: {
tsconfigPaths: true,
alias: {
src: path.resolve(import.meta.dirname, "./src"),
wailsjs: path.resolve(import.meta.dirname, "./wailsjs"),
// used to refrence public assets when importing images or other
// assets from the public folder
// this is necessary to inject the base path during build
public: "",
// lottie-react's `browser` field points to a UMD build, which breaks
// under Vite 8's Node-style CJS interop (default import resolves to the
// whole exports object); force the ESM build instead
"lottie-react": "lottie-react/build/index.es.js",
},
},
build: {
assetsInlineLimit: 0,
},
html:
command === "serve"
? {
cspNonce: "DEVELOPMENT",
}
: undefined,
base: process.env.BASE_PATH || "/",
}));
const DEVELOPMENT_NONCE = "'nonce-DEVELOPMENT'";
// when making changes here, also update the CSP header in http_service.go
const buildCSP = (nonce?: string) =>
`default-src 'self'${nonce ? " " + nonce : ""}; img-src 'self' https://uploads.getalby-assets.com https://cdn.getalby-assets.com https://getalby.com; connect-src 'self' https://api.getalby.com https://getalby.com https://zapplanner.albylabs.com wss://relay.getalby.com wss://relay2.getalby.com; frame-src https://www.youtube-nocookie.com`;
const insertCSPMetaTag = (comment: string, csp: string) => (html: string) =>
html.replace(
"<head>",
`<head>
<!-- ${comment} -->
<meta http-equiv="Content-Security-Policy" content="${csp}" />`
);
const insertDevCSPPlugin: Plugin = {
name: "dev-csp",
transformIndexHtml: {
order: "pre",
handler: insertCSPMetaTag(
"DEV-ONLY CSP - when making changes here, also update the CSP header in http_service.go (without the nonce!)",
buildCSP(DEVELOPMENT_NONCE)
),
},
};
// the same CSP is served as a HTTP header in http mode (see http_service.go).
// The meta tag ensures the policy also applies where no HTTP headers are set,
// e.g. in the desktop app.
const insertProdCSPPlugin: Plugin = {
name: "prod-csp",
transformIndexHtml: {
order: "pre",
handler: insertCSPMetaTag(
"when making changes here, also update the CSP header in http_service.go",
buildCSP()
),
},
};