diff --git a/.woodpecker/deploy.yml b/.woodpecker/deploy.yml
index b002985..e8cd49d 100644
--- a/.woodpecker/deploy.yml
+++ b/.woodpecker/deploy.yml
@@ -14,8 +14,8 @@ steps:
image: docker:latest
environment:
REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links
- DOCKER_API_VERSION: "1.43"
- DOCKER_BUILDKIT: "1"
+ DOCKER_API_VERSION: '1.43'
+ DOCKER_BUILDKIT: '1'
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
@@ -48,7 +48,7 @@ steps:
- name: Push to registry
image: docker:latest
environment:
- DOCKER_API_VERSION: "1.43"
+ DOCKER_API_VERSION: '1.43'
REGISTRY_URL: git.mifi.dev
REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links
REGISTRY_USERNAME:
diff --git a/Dockerfile b/Dockerfile
index dfdbe64..65e00b1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -48,6 +48,7 @@ FROM nginx:alpine
COPY --from=builder /out/dev /usr/share/nginx/html/dev
COPY --from=builder /out/bio /usr/share/nginx/html/bio
+COPY nginx.conf /etc/nginx/nginx.conf
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
COPY nginx/snippets/ /etc/nginx/snippets/
diff --git a/nginx.conf b/nginx.conf
new file mode 100644
index 0000000..d63bc1d
--- /dev/null
+++ b/nginx.conf
@@ -0,0 +1,49 @@
+ Minimal nginx configuration for static site delivery
+# Security headers are handled upstream by Traefik
+
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log warn;
+pid /var/run/nginx.pid;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ # Logging
+ log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+ '$status $body_bytes_sent "$http_referer" '
+ '"$http_user_agent" "$http_x_forwarded_for"';
+ access_log /var/log/nginx/access.log main;
+
+ # Performance optimizations
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+ types_hash_max_size 2048;
+ server_tokens off;
+
+ # Gzip compression for text-based assets
+ gzip on;
+ gzip_vary on;
+ gzip_proxied any;
+ gzip_comp_level 6;
+ gzip_min_length 256;
+ # text/html is always gzipped by default; listing it again causes "duplicate MIME type" warning
+ gzip_types
+ text/plain
+ text/css
+ text/xml
+ text/javascript
+ application/json
+ application/javascript
+ application/xml+rss
+ application/rss+xml
+ application/atom+xml
+ image/svg+xml;
+}
diff --git a/package.json b/package.json
index 33d0d97..f214d9c 100644
--- a/package.json
+++ b/package.json
@@ -5,12 +5,12 @@
"scripts": {
"dev:bio": "CONTENT_VARIANT=bio vite dev",
"dev:dev": "CONTENT_VARIANT=dev vite dev",
- "build": "vite build && node scripts/externalize-inline-script.mjs",
- "build:bio": "CONTENT_VARIANT=bio vite build && node scripts/externalize-inline-script.mjs",
- "build:dev": "CONTENT_VARIANT=dev vite build && node scripts/externalize-inline-script.mjs",
- "build:full": "vite build && pnpm run critical-css && node scripts/externalize-inline-script.mjs",
- "build:full:bio": "CONTENT_VARIANT=bio vite build && pnpm run critical-css && node scripts/externalize-inline-script.mjs",
- "build:full:dev": "CONTENT_VARIANT=dev vite build && pnpm run critical-css && node scripts/externalize-inline-script.mjs",
+ "build": "vite build && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
+ "build:bio": "CONTENT_VARIANT=bio vite build && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
+ "build:dev": "CONTENT_VARIANT=dev vite build && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
+ "build:full": "vite build && pnpm run critical-css && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
+ "build:full:bio": "CONTENT_VARIANT=bio vite build && pnpm run critical-css && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
+ "build:full:dev": "CONTENT_VARIANT=dev vite build && pnpm run critical-css && node scripts/minify-static-assets.mjs && node scripts/externalize-inline-script.mjs",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
@@ -40,6 +40,7 @@
"@typescript-eslint/parser": "^8.16.0",
"@vitest/coverage-v8": "^2.1.0",
"critical": "^7.0.0",
+ "esbuild": "^0.27.3",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 09dfaaf..0efc5a8 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -38,6 +38,9 @@ importers:
critical:
specifier: ^7.0.0
version: 7.2.1
+ esbuild:
+ specifier: ^0.27.3
+ version: 0.27.3
eslint:
specifier: ^8.57.0
version: 8.57.1
@@ -721,6 +724,15 @@ packages:
cpu: [ppc64]
os: [aix]
+ '@esbuild/aix-ppc64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [ppc64]
+ os: [aix]
+
'@esbuild/android-arm64@0.21.5':
resolution:
{
@@ -739,6 +751,15 @@ packages:
cpu: [arm64]
os: [android]
+ '@esbuild/android-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [android]
+
'@esbuild/android-arm@0.21.5':
resolution:
{
@@ -757,6 +778,15 @@ packages:
cpu: [arm]
os: [android]
+ '@esbuild/android-arm@0.27.3':
+ resolution:
+ {
+ integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm]
+ os: [android]
+
'@esbuild/android-x64@0.21.5':
resolution:
{
@@ -775,6 +805,15 @@ packages:
cpu: [x64]
os: [android]
+ '@esbuild/android-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [android]
+
'@esbuild/darwin-arm64@0.21.5':
resolution:
{
@@ -793,6 +832,15 @@ packages:
cpu: [arm64]
os: [darwin]
+ '@esbuild/darwin-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [darwin]
+
'@esbuild/darwin-x64@0.21.5':
resolution:
{
@@ -811,6 +859,15 @@ packages:
cpu: [x64]
os: [darwin]
+ '@esbuild/darwin-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [darwin]
+
'@esbuild/freebsd-arm64@0.21.5':
resolution:
{
@@ -829,6 +886,15 @@ packages:
cpu: [arm64]
os: [freebsd]
+ '@esbuild/freebsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [freebsd]
+
'@esbuild/freebsd-x64@0.21.5':
resolution:
{
@@ -847,6 +913,15 @@ packages:
cpu: [x64]
os: [freebsd]
+ '@esbuild/freebsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [freebsd]
+
'@esbuild/linux-arm64@0.21.5':
resolution:
{
@@ -865,6 +940,15 @@ packages:
cpu: [arm64]
os: [linux]
+ '@esbuild/linux-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [linux]
+
'@esbuild/linux-arm@0.21.5':
resolution:
{
@@ -883,6 +967,15 @@ packages:
cpu: [arm]
os: [linux]
+ '@esbuild/linux-arm@0.27.3':
+ resolution:
+ {
+ integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm]
+ os: [linux]
+
'@esbuild/linux-ia32@0.21.5':
resolution:
{
@@ -901,6 +994,15 @@ packages:
cpu: [ia32]
os: [linux]
+ '@esbuild/linux-ia32@0.27.3':
+ resolution:
+ {
+ integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==,
+ }
+ engines: { node: '>=18' }
+ cpu: [ia32]
+ os: [linux]
+
'@esbuild/linux-loong64@0.21.5':
resolution:
{
@@ -919,6 +1021,15 @@ packages:
cpu: [loong64]
os: [linux]
+ '@esbuild/linux-loong64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [loong64]
+ os: [linux]
+
'@esbuild/linux-mips64el@0.21.5':
resolution:
{
@@ -937,6 +1048,15 @@ packages:
cpu: [mips64el]
os: [linux]
+ '@esbuild/linux-mips64el@0.27.3':
+ resolution:
+ {
+ integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==,
+ }
+ engines: { node: '>=18' }
+ cpu: [mips64el]
+ os: [linux]
+
'@esbuild/linux-ppc64@0.21.5':
resolution:
{
@@ -955,6 +1075,15 @@ packages:
cpu: [ppc64]
os: [linux]
+ '@esbuild/linux-ppc64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [ppc64]
+ os: [linux]
+
'@esbuild/linux-riscv64@0.21.5':
resolution:
{
@@ -973,6 +1102,15 @@ packages:
cpu: [riscv64]
os: [linux]
+ '@esbuild/linux-riscv64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==,
+ }
+ engines: { node: '>=18' }
+ cpu: [riscv64]
+ os: [linux]
+
'@esbuild/linux-s390x@0.21.5':
resolution:
{
@@ -991,6 +1129,15 @@ packages:
cpu: [s390x]
os: [linux]
+ '@esbuild/linux-s390x@0.27.3':
+ resolution:
+ {
+ integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==,
+ }
+ engines: { node: '>=18' }
+ cpu: [s390x]
+ os: [linux]
+
'@esbuild/linux-x64@0.21.5':
resolution:
{
@@ -1009,6 +1156,15 @@ packages:
cpu: [x64]
os: [linux]
+ '@esbuild/linux-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [linux]
+
'@esbuild/netbsd-arm64@0.25.12':
resolution:
{
@@ -1018,6 +1174,15 @@ packages:
cpu: [arm64]
os: [netbsd]
+ '@esbuild/netbsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [netbsd]
+
'@esbuild/netbsd-x64@0.21.5':
resolution:
{
@@ -1036,6 +1201,15 @@ packages:
cpu: [x64]
os: [netbsd]
+ '@esbuild/netbsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [netbsd]
+
'@esbuild/openbsd-arm64@0.25.12':
resolution:
{
@@ -1045,6 +1219,15 @@ packages:
cpu: [arm64]
os: [openbsd]
+ '@esbuild/openbsd-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [openbsd]
+
'@esbuild/openbsd-x64@0.21.5':
resolution:
{
@@ -1063,6 +1246,15 @@ packages:
cpu: [x64]
os: [openbsd]
+ '@esbuild/openbsd-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [openbsd]
+
'@esbuild/openharmony-arm64@0.25.12':
resolution:
{
@@ -1072,6 +1264,15 @@ packages:
cpu: [arm64]
os: [openharmony]
+ '@esbuild/openharmony-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [openharmony]
+
'@esbuild/sunos-x64@0.21.5':
resolution:
{
@@ -1090,6 +1291,15 @@ packages:
cpu: [x64]
os: [sunos]
+ '@esbuild/sunos-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [sunos]
+
'@esbuild/win32-arm64@0.21.5':
resolution:
{
@@ -1108,6 +1318,15 @@ packages:
cpu: [arm64]
os: [win32]
+ '@esbuild/win32-arm64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [arm64]
+ os: [win32]
+
'@esbuild/win32-ia32@0.21.5':
resolution:
{
@@ -1126,6 +1345,15 @@ packages:
cpu: [ia32]
os: [win32]
+ '@esbuild/win32-ia32@0.27.3':
+ resolution:
+ {
+ integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==,
+ }
+ engines: { node: '>=18' }
+ cpu: [ia32]
+ os: [win32]
+
'@esbuild/win32-x64@0.21.5':
resolution:
{
@@ -1144,6 +1372,15 @@ packages:
cpu: [x64]
os: [win32]
+ '@esbuild/win32-x64@0.27.3':
+ resolution:
+ {
+ integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==,
+ }
+ engines: { node: '>=18' }
+ cpu: [x64]
+ os: [win32]
+
'@eslint-community/eslint-utils@4.9.1':
resolution:
{
@@ -2885,6 +3122,14 @@ packages:
engines: { node: '>=18' }
hasBin: true
+ esbuild@0.27.3:
+ resolution:
+ {
+ integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==,
+ }
+ engines: { node: '>=18' }
+ hasBin: true
+
escalade@3.2.0:
resolution:
{
@@ -6678,147 +6923,225 @@ snapshots:
'@esbuild/aix-ppc64@0.25.12':
optional: true
+ '@esbuild/aix-ppc64@0.27.3':
+ optional: true
+
'@esbuild/android-arm64@0.21.5':
optional: true
'@esbuild/android-arm64@0.25.12':
optional: true
+ '@esbuild/android-arm64@0.27.3':
+ optional: true
+
'@esbuild/android-arm@0.21.5':
optional: true
'@esbuild/android-arm@0.25.12':
optional: true
+ '@esbuild/android-arm@0.27.3':
+ optional: true
+
'@esbuild/android-x64@0.21.5':
optional: true
'@esbuild/android-x64@0.25.12':
optional: true
+ '@esbuild/android-x64@0.27.3':
+ optional: true
+
'@esbuild/darwin-arm64@0.21.5':
optional: true
'@esbuild/darwin-arm64@0.25.12':
optional: true
+ '@esbuild/darwin-arm64@0.27.3':
+ optional: true
+
'@esbuild/darwin-x64@0.21.5':
optional: true
'@esbuild/darwin-x64@0.25.12':
optional: true
+ '@esbuild/darwin-x64@0.27.3':
+ optional: true
+
'@esbuild/freebsd-arm64@0.21.5':
optional: true
'@esbuild/freebsd-arm64@0.25.12':
optional: true
+ '@esbuild/freebsd-arm64@0.27.3':
+ optional: true
+
'@esbuild/freebsd-x64@0.21.5':
optional: true
'@esbuild/freebsd-x64@0.25.12':
optional: true
+ '@esbuild/freebsd-x64@0.27.3':
+ optional: true
+
'@esbuild/linux-arm64@0.21.5':
optional: true
'@esbuild/linux-arm64@0.25.12':
optional: true
+ '@esbuild/linux-arm64@0.27.3':
+ optional: true
+
'@esbuild/linux-arm@0.21.5':
optional: true
'@esbuild/linux-arm@0.25.12':
optional: true
+ '@esbuild/linux-arm@0.27.3':
+ optional: true
+
'@esbuild/linux-ia32@0.21.5':
optional: true
'@esbuild/linux-ia32@0.25.12':
optional: true
+ '@esbuild/linux-ia32@0.27.3':
+ optional: true
+
'@esbuild/linux-loong64@0.21.5':
optional: true
'@esbuild/linux-loong64@0.25.12':
optional: true
+ '@esbuild/linux-loong64@0.27.3':
+ optional: true
+
'@esbuild/linux-mips64el@0.21.5':
optional: true
'@esbuild/linux-mips64el@0.25.12':
optional: true
+ '@esbuild/linux-mips64el@0.27.3':
+ optional: true
+
'@esbuild/linux-ppc64@0.21.5':
optional: true
'@esbuild/linux-ppc64@0.25.12':
optional: true
+ '@esbuild/linux-ppc64@0.27.3':
+ optional: true
+
'@esbuild/linux-riscv64@0.21.5':
optional: true
'@esbuild/linux-riscv64@0.25.12':
optional: true
+ '@esbuild/linux-riscv64@0.27.3':
+ optional: true
+
'@esbuild/linux-s390x@0.21.5':
optional: true
'@esbuild/linux-s390x@0.25.12':
optional: true
+ '@esbuild/linux-s390x@0.27.3':
+ optional: true
+
'@esbuild/linux-x64@0.21.5':
optional: true
'@esbuild/linux-x64@0.25.12':
optional: true
+ '@esbuild/linux-x64@0.27.3':
+ optional: true
+
'@esbuild/netbsd-arm64@0.25.12':
optional: true
+ '@esbuild/netbsd-arm64@0.27.3':
+ optional: true
+
'@esbuild/netbsd-x64@0.21.5':
optional: true
'@esbuild/netbsd-x64@0.25.12':
optional: true
+ '@esbuild/netbsd-x64@0.27.3':
+ optional: true
+
'@esbuild/openbsd-arm64@0.25.12':
optional: true
+ '@esbuild/openbsd-arm64@0.27.3':
+ optional: true
+
'@esbuild/openbsd-x64@0.21.5':
optional: true
'@esbuild/openbsd-x64@0.25.12':
optional: true
+ '@esbuild/openbsd-x64@0.27.3':
+ optional: true
+
'@esbuild/openharmony-arm64@0.25.12':
optional: true
+ '@esbuild/openharmony-arm64@0.27.3':
+ optional: true
+
'@esbuild/sunos-x64@0.21.5':
optional: true
'@esbuild/sunos-x64@0.25.12':
optional: true
+ '@esbuild/sunos-x64@0.27.3':
+ optional: true
+
'@esbuild/win32-arm64@0.21.5':
optional: true
'@esbuild/win32-arm64@0.25.12':
optional: true
+ '@esbuild/win32-arm64@0.27.3':
+ optional: true
+
'@esbuild/win32-ia32@0.21.5':
optional: true
'@esbuild/win32-ia32@0.25.12':
optional: true
+ '@esbuild/win32-ia32@0.27.3':
+ optional: true
+
'@esbuild/win32-x64@0.21.5':
optional: true
'@esbuild/win32-x64@0.25.12':
optional: true
+ '@esbuild/win32-x64@0.27.3':
+ optional: true
+
'@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)':
dependencies:
eslint: 8.57.1
@@ -7904,6 +8227,35 @@ snapshots:
'@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 0.25.12
+ esbuild@0.27.3:
+ optionalDependencies:
+ '@esbuild/aix-ppc64': 0.27.3
+ '@esbuild/android-arm': 0.27.3
+ '@esbuild/android-arm64': 0.27.3
+ '@esbuild/android-x64': 0.27.3
+ '@esbuild/darwin-arm64': 0.27.3
+ '@esbuild/darwin-x64': 0.27.3
+ '@esbuild/freebsd-arm64': 0.27.3
+ '@esbuild/freebsd-x64': 0.27.3
+ '@esbuild/linux-arm': 0.27.3
+ '@esbuild/linux-arm64': 0.27.3
+ '@esbuild/linux-ia32': 0.27.3
+ '@esbuild/linux-loong64': 0.27.3
+ '@esbuild/linux-mips64el': 0.27.3
+ '@esbuild/linux-ppc64': 0.27.3
+ '@esbuild/linux-riscv64': 0.27.3
+ '@esbuild/linux-s390x': 0.27.3
+ '@esbuild/linux-x64': 0.27.3
+ '@esbuild/netbsd-arm64': 0.27.3
+ '@esbuild/netbsd-x64': 0.27.3
+ '@esbuild/openbsd-arm64': 0.27.3
+ '@esbuild/openbsd-x64': 0.27.3
+ '@esbuild/openharmony-arm64': 0.27.3
+ '@esbuild/sunos-x64': 0.27.3
+ '@esbuild/win32-arm64': 0.27.3
+ '@esbuild/win32-ia32': 0.27.3
+ '@esbuild/win32-x64': 0.27.3
+
escalade@3.2.0: {}
escape-string-regexp@4.0.0: {}
diff --git a/scripts/externalize-inline-script.mjs b/scripts/externalize-inline-script.mjs
index a986dea..5180f3c 100644
--- a/scripts/externalize-inline-script.mjs
+++ b/scripts/externalize-inline-script.mjs
@@ -1,6 +1,7 @@
/**
* Post-build: extract SvelteKit's inline bootstrap script to an external file
* and replace it with `;
+ html = html.slice(0, found.start) + scriptTag + html.slice(found.end);
+ // Use absolute paths for _app assets so they resolve correctly (host-based routing, redirects)
+ html = html.replace(/\.\/_app\//g, '/_app/');
+ writeFileSync(htmlPath, html, 'utf-8');
+ console.log('Externalized SvelteKit bootstrap to', scriptPath);
+ } catch (err) {
+ console.error(
+ 'externalize-inline-script failed:',
+ err instanceof Error ? err.message : String(err),
+ );
+ process.exit(1);
}
- let content = found.content;
- // Bootstrap runs from /_app/immutable/bootstrap.xxx.js; imports like "./_app/immutable/entry/..."
- // would resolve to /_app/immutable/_app/immutable/entry/... (duplicate). Use directory-relative paths.
- content = content.replace(/\.\/_app\/immutable\//g, './');
- const hash = createHash('sha256').update(content).digest('hex').slice(0, 8);
- const filename = `bootstrap.${hash}.js`;
- const immutableDir = join(buildDir, '_app', 'immutable');
- mkdirSync(immutableDir, { recursive: true });
- const scriptPath = join(immutableDir, filename);
- writeFileSync(scriptPath, content.trimStart(), 'utf-8');
- const scriptTag = ``;
- html = html.slice(0, found.start) + scriptTag + html.slice(found.end);
- // Use absolute paths for _app assets so they resolve correctly (host-based routing, redirects)
- html = html.replace(/\.\/_app\//g, '/_app/');
- writeFileSync(htmlPath, html, 'utf-8');
- console.log('Externalized SvelteKit bootstrap to', scriptPath);
-} catch (err) {
- console.error(
- 'externalize-inline-script failed:',
- err instanceof Error ? err.message : String(err),
- );
- process.exit(1);
}
+
+main();
diff --git a/scripts/minify-static-assets.mjs b/scripts/minify-static-assets.mjs
new file mode 100644
index 0000000..fe0738c
--- /dev/null
+++ b/scripts/minify-static-assets.mjs
@@ -0,0 +1,41 @@
+/**
+ * Post-build: minify JS and CSS under build/assets (files copied from static/).
+ * Usage: node scripts/minify-static-assets.mjs [buildDir]
+ */
+import { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs';
+import { join } from 'node:path';
+import { cwd } from 'node:process';
+import * as esbuild from 'esbuild';
+
+const buildDir = join(cwd(), process.argv[2] || 'build');
+const assetsDir = join(buildDir, 'assets');
+
+function* walk(dir, base = '') {
+ for (const name of readdirSync(dir, { withFileTypes: true })) {
+ const rel = join(base, name.name);
+ if (name.isDirectory()) yield* walk(join(dir, name.name), rel);
+ else yield rel;
+ }
+}
+
+async function minifyAll() {
+ if (!existsSync(assetsDir)) return;
+ for (const rel of walk(assetsDir, '')) {
+ const path = join(assetsDir, rel);
+ const ext = rel.slice(rel.lastIndexOf('.'));
+ if (ext === '.js') {
+ const code = readFileSync(path, 'utf-8');
+ const out = await esbuild.transform(code, { minify: true, loader: 'js' });
+ writeFileSync(path, out.code);
+ } else if (ext === '.css') {
+ const code = readFileSync(path, 'utf-8');
+ const out = await esbuild.transform(code, { minify: true, loader: 'css' });
+ writeFileSync(path, out.code);
+ }
+ }
+}
+
+minifyAll().catch((e) => {
+ console.error(e);
+ process.exit(1);
+});
diff --git a/static/assets/js/bootstrap.js b/static/assets/js/bootstrap.js
index 372251d..ce0dea3 100644
--- a/static/assets/js/bootstrap.js
+++ b/static/assets/js/bootstrap.js
@@ -2,8 +2,14 @@
// Default Trusted Type policy so Svelte hydration can assign to innerHTML under CSP require-trusted-types-for 'script'.
if (typeof window.trustedTypes !== 'undefined' && window.trustedTypes.createPolicy) {
try {
- window.trustedTypes.createPolicy('default', { createHTML: function (input) { return input; } });
- } catch { /* policy already exists */ }
+ window.trustedTypes.createPolicy('default', {
+ createHTML: function (input) {
+ return input;
+ },
+ });
+ } catch {
+ /* policy already exists */
+ }
}
var t = localStorage.getItem('mifi-theme');
diff --git a/vite.config.ts b/vite.config.ts
index b109c7d..732c1a3 100644
--- a/vite.config.ts
+++ b/vite.config.ts
@@ -3,4 +3,7 @@ import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
+ build: {
+ cssMinify: true,
+ },
});