Files
bincio-activity/site/astro.config.mjs
T
Davide Scaini 59cf99f0af Fix stuck segments tab; add /segments/ dev fallback
AthleteView: use segmentsFetched flag to prevent infinite fetch loop when
there are no efforts (segmentSummary.length === 0 was re-triggering the
reactive statement after every empty response). Also improve empty state
message and reset flag after rescan so the table reloads.

astro.config.mjs: extend shell fallback plugin to cover /segments/{id}/
the same way /activity/{id}/ is handled, so segment detail pages work in
the dev server without nginx.
2026-05-13 08:35:00 +02:00

84 lines
3.1 KiB
JavaScript

import { defineConfig } from "astro/config";
import { loadEnv } from "vite";
import svelte from "@astrojs/svelte";
import tailwind from "@astrojs/tailwind";
const env = loadEnv(process.env.NODE_ENV ?? 'development', process.cwd(), '');
// PUBLIC_EDIT_URL: non-empty → bincio edit URL; empty → proxy to bincio serve.
// VITE_API_PORT lets `bincio dev` override the serve port without touching .env.
const apiPort = process.env.VITE_API_PORT || '4041';
const serveTarget = env.PUBLIC_EDIT_URL || `http://localhost:${apiPort}`;
// In production, nginx serves the shell for dynamic sub-paths via try_files.
// In dev (Astro dev server), no nginx — this plugin replicates those rules.
const shellFallbackPlugin = {
name: 'shell-fallback',
configureServer(server) {
server.middlewares.use((req, _res, next) => {
if (req.url && /^\/activity\/[^/]+\/?(\?|$)/.test(req.url)) {
req.url = '/activity/';
}
// /segments/{id}/ → /segments/ (but not /segments/new/ which has its own page)
const segMatch = req.url?.match(/^\/segments\/([^/?]+)\//);
if (segMatch && segMatch[1] !== 'new') {
req.url = '/segments/';
}
next();
});
},
};
export default defineConfig({
integrations: [svelte(), tailwind()],
devToolbar: { enabled: false },
output: "static",
// When hosting at a subdirectory (e.g. GitHub Pages project site), set:
// base: "/repo-name",
vite: {
plugins: [shellFallbackPlugin],
optimizeDeps: {
include: ['maplibre-gl'],
esbuildOptions: { target: 'es2022' },
},
build: { target: 'es2022' },
// Proxy /api/* to bincio serve/edit so cookies work same-origin in dev.
// In production nginx handles this — same pattern, no code change needed.
server: {
watch: {
// public/data is a symlink to the live data dir; Chokidar follows it and
// opens a handle per file, which causes EMFILE during bulk uploads as
// activity count grows. Data files don't need HMR — exclude them.
ignored: ['**/public/data/**'],
},
proxy: {
// Both /api/upload and /api/upload/strava-zip return SSE streams in response
// to POST requests. Vite's default proxy buffers the full body before forwarding,
// which breaks streaming and causes EPIPE on long uploads.
// selfHandleResponse + manual pipe sends chunks as they arrive.
'/api/upload': {
target: serveTarget,
changeOrigin: true,
selfHandleResponse: true,
configure: (proxy) => {
proxy.on('proxyRes', (proxyRes, req, res) => {
res.writeHead(proxyRes.statusCode ?? 200, proxyRes.headers);
proxyRes.pipe(res, { end: true });
});
proxy.on('error', (err, _req, res) => {
if (err.code === 'EPIPE' || err.code === 'ECONNRESET') return;
if (!res.headersSent) {
res.writeHead(502);
res.end('proxy error');
}
});
},
},
'/api': {
target: serveTarget,
changeOrigin: true,
},
},
},
},
});