2D Game Engine

Wdrożenie

Dwie konfiguracje Vite, względne base, brak SPA fallback, CSP z hashem, cache immutable i gotowe konfiguracje hostingu.

Dwie konfiguracje#

PlikKomendaPrzeznaczenie
vite.config.tsnpm run devSerwer deweloperski, HMR, /docs
vite.prod.config.tsnpm run buildProdukcja, base z B2D_BASE, jeden chunk, release.json
config/build-meta.tsobaMeta b2d-build, b2d-built-at, b2d-base, b2d-mode

B2D_BASE steruje ścieżką bazową:

bash
npm run build
B2D_BASE=/ npm run build
B2D_BASE=/game/ npm run build

Domyślnie ./ — gra działa w dowolnym podkatalogu bez przebudowy.

Czego pilnujemy#

  1. Względne ścieżki — build nie zawiera absolutnych /assets/….
  2. Brak SPA fallback — nieznane ścieżki zwracają 404.html; gra nie ma routingu po ścieżkach, a przepisanie na index.html psuje względne assets/.
  3. Stan w query stringu — ?example=<id>&lang=<pl|en> przeżywa odświeżenie.
  4. Cache — index.html zawsze no-cache, pliki assets/* z hashem immutable.
  5. HTTPS — wymagane przez audio i część API.
  6. CSP — script-src 'self' 'sha256-…' bez 'unsafe-inline'; hash liczony z faktycznej treści inline skryptu startowego.
  7. MIME — .wasm jako application/wasm, .js jako text/javascript.
  8. Widoczny błąd — brak modułu kończy się ekranem startowym z diagnostyką, nigdy czarną planszą.

Komendy#

bash
npm run build
npm run build:site
npm run build:single
npm run bundle:report
npm run bundle:check
npm run export:game
npm run test:hosting

Eksport z konfiguracjami hostingu#

npm run export:game tworzy release/game (katalog do wgrania w całości) oraz release/game/hosting:

PlikHosting
nginx.confnginx (TLS, CSP, cache, error_page 404)
htaccessApache 2.4 → zmień nazwę na .htaccess
netlify.tomlNetlify
_headersCloudflare Pages i Netlify
vercel.jsonVercel (bez rewrites)
firebase.jsonFirebase Hosting

CHECKSUMS.txt zawiera SHA-256 każdego pliku — po wgraniu porównaj kilka pozycji, żeby wykluczyć niekompletny upload.

Przykład: nginx#

nginxnginx.conf
server {
  listen 443 ssl http2;
  server_name game.example.com;
  root /var/www/game;

  location = /index.html {
    add_header Cache-Control "no-cache";
  }

  location /assets/ {
    add_header Cache-Control "public, max-age=31536000, immutable";
  }

  location ~ \.wasm$ {
    types { application/wasm wasm; }
    add_header Cache-Control "public, max-age=31536000, immutable";
  }

  error_page 404 /404.html;
}

Przykład: Vercel#

jsonvercel.json
{
  "headers": [
    {
      "source": "/assets/(.*)",
      "headers": [
        { "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }
      ]
    },
    {
      "source": "/(.*).wasm",
      "headers": [
        { "key": "Content-Type", "value": "application/wasm" }
      ]
    }
  ]
}

Bez rewrites

Nie dodawaj SPA rewrite (/(.*) → /index.html). Gra żyje pod jednym adresem katalogu i trzyma stan w query stringu — rewrite psuje względne ścieżki assetów.

Testy hostingu#

bash
npm run test:hosting

Osiem scenariuszy w Chromium: HTTP w korzeniu, podkatalog, ścisły CSP, HTTPS z self-signed, cache immutable, odświeżenie stanu, zablokowany bundle i nieznana ścieżka.

Ograniczenia#

  • Eksport desktopowy (Electron/Tauri) odłożony do stabilizacji wersji webowej.
  • Brak routingu po ścieżkach — aplikacja żyje pod jednym adresem katalogu.
  • Testy hostingu wymagają Chromium (Playwright) w CI.