Minification and compression
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/push/deploy Pipeline was successful

This commit is contained in:
2026-02-07 00:30:08 -03:00
parent 93e2618dcf
commit 840c6cdeba
9 changed files with 501 additions and 39 deletions

View File

@@ -14,8 +14,8 @@ steps:
image: docker:latest image: docker:latest
environment: environment:
REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links
DOCKER_API_VERSION: "1.43" DOCKER_API_VERSION: '1.43'
DOCKER_BUILDKIT: "1" DOCKER_BUILDKIT: '1'
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock - /var/run/docker.sock:/var/run/docker.sock
commands: commands:
@@ -48,7 +48,7 @@ steps:
- name: Push to registry - name: Push to registry
image: docker:latest image: docker:latest
environment: environment:
DOCKER_API_VERSION: "1.43" DOCKER_API_VERSION: '1.43'
REGISTRY_URL: git.mifi.dev REGISTRY_URL: git.mifi.dev
REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links REGISTRY_REPO: git.mifi.dev/mifi-holdings/mifi-links
REGISTRY_USERNAME: REGISTRY_USERNAME:

View File

@@ -48,6 +48,7 @@ FROM nginx:alpine
COPY --from=builder /out/dev /usr/share/nginx/html/dev COPY --from=builder /out/dev /usr/share/nginx/html/dev
COPY --from=builder /out/bio /usr/share/nginx/html/bio 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/default.conf /etc/nginx/conf.d/default.conf
COPY nginx/snippets/ /etc/nginx/snippets/ COPY nginx/snippets/ /etc/nginx/snippets/

49
nginx.conf Normal file
View File

@@ -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;
}

View File

@@ -5,12 +5,12 @@
"scripts": { "scripts": {
"dev:bio": "CONTENT_VARIANT=bio vite dev", "dev:bio": "CONTENT_VARIANT=bio vite dev",
"dev:dev": "CONTENT_VARIANT=dev vite dev", "dev:dev": "CONTENT_VARIANT=dev vite dev",
"build": "vite build && 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/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/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/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/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/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", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
@@ -40,6 +40,7 @@
"@typescript-eslint/parser": "^8.16.0", "@typescript-eslint/parser": "^8.16.0",
"@vitest/coverage-v8": "^2.1.0", "@vitest/coverage-v8": "^2.1.0",
"critical": "^7.0.0", "critical": "^7.0.0",
"esbuild": "^0.27.3",
"eslint": "^8.57.0", "eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.36.0", "eslint-plugin-svelte": "^2.36.0",

352
pnpm-lock.yaml generated
View File

@@ -38,6 +38,9 @@ importers:
critical: critical:
specifier: ^7.0.0 specifier: ^7.0.0
version: 7.2.1 version: 7.2.1
esbuild:
specifier: ^0.27.3
version: 0.27.3
eslint: eslint:
specifier: ^8.57.0 specifier: ^8.57.0
version: 8.57.1 version: 8.57.1
@@ -721,6 +724,15 @@ packages:
cpu: [ppc64] cpu: [ppc64]
os: [aix] 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': '@esbuild/android-arm64@0.21.5':
resolution: resolution:
{ {
@@ -739,6 +751,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [android] 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': '@esbuild/android-arm@0.21.5':
resolution: resolution:
{ {
@@ -757,6 +778,15 @@ packages:
cpu: [arm] cpu: [arm]
os: [android] 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': '@esbuild/android-x64@0.21.5':
resolution: resolution:
{ {
@@ -775,6 +805,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [android] 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': '@esbuild/darwin-arm64@0.21.5':
resolution: resolution:
{ {
@@ -793,6 +832,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [darwin] 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': '@esbuild/darwin-x64@0.21.5':
resolution: resolution:
{ {
@@ -811,6 +859,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [darwin] 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': '@esbuild/freebsd-arm64@0.21.5':
resolution: resolution:
{ {
@@ -829,6 +886,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [freebsd] 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': '@esbuild/freebsd-x64@0.21.5':
resolution: resolution:
{ {
@@ -847,6 +913,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [freebsd] 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': '@esbuild/linux-arm64@0.21.5':
resolution: resolution:
{ {
@@ -865,6 +940,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [linux] 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': '@esbuild/linux-arm@0.21.5':
resolution: resolution:
{ {
@@ -883,6 +967,15 @@ packages:
cpu: [arm] cpu: [arm]
os: [linux] 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': '@esbuild/linux-ia32@0.21.5':
resolution: resolution:
{ {
@@ -901,6 +994,15 @@ packages:
cpu: [ia32] cpu: [ia32]
os: [linux] 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': '@esbuild/linux-loong64@0.21.5':
resolution: resolution:
{ {
@@ -919,6 +1021,15 @@ packages:
cpu: [loong64] cpu: [loong64]
os: [linux] 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': '@esbuild/linux-mips64el@0.21.5':
resolution: resolution:
{ {
@@ -937,6 +1048,15 @@ packages:
cpu: [mips64el] cpu: [mips64el]
os: [linux] 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': '@esbuild/linux-ppc64@0.21.5':
resolution: resolution:
{ {
@@ -955,6 +1075,15 @@ packages:
cpu: [ppc64] cpu: [ppc64]
os: [linux] 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': '@esbuild/linux-riscv64@0.21.5':
resolution: resolution:
{ {
@@ -973,6 +1102,15 @@ packages:
cpu: [riscv64] cpu: [riscv64]
os: [linux] 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': '@esbuild/linux-s390x@0.21.5':
resolution: resolution:
{ {
@@ -991,6 +1129,15 @@ packages:
cpu: [s390x] cpu: [s390x]
os: [linux] 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': '@esbuild/linux-x64@0.21.5':
resolution: resolution:
{ {
@@ -1009,6 +1156,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [linux] 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': '@esbuild/netbsd-arm64@0.25.12':
resolution: resolution:
{ {
@@ -1018,6 +1174,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [netbsd] 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': '@esbuild/netbsd-x64@0.21.5':
resolution: resolution:
{ {
@@ -1036,6 +1201,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [netbsd] 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': '@esbuild/openbsd-arm64@0.25.12':
resolution: resolution:
{ {
@@ -1045,6 +1219,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [openbsd] 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': '@esbuild/openbsd-x64@0.21.5':
resolution: resolution:
{ {
@@ -1063,6 +1246,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [openbsd] 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': '@esbuild/openharmony-arm64@0.25.12':
resolution: resolution:
{ {
@@ -1072,6 +1264,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [openharmony] 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': '@esbuild/sunos-x64@0.21.5':
resolution: resolution:
{ {
@@ -1090,6 +1291,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [sunos] 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': '@esbuild/win32-arm64@0.21.5':
resolution: resolution:
{ {
@@ -1108,6 +1318,15 @@ packages:
cpu: [arm64] cpu: [arm64]
os: [win32] 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': '@esbuild/win32-ia32@0.21.5':
resolution: resolution:
{ {
@@ -1126,6 +1345,15 @@ packages:
cpu: [ia32] cpu: [ia32]
os: [win32] 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': '@esbuild/win32-x64@0.21.5':
resolution: resolution:
{ {
@@ -1144,6 +1372,15 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] 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': '@eslint-community/eslint-utils@4.9.1':
resolution: resolution:
{ {
@@ -2885,6 +3122,14 @@ packages:
engines: { node: '>=18' } engines: { node: '>=18' }
hasBin: true hasBin: true
esbuild@0.27.3:
resolution:
{
integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==,
}
engines: { node: '>=18' }
hasBin: true
escalade@3.2.0: escalade@3.2.0:
resolution: resolution:
{ {
@@ -6678,147 +6923,225 @@ snapshots:
'@esbuild/aix-ppc64@0.25.12': '@esbuild/aix-ppc64@0.25.12':
optional: true optional: true
'@esbuild/aix-ppc64@0.27.3':
optional: true
'@esbuild/android-arm64@0.21.5': '@esbuild/android-arm64@0.21.5':
optional: true optional: true
'@esbuild/android-arm64@0.25.12': '@esbuild/android-arm64@0.25.12':
optional: true optional: true
'@esbuild/android-arm64@0.27.3':
optional: true
'@esbuild/android-arm@0.21.5': '@esbuild/android-arm@0.21.5':
optional: true optional: true
'@esbuild/android-arm@0.25.12': '@esbuild/android-arm@0.25.12':
optional: true optional: true
'@esbuild/android-arm@0.27.3':
optional: true
'@esbuild/android-x64@0.21.5': '@esbuild/android-x64@0.21.5':
optional: true optional: true
'@esbuild/android-x64@0.25.12': '@esbuild/android-x64@0.25.12':
optional: true optional: true
'@esbuild/android-x64@0.27.3':
optional: true
'@esbuild/darwin-arm64@0.21.5': '@esbuild/darwin-arm64@0.21.5':
optional: true optional: true
'@esbuild/darwin-arm64@0.25.12': '@esbuild/darwin-arm64@0.25.12':
optional: true optional: true
'@esbuild/darwin-arm64@0.27.3':
optional: true
'@esbuild/darwin-x64@0.21.5': '@esbuild/darwin-x64@0.21.5':
optional: true optional: true
'@esbuild/darwin-x64@0.25.12': '@esbuild/darwin-x64@0.25.12':
optional: true optional: true
'@esbuild/darwin-x64@0.27.3':
optional: true
'@esbuild/freebsd-arm64@0.21.5': '@esbuild/freebsd-arm64@0.21.5':
optional: true optional: true
'@esbuild/freebsd-arm64@0.25.12': '@esbuild/freebsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/freebsd-arm64@0.27.3':
optional: true
'@esbuild/freebsd-x64@0.21.5': '@esbuild/freebsd-x64@0.21.5':
optional: true optional: true
'@esbuild/freebsd-x64@0.25.12': '@esbuild/freebsd-x64@0.25.12':
optional: true optional: true
'@esbuild/freebsd-x64@0.27.3':
optional: true
'@esbuild/linux-arm64@0.21.5': '@esbuild/linux-arm64@0.21.5':
optional: true optional: true
'@esbuild/linux-arm64@0.25.12': '@esbuild/linux-arm64@0.25.12':
optional: true optional: true
'@esbuild/linux-arm64@0.27.3':
optional: true
'@esbuild/linux-arm@0.21.5': '@esbuild/linux-arm@0.21.5':
optional: true optional: true
'@esbuild/linux-arm@0.25.12': '@esbuild/linux-arm@0.25.12':
optional: true optional: true
'@esbuild/linux-arm@0.27.3':
optional: true
'@esbuild/linux-ia32@0.21.5': '@esbuild/linux-ia32@0.21.5':
optional: true optional: true
'@esbuild/linux-ia32@0.25.12': '@esbuild/linux-ia32@0.25.12':
optional: true optional: true
'@esbuild/linux-ia32@0.27.3':
optional: true
'@esbuild/linux-loong64@0.21.5': '@esbuild/linux-loong64@0.21.5':
optional: true optional: true
'@esbuild/linux-loong64@0.25.12': '@esbuild/linux-loong64@0.25.12':
optional: true optional: true
'@esbuild/linux-loong64@0.27.3':
optional: true
'@esbuild/linux-mips64el@0.21.5': '@esbuild/linux-mips64el@0.21.5':
optional: true optional: true
'@esbuild/linux-mips64el@0.25.12': '@esbuild/linux-mips64el@0.25.12':
optional: true optional: true
'@esbuild/linux-mips64el@0.27.3':
optional: true
'@esbuild/linux-ppc64@0.21.5': '@esbuild/linux-ppc64@0.21.5':
optional: true optional: true
'@esbuild/linux-ppc64@0.25.12': '@esbuild/linux-ppc64@0.25.12':
optional: true optional: true
'@esbuild/linux-ppc64@0.27.3':
optional: true
'@esbuild/linux-riscv64@0.21.5': '@esbuild/linux-riscv64@0.21.5':
optional: true optional: true
'@esbuild/linux-riscv64@0.25.12': '@esbuild/linux-riscv64@0.25.12':
optional: true optional: true
'@esbuild/linux-riscv64@0.27.3':
optional: true
'@esbuild/linux-s390x@0.21.5': '@esbuild/linux-s390x@0.21.5':
optional: true optional: true
'@esbuild/linux-s390x@0.25.12': '@esbuild/linux-s390x@0.25.12':
optional: true optional: true
'@esbuild/linux-s390x@0.27.3':
optional: true
'@esbuild/linux-x64@0.21.5': '@esbuild/linux-x64@0.21.5':
optional: true optional: true
'@esbuild/linux-x64@0.25.12': '@esbuild/linux-x64@0.25.12':
optional: true optional: true
'@esbuild/linux-x64@0.27.3':
optional: true
'@esbuild/netbsd-arm64@0.25.12': '@esbuild/netbsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/netbsd-arm64@0.27.3':
optional: true
'@esbuild/netbsd-x64@0.21.5': '@esbuild/netbsd-x64@0.21.5':
optional: true optional: true
'@esbuild/netbsd-x64@0.25.12': '@esbuild/netbsd-x64@0.25.12':
optional: true optional: true
'@esbuild/netbsd-x64@0.27.3':
optional: true
'@esbuild/openbsd-arm64@0.25.12': '@esbuild/openbsd-arm64@0.25.12':
optional: true optional: true
'@esbuild/openbsd-arm64@0.27.3':
optional: true
'@esbuild/openbsd-x64@0.21.5': '@esbuild/openbsd-x64@0.21.5':
optional: true optional: true
'@esbuild/openbsd-x64@0.25.12': '@esbuild/openbsd-x64@0.25.12':
optional: true optional: true
'@esbuild/openbsd-x64@0.27.3':
optional: true
'@esbuild/openharmony-arm64@0.25.12': '@esbuild/openharmony-arm64@0.25.12':
optional: true optional: true
'@esbuild/openharmony-arm64@0.27.3':
optional: true
'@esbuild/sunos-x64@0.21.5': '@esbuild/sunos-x64@0.21.5':
optional: true optional: true
'@esbuild/sunos-x64@0.25.12': '@esbuild/sunos-x64@0.25.12':
optional: true optional: true
'@esbuild/sunos-x64@0.27.3':
optional: true
'@esbuild/win32-arm64@0.21.5': '@esbuild/win32-arm64@0.21.5':
optional: true optional: true
'@esbuild/win32-arm64@0.25.12': '@esbuild/win32-arm64@0.25.12':
optional: true optional: true
'@esbuild/win32-arm64@0.27.3':
optional: true
'@esbuild/win32-ia32@0.21.5': '@esbuild/win32-ia32@0.21.5':
optional: true optional: true
'@esbuild/win32-ia32@0.25.12': '@esbuild/win32-ia32@0.25.12':
optional: true optional: true
'@esbuild/win32-ia32@0.27.3':
optional: true
'@esbuild/win32-x64@0.21.5': '@esbuild/win32-x64@0.21.5':
optional: true optional: true
'@esbuild/win32-x64@0.25.12': '@esbuild/win32-x64@0.25.12':
optional: true optional: true
'@esbuild/win32-x64@0.27.3':
optional: true
'@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)':
dependencies: dependencies:
eslint: 8.57.1 eslint: 8.57.1
@@ -7904,6 +8227,35 @@ snapshots:
'@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-ia32': 0.25.12
'@esbuild/win32-x64': 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: {} escalade@3.2.0: {}
escape-string-regexp@4.0.0: {} escape-string-regexp@4.0.0: {}

View File

@@ -1,6 +1,7 @@
/** /**
* Post-build: extract SvelteKit's inline bootstrap script to an external file * Post-build: extract SvelteKit's inline bootstrap script to an external file
* and replace it with <script src="..."> so CSP can use script-src 'self' without unsafe-inline. * and replace it with <script src="..."> so CSP can use script-src 'self' without unsafe-inline.
* Minifies the extracted JS.
* *
* Usage: node scripts/externalize-inline-script.mjs [buildDir] * Usage: node scripts/externalize-inline-script.mjs [buildDir]
* buildDir: path to build output (default: "build"). Use from repo root. * buildDir: path to build output (default: "build"). Use from repo root.
@@ -9,6 +10,7 @@ import { readFileSync, writeFileSync, mkdirSync } from 'node:fs';
import { createHash } from 'node:crypto'; import { createHash } from 'node:crypto';
import { join } from 'node:path'; import { join } from 'node:path';
import { cwd } from 'node:process'; import { cwd } from 'node:process';
import * as esbuild from 'esbuild';
const buildDir = join(cwd(), process.argv[2] || 'build'); const buildDir = join(cwd(), process.argv[2] || 'build');
const htmlPath = join(buildDir, 'index.html'); const htmlPath = join(buildDir, 'index.html');
@@ -66,7 +68,8 @@ function extractScriptContent(html, scriptStart) {
return null; return null;
} }
try { async function main() {
try {
let html = readFileSync(htmlPath, 'utf-8'); let html = readFileSync(htmlPath, 'utf-8');
const found = findSvelteKitInlineScript(html); const found = findSvelteKitInlineScript(html);
if (!found) { if (!found) {
@@ -77,22 +80,28 @@ try {
// Bootstrap runs from /_app/immutable/bootstrap.xxx.js; imports like "./_app/immutable/entry/..." // 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. // would resolve to /_app/immutable/_app/immutable/entry/... (duplicate). Use directory-relative paths.
content = content.replace(/\.\/_app\/immutable\//g, './'); content = content.replace(/\.\/_app\/immutable\//g, './');
// Minify
const minified = await esbuild.transform(content, { minify: true, loader: 'js' });
content = minified.code;
const hash = createHash('sha256').update(content).digest('hex').slice(0, 8); const hash = createHash('sha256').update(content).digest('hex').slice(0, 8);
const filename = `bootstrap.${hash}.js`; const filename = `bootstrap.${hash}.js`;
const immutableDir = join(buildDir, '_app', 'immutable'); const immutableDir = join(buildDir, '_app', 'immutable');
mkdirSync(immutableDir, { recursive: true }); mkdirSync(immutableDir, { recursive: true });
const scriptPath = join(immutableDir, filename); const scriptPath = join(immutableDir, filename);
writeFileSync(scriptPath, content.trimStart(), 'utf-8'); writeFileSync(scriptPath, content, 'utf-8');
const scriptTag = `<script src="/_app/immutable/${filename}"></script>`; const scriptTag = `<script src="/_app/immutable/${filename}"></script>`;
html = html.slice(0, found.start) + scriptTag + html.slice(found.end); 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) // Use absolute paths for _app assets so they resolve correctly (host-based routing, redirects)
html = html.replace(/\.\/_app\//g, '/_app/'); html = html.replace(/\.\/_app\//g, '/_app/');
writeFileSync(htmlPath, html, 'utf-8'); writeFileSync(htmlPath, html, 'utf-8');
console.log('Externalized SvelteKit bootstrap to', scriptPath); console.log('Externalized SvelteKit bootstrap to', scriptPath);
} catch (err) { } catch (err) {
console.error( console.error(
'externalize-inline-script failed:', 'externalize-inline-script failed:',
err instanceof Error ? err.message : String(err), err instanceof Error ? err.message : String(err),
); );
process.exit(1); process.exit(1);
}
} }
main();

View File

@@ -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);
});

View File

@@ -2,8 +2,14 @@
// Default Trusted Type policy so Svelte hydration can assign to innerHTML under CSP require-trusted-types-for 'script'. // 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) { if (typeof window.trustedTypes !== 'undefined' && window.trustedTypes.createPolicy) {
try { try {
window.trustedTypes.createPolicy('default', { createHTML: function (input) { return input; } }); window.trustedTypes.createPolicy('default', {
} catch { /* policy already exists */ } createHTML: function (input) {
return input;
},
});
} catch {
/* policy already exists */
}
} }
var t = localStorage.getItem('mifi-theme'); var t = localStorage.getItem('mifi-theme');

View File

@@ -3,4 +3,7 @@ import { defineConfig } from 'vite';
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()], plugins: [sveltekit()],
build: {
cssMinify: true,
},
}); });