Build: stop the lazy geotiff and shapefile chunks loading at startup

vite.config.js splits geotiff and shpjs out so they load only when a user opens
a Cloud-Optimized GeoTIFF or imports a shapefile, but the built index.html
preloaded both on every visit — about 428 kB (152 kB gzipped) nobody had asked
for.

Two separate causes, both visible in the entry chunk's first line:
- it imported Vite's preload helper, used by every dynamic import(), from the
  geotiff chunk. The helper is a virtual module with no node_modules path, so
  Rollup had parked it there; needing it at startup dragged the whole chunk in.
  It now has a chunk of its own, about 1 kB.
- it imported JSZip from the shpjs chunk. JSZip reached the bundle through
  shp-write, which gis-export.js imports for Shapefile export, so it is needed
  at startup whatever happens; filing it under shpjs pulled that chunk in too.
  It is now its own chunk, costing the 31 kB it actually is.

dist/ rebuilt: index.html now preloads vite-helpers and jszip instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
ekke 2026-09-23 13:40:13 +02:00
parent d8b635b442
commit 8674ca4df2
26 changed files with 97 additions and 74 deletions

File diff suppressed because one or more lines are too long

11
dist/assets/analysis-modal-D9UrhqgN.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/assets/geotiff-DGVlFsHY.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
dist/assets/index-D79Zl-eh.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3
dist/assets/jszip-Dgg-11DP.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/assets/jszip-Dgg-11DP.js.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,2 +0,0 @@
import{E as f,a as b}from"./jspdf-BsOD2LDR.js";import"./pako-Xa-UToif.js";import"./geotiff-B9aROX49.js";import"./openlayers-D5-VSKzq.js";b(f);let s=null;async function x(){if(s)return s;try{const e=new Image;e.crossOrigin="anonymous",await new Promise((r,i)=>{e.onload=r,e.onerror=i,e.src="./app-icons/luspa-pdf.jpg"});const n=document.createElement("canvas");n.width=e.naturalWidth,n.height=e.naturalHeight;const t=n.getContext("2d");return t.fillStyle="#ffffff",t.fillRect(0,0,n.width,n.height),t.drawImage(e,0,0),s=n.toDataURL("image/jpeg",.92),s}catch(e){return console.warn("[PDF] Could not load logo:",e),null}}async function F({title:e,rows:n}){const t=new f({orientation:"portrait",unit:"mm",format:"a4"}),r=t.internal.pageSize.getWidth(),i=[30,26,75],g=await x(),c=28,a=14;let o=14;g&&t.addImage(g,"JPEG",a,o,c,c);const m=a+c+6;t.setFont("helvetica","bold"),t.setFontSize(18),t.setTextColor(...i),t.text("LUPMIS",m,o+11),t.setFont("helvetica","normal"),t.setFontSize(12),t.text(e,m,o+19);const d=new Date,h=d.toLocaleDateString(void 0,{year:"numeric",month:"long",day:"numeric"}),p=d.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.setFontSize(9),t.setTextColor(120,120,120),t.text(`${h} ${p}`,r-a,o+11,{align:"right"}),o+=c+6,t.setDrawColor(...i),t.setLineWidth(.5),t.line(a,o,r-a,o),o+=6;const y=n.map(l=>[l.label,l.value]);t.autoTable({startY:o,head:[["Property","Value"]],body:y,margin:{left:a,right:a},styles:{font:"helvetica",fontSize:10,cellPadding:4},headStyles:{fillColor:i,textColor:[255,255,255],fontStyle:"bold"},alternateRowStyles:{fillColor:[245,245,250]},columnStyles:{0:{fontStyle:"bold",cellWidth:50}}});const S=t.lastAutoTable.finalY+10;t.setFontSize(8),t.setTextColor(160,160,160),t.text("Generated by LUPMIS2 Land Use Planning & Management Information System",a,S);const w=t.output("blob"),u=URL.createObjectURL(w);if(!window.open(u,"_blank")){const l=document.createElement("a");l.href=u,l.download=`${e.replace(/\s+/g,"_")}_${d.toISOString().slice(0,10)}.pdf`,document.body.appendChild(l),l.click(),document.body.removeChild(l)}}export{F as exportAnalysisPDF};
//# sourceMappingURL=pdf-export-C0eAmANf.js.map

2
dist/assets/pdf-export-Cq3nXOgJ.js vendored Normal file
View File

@ -0,0 +1,2 @@
import{E as f,a as b}from"./jspdf-BpioTcs4.js";import"./pako-Xa-UToif.js";import"./vite-helpers-BlTxHScW.js";b(f);let s=null;async function x(){if(s)return s;try{const e=new Image;e.crossOrigin="anonymous",await new Promise((r,i)=>{e.onload=r,e.onerror=i,e.src="./app-icons/luspa-pdf.jpg"});const n=document.createElement("canvas");n.width=e.naturalWidth,n.height=e.naturalHeight;const t=n.getContext("2d");return t.fillStyle="#ffffff",t.fillRect(0,0,n.width,n.height),t.drawImage(e,0,0),s=n.toDataURL("image/jpeg",.92),s}catch(e){return console.warn("[PDF] Could not load logo:",e),null}}async function D({title:e,rows:n}){const t=new f({orientation:"portrait",unit:"mm",format:"a4"}),r=t.internal.pageSize.getWidth(),i=[30,26,75],g=await x(),c=28,a=14;let o=14;g&&t.addImage(g,"JPEG",a,o,c,c);const m=a+c+6;t.setFont("helvetica","bold"),t.setFontSize(18),t.setTextColor(...i),t.text("LUPMIS",m,o+11),t.setFont("helvetica","normal"),t.setFontSize(12),t.text(e,m,o+19);const d=new Date,h=d.toLocaleDateString(void 0,{year:"numeric",month:"long",day:"numeric"}),p=d.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.setFontSize(9),t.setTextColor(120,120,120),t.text(`${h} ${p}`,r-a,o+11,{align:"right"}),o+=c+6,t.setDrawColor(...i),t.setLineWidth(.5),t.line(a,o,r-a,o),o+=6;const y=n.map(l=>[l.label,l.value]);t.autoTable({startY:o,head:[["Property","Value"]],body:y,margin:{left:a,right:a},styles:{font:"helvetica",fontSize:10,cellPadding:4},headStyles:{fillColor:i,textColor:[255,255,255],fontStyle:"bold"},alternateRowStyles:{fillColor:[245,245,250]},columnStyles:{0:{fontStyle:"bold",cellWidth:50}}});const S=t.lastAutoTable.finalY+10;t.setFontSize(8),t.setTextColor(160,160,160),t.text("Generated by LUPMIS2 Land Use Planning & Management Information System",a,S);const w=t.output("blob"),u=URL.createObjectURL(w);if(!window.open(u,"_blank")){const l=document.createElement("a");l.href=u,l.download=`${e.replace(/\s+/g,"_")}_${d.toISOString().slice(0,10)}.pdf`,document.body.appendChild(l),l.click(),document.body.removeChild(l)}}export{D as exportAnalysisPDF};
//# sourceMappingURL=pdf-export-Cq3nXOgJ.js.map

File diff suppressed because one or more lines are too long

5
dist/assets/shpjs-CNrRgkgn.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/assets/shpjs-CNrRgkgn.js.map vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
dist/assets/vite-helpers-BlTxHScW.js vendored Normal file
View File

@ -0,0 +1,2 @@
const p="modulepreload",v=function(l){return"/"+l},d={},y=function(f,c,E){let i=Promise.resolve();if(c&&c.length>0){let r=function(e){return Promise.all(e.map(o=>Promise.resolve(o).then(s=>({status:"fulfilled",value:s}),s=>({status:"rejected",reason:s}))))};document.getElementsByTagName("link");const t=document.querySelector("meta[property=csp-nonce]"),u=t?.nonce||t?.getAttribute("nonce");i=r(c.map(e=>{if(e=v(e),e in d)return;d[e]=!0;const o=e.endsWith(".css"),s=o?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${e}"]${s}`))return;const n=document.createElement("link");if(n.rel=o?"stylesheet":p,o||(n.as="script"),n.crossOrigin="",n.href=e,u&&n.setAttribute("nonce",u),document.head.appendChild(n),o)return new Promise((m,h)=>{n.addEventListener("load",m),n.addEventListener("error",()=>h(new Error(`Unable to preload CSS for ${e}`)))})}))}function a(r){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=r,window.dispatchEvent(t),!t.defaultPrevented)throw r}return i.then(r=>{for(const t of r||[])t.status==="rejected"&&a(t.reason);return f().catch(a)})};export{y as _};
//# sourceMappingURL=vite-helpers-BlTxHScW.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"vite-helpers-BlTxHScW.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}

12
dist/index.html vendored
View File

@ -1997,15 +1997,15 @@
} }
</style> </style>
<script type="module" crossorigin src="/assets/index-BzlrAJOS.js"></script> <script type="module" crossorigin src="/assets/index-D79Zl-eh.js"></script>
<link rel="modulepreload" crossorigin href="/assets/openlayers-D5-VSKzq.js"> <link rel="modulepreload" crossorigin href="/assets/vite-helpers-BlTxHScW.js">
<link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js">
<link rel="modulepreload" crossorigin href="/assets/geotiff-B9aROX49.js">
<link rel="modulepreload" crossorigin href="/assets/bootstrap-D1-uvFxm.js"> <link rel="modulepreload" crossorigin href="/assets/bootstrap-D1-uvFxm.js">
<link rel="modulepreload" crossorigin href="/assets/openlayers-D5-VSKzq.js">
<link rel="modulepreload" crossorigin href="/assets/ol-ext-DV70ljNY.js"> <link rel="modulepreload" crossorigin href="/assets/ol-ext-DV70ljNY.js">
<link rel="modulepreload" crossorigin href="/assets/shpjs-Doisr2ug.js"> <link rel="modulepreload" crossorigin href="/assets/pako-Xa-UToif.js">
<link rel="stylesheet" crossorigin href="/assets/openlayers-BtPuoxOl.css"> <link rel="modulepreload" crossorigin href="/assets/jszip-Dgg-11DP.js">
<link rel="stylesheet" crossorigin href="/assets/bootstrap-BtmJYOxZ.css"> <link rel="stylesheet" crossorigin href="/assets/bootstrap-BtmJYOxZ.css">
<link rel="stylesheet" crossorigin href="/assets/openlayers-BtPuoxOl.css">
<link rel="stylesheet" crossorigin href="/assets/ol-ext-BgKrOIxx.css"> <link rel="stylesheet" crossorigin href="/assets/ol-ext-BgKrOIxx.css">
<link rel="stylesheet" crossorigin href="/assets/index-Dp-9_Fz_.css"> <link rel="stylesheet" crossorigin href="/assets/index-Dp-9_Fz_.css">
</head> </head>

View File

@ -50,6 +50,21 @@ export default defineConfig({
// Without its own chunk, Rollup assigns it to one of them and the two // Without its own chunk, Rollup assigns it to one of them and the two
// chunks reference each other ("Circular chunk: jspdf -> geotiff"). // chunks reference each other ("Circular chunk: jspdf -> geotiff").
if (id.includes('node_modules/pako/')) return 'pako'; 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';
// JSZip reaches the bundle through shp-write, which src/gis-export.js
// imports statically for Shapefile export — so it is eager whatever
// we do. The old rule filed it under the shpjs chunk (shpjs 6 in fact
// unzips with but-unzip and never touches JSZip), which dragged that
// whole ~171 kB lazy chunk into the startup preload. On its own it
// costs the ~31 kB it actually is.
if (id.includes('node_modules/jszip/')) return 'jszip';
// Turf.js — only needed when the Analysis panel is opened, which // Turf.js — only needed when the Analysis panel is opened, which
// main.js imports dynamically. Keep it out of the eager bundle. // main.js imports dynamically. Keep it out of the eager bundle.
if (id.includes('node_modules/@turf/')) return 'turf'; if (id.includes('node_modules/@turf/')) return 'turf';
@ -63,9 +78,11 @@ export default defineConfig({
if (id.includes('node_modules/ol/')) return 'openlayers'; if (id.includes('node_modules/ol/')) return 'openlayers';
if (id.includes('node_modules/ol-ext/')) return 'ol-ext'; if (id.includes('node_modules/ol-ext/')) return 'ol-ext';
if (id.includes('node_modules/bootstrap/')) return 'bootstrap'; if (id.includes('node_modules/bootstrap/')) return 'bootstrap';
// shpjs (+ its jszip dependency) — dynamically imported at runtime, // shpjs — dynamically imported at runtime (main.js), so this chunk is
// so this chunk is only fetched when the user imports a shapefile. // only fetched when the user imports a shapefile. JSZip is no longer
if (id.includes('node_modules/shpjs/') || id.includes('node_modules/jszip/')) return 'shpjs'; // matched here (see the jszip rule above): it belongs to shp-write,
// and listing it here is what made this chunk load at startup.
if (id.includes('node_modules/shpjs/')) return 'shpjs';
if (id.includes('node_modules/jspdf')) return 'jspdf'; if (id.includes('node_modules/jspdf')) return 'jspdf';
}, },
}, },