pwaLUPMIS2/vite.config.js
ekke 4952c92e42 Reconnect the app to the API, and fix the session that was never injected
Four changes that together get a signed-in officer back to working data.

The SSO validation in index.php and embed.php called the public hostname from
inside the server. The Lands Commission's NAT rule blocks traffic that leaves
the server and tries to come back in, so that curl stalled for its full
30-second timeout and then failed validation, bouncing the user back to the
login. Both now call http://l4lmainbackend/sso/validate, overridable with
LUPMIS_SSO_BASE. Measured from inside the spdrawing container: 25 ms with no
redirect, against a 10-second timeout on the public name.

API_ROOT is now the relative path /api. The PWA host already proxies it to the
ApiEngine container — a deliberate route, not a catch-all: /api answers on pwa.
and api. but not on permits., minio. or minioapi. Same-origin removes the
mixed-content, CORS and CORP constraints that Cross-Origin-Embedder-Policy:
require-corp imposes on a cross-origin call, and no API hostname is compiled
into the bundle any more. The dev server proxies /api to the public host, which
is right there because a developer's machine is outside the server and only
callers inside it are blocked from the public name.

A direct request for /index.html bypassed index.php, which is what injects
window.LUPMIS_SESSION, so the app started with no session at all and said so in
the menu. The LUSPA landing page links to exactly that URL, and the SPA
fallback could not help because its RewriteCond !-f fails precisely when the
file exists. .htaccess now routes it through index.php; index.php reads
index.html from the filesystem, so there is no loop. This one is inert until
AllowOverride is relaxed on the PWA container, where it is currently None.

Service worker v29, and v28 before it, which carries the GIS Tools rename to
devices that already have the app installed. The tile cache stays pinned at
v24, so downloaded map areas survive both updates.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-20 15:11:01 +02:00

107 lines
4.3 KiB
JavaScript

/**
* Vite Configuration
*
* Configures:
* - Cross-origin isolation headers (required for OPFS/SQLite)
* - Worker bundling
*/
import { defineConfig } from 'vite';
export default defineConfig({
// Development server configuration
server: {
headers: {
// Required for OPFS (Origin Private File System) access
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
// In production the PWA host proxies /api to the ApiEngine container, so
// the app calls the API with a relative path. The dev server is not behind
// that proxy, so it forwards /api to the public host — which is correct
// here because a developer's machine is outside the server, and only
// callers inside it are blocked from using the public name.
proxy: {
'/api': {
target: 'https://api.lupmis4luspa.org',
changeOrigin: true,
secure: true,
},
},
},
// Preview server (npm run preview) configuration
preview: {
headers: {
'Cross-Origin-Opener-Policy': 'same-origin',
'Cross-Origin-Embedder-Policy': 'require-corp',
},
},
// Build configuration
build: {
// Generate source maps for debugging
sourcemap: true,
// Target modern browsers that support OPFS
target: 'esnext',
// Raise the chunk-size warning threshold.
// Rationale: the two largest chunks are unavoidable —
// • openlayers (~535 kB / ~152 kB gzipped) — the OL library itself,
// used app-wide; further splitting just creates more HTTP round-trips
// • sqlite3.wasm (~856 kB) — a runtime WASM binary, not a JS chunk;
// code-splitting does not apply
// 900 kB silences the noise without hiding genuine regressions.
chunkSizeWarningLimit: 900,
rollupOptions: {
output: {
manualChunks(id) {
// pako (zlib) is pulled in by BOTH geotiff and jspdf (via fast-png).
// Without its own chunk, Rollup assigns it to one of them and the two
// chunks reference each other ("Circular chunk: jspdf -> geotiff").
if (id.includes('node_modules/pako/')) return 'pako';
// Vite's preload helper (the `__vitePreload` used by every dynamic
// import()) is a virtual module with no node_modules path, so Rollup
// is free to park it in whichever chunk it likes — it used to land in
// the geotiff chunk. The entry needs the helper at startup, so that
// made the browser preload all ~257 kB of geotiff.js on every visit,
// defeating the lazy rule below. Give the helper a chunk of its own
// (~1 kB) so the entry pulls in only that.
if (id.includes('vite/preload-helper')) return 'vite-helpers';
// Turf.js — only needed when the Analysis panel is opened, which
// main.js imports dynamically. Keep it out of the eager bundle.
if (id.includes('node_modules/@turf/')) return 'turf';
// geotiff.js + the OL modules that use it — only needed when the user
// opens a Cloud-Optimized GeoTIFF layer, which MapView.addCOGLayer()
// imports dynamically. Must be tested BEFORE the generic ol/ rule so
// it isn't swallowed into the eagerly-loaded openlayers chunk.
if (id.includes('node_modules/geotiff/') ||
id.includes('node_modules/ol/source/GeoTIFF') ||
id.includes('node_modules/ol/layer/WebGLTile')) return 'geotiff';
if (id.includes('node_modules/ol/')) return 'openlayers';
if (id.includes('node_modules/ol-ext/')) return 'ol-ext';
if (id.includes('node_modules/bootstrap/')) return 'bootstrap';
// shpjs — dynamically imported at runtime (main.js), so this chunk is
// only fetched when the user imports a shapefile. Writing shapefiles
// needs no dependency at all (src/shapefile-write.js), and shpjs 6
// unzips with but-unzip, so nothing here reaches JSZip any more.
if (id.includes('node_modules/shpjs/')) return 'shpjs';
if (id.includes('node_modules/jspdf')) return 'jspdf';
},
},
},
},
// Worker configuration
worker: {
format: 'es',
},
// Dependency optimization
optimizeDeps: {
exclude: ['sqlocal'],
},
});