feat: switch to SSR for live Sanity updates
Migrate from SSG to SSR with @astrojs/node adapter so Sanity CMS changes are reflected immediately without rebuild. Separate ports for Astro SSR (4321) and Fastify API (3000) in production. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7c77ac6c19
commit
1b53e04b5d
42
CLAUDE.md
42
CLAUDE.md
@ -37,7 +37,7 @@ rebours/
|
||||
|
||||
| Couche | Techno |
|
||||
|--------|--------|
|
||||
| Front (SSG) | Astro + HTML/CSS/JS vanilla + GSAP |
|
||||
| Front (SSR) | Astro + HTML/CSS/JS vanilla + GSAP |
|
||||
| CMS | Sanity (headless, hébergé) |
|
||||
| API | Fastify (Node.js) |
|
||||
| Paiement | Stripe Checkout (price_data inline) |
|
||||
@ -65,20 +65,21 @@ STRIPE_SECRET_KEY=sk_test_...
|
||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
|
||||
DOMAIN=http://localhost:4321
|
||||
PORT=8888
|
||||
FASTIFY_PORT=3000 # Port Fastify API (prod)
|
||||
ASTRO_PORT=4321 # Port Astro SSR (prod)
|
||||
```
|
||||
|
||||
### Lancer le projet
|
||||
```bash
|
||||
npm install
|
||||
npm run dev
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
Cela lance en parallèle (via `concurrently`) :
|
||||
- `astro dev` sur http://localhost:4321
|
||||
- `node --watch server.mjs` (mode dev, PORT=8888)
|
||||
- `node --watch server.mjs` (mode dev)
|
||||
|
||||
Le proxy Vite dans `astro.config.mjs` redirige `/api/*` vers `http://127.0.0.1:8888`.
|
||||
Le proxy Vite dans `astro.config.mjs` redirige `/api/*` vers le serveur Fastify.
|
||||
|
||||
### Sanity Studio
|
||||
```bash
|
||||
@ -90,8 +91,8 @@ Accessible sur http://localhost:3333
|
||||
|
||||
### Build
|
||||
```bash
|
||||
npm run build
|
||||
# Génère ./dist/ (fichiers statiques Astro)
|
||||
pnpm build
|
||||
# Génère ./dist/ (serveur Astro SSR + assets client)
|
||||
```
|
||||
|
||||
---
|
||||
@ -116,8 +117,7 @@ Champs principaux :
|
||||
1. Ouvrir Sanity Studio
|
||||
2. Créer un nouveau document "Produit"
|
||||
3. Remplir les champs, uploader l'image
|
||||
4. Publier
|
||||
5. Rebuild le site : `npm run build` + déployer
|
||||
4. Publier → visible immédiatement sur le site (SSR, pas de rebuild nécessaire)
|
||||
|
||||
### Images
|
||||
Les images sont servies via le CDN Sanity avec transformations automatiques.
|
||||
@ -154,12 +154,19 @@ Quand un client clique "Commander" :
|
||||
|
||||
### Serveur : ordinarthur@10.10.0.13
|
||||
|
||||
### Architecture prod
|
||||
### Architecture prod (SSR)
|
||||
```
|
||||
Internet -> Nginx (port 80) -> /var/www/html/rebours/dist/ (statiques)
|
||||
Internet -> Nginx (port 80) -> / -> proxy -> Astro SSR :4321
|
||||
-> /_astro/* -> fichiers statiques (dist/client/)
|
||||
-> /api/* -> proxy -> Fastify :3000
|
||||
```
|
||||
|
||||
### Services systemd
|
||||
| Service | Port | Rôle |
|
||||
|---------|------|------|
|
||||
| `rebours-ssr` | 4321 | Astro SSR (pages dynamiques) |
|
||||
| `rebours` | 3000 | Fastify API (Stripe, checkout) |
|
||||
|
||||
### Variables d'environnement en prod
|
||||
```env
|
||||
SANITY_PROJECT_ID=...
|
||||
@ -167,14 +174,15 @@ SANITY_DATASET=production
|
||||
STRIPE_SECRET_KEY=sk_live_...
|
||||
STRIPE_WEBHOOK_SECRET=whsec_...
|
||||
DOMAIN=https://rebours.studio
|
||||
PORT=3000
|
||||
FASTIFY_PORT=3000
|
||||
ASTRO_PORT=4321
|
||||
```
|
||||
|
||||
### Déploiement
|
||||
```bash
|
||||
npm run build
|
||||
pnpm build
|
||||
scp -r dist/* ordinarthur@10.10.0.13:/tmp/rebours-dist/
|
||||
ssh ordinarthur@10.10.0.13 "sudo cp -r /tmp/rebours-dist/* /var/www/html/rebours/dist/"
|
||||
ssh ordinarthur@10.10.0.13 "sudo rm -rf /var/www/html/rebours/dist && sudo mkdir -p /var/www/html/rebours/dist && sudo cp -r /tmp/rebours-dist/* /var/www/html/rebours/dist/ && sudo chown -R ordinarthur:ordinarthur /var/www/html/rebours/dist && sudo systemctl restart rebours-ssr"
|
||||
```
|
||||
|
||||
Si server.mjs a changé :
|
||||
@ -189,8 +197,8 @@ ssh ordinarthur@10.10.0.13 "sudo cp /tmp/server.mjs /var/www/html/rebours/server
|
||||
|
||||
| URL | Comportement |
|
||||
|-----|-------------|
|
||||
| `/` | Page principale Astro (SSG) |
|
||||
| `/collection/{slug}` | Page produit (SSG), auto-open panel via `window.__OPEN_PANEL__` |
|
||||
| `/` | Page principale Astro (SSR, données Sanity live) |
|
||||
| `/collection/{slug}` | Page produit (SSR), auto-open panel via `window.__OPEN_PANEL__` |
|
||||
| `/success?session_id=...` | Page de confirmation Stripe |
|
||||
| `/robots.txt` | Généré au build |
|
||||
| `/sitemap.xml` | Généré au build depuis Sanity |
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
import node from '@astrojs/node';
|
||||
|
||||
export default defineConfig({
|
||||
output: 'static',
|
||||
output: 'server',
|
||||
adapter: node({ mode: 'standalone' }),
|
||||
outDir: './dist',
|
||||
server: { port: 4321 },
|
||||
vite: {
|
||||
|
||||
30
nginx.conf
30
nginx.conf
@ -2,10 +2,7 @@ server {
|
||||
listen 80;
|
||||
server_name rebours.studio;
|
||||
|
||||
root /var/www/html/rebours/dist;
|
||||
index index.html;
|
||||
|
||||
# ── API proxy → Fastify ──────────────────────────────────────────────────
|
||||
# ── API proxy → Fastify ────────────────<EFBFBD><EFBFBD><EFBFBD>─────────────────────────────────
|
||||
location /api/ {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
@ -14,28 +11,23 @@ server {
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
}
|
||||
|
||||
# ── Cache : Astro hashed → immutable ─────────────────────────────────────
|
||||
# ── Static assets from Astro client build ──────────────────<EFBFBD><EFBFBD><EFBFBD>─────────────
|
||||
location /_astro/ {
|
||||
root /var/www/html/rebours/dist/client;
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
}
|
||||
|
||||
# ── Cache : CSS/JS sans hash → revalidation ─────────────────────────────
|
||||
location ~* \.(css|js)$ {
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
# ── Cache : assets → 7 jours ────────────────────────────────────────────
|
||||
location ~* \.(jpg|jpeg|png|gif|webp|svg|woff2|woff|ttf|ico|mp3)$ {
|
||||
location ~* \.(css|js|jpg|jpeg|png|gif|webp|svg|woff2|woff|ttf|ico|mp3)$ {
|
||||
root /var/www/html/rebours/dist/client;
|
||||
add_header Cache-Control "public, max-age=604800";
|
||||
}
|
||||
|
||||
# ── HTML : jamais caché ──────────────────────────────────────────────────
|
||||
location ~* \.html$ {
|
||||
add_header Cache-Control "no-store";
|
||||
}
|
||||
|
||||
# ── SPA fallback ─────────────────────────────────────────────────────────
|
||||
# ── SSR → Astro Node server ─────────────────────<EFBFBD><EFBFBD><EFBFBD>────────────────────────
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html /index.html;
|
||||
proxy_pass http://127.0.0.1:4321;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,9 +7,11 @@
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"server": "NODE_ENV=production node server.mjs",
|
||||
"start": "NODE_ENV=production node dist/server/entry.mjs",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^9.5.5",
|
||||
"@fastify/cors": "^10.0.2",
|
||||
"@sanity/client": "^7",
|
||||
"@sanity/image-url": "^1",
|
||||
|
||||
133
pnpm-lock.yaml
generated
133
pnpm-lock.yaml
generated
@ -8,6 +8,9 @@ importers:
|
||||
|
||||
.:
|
||||
dependencies:
|
||||
'@astrojs/node':
|
||||
specifier: ^9.5.5
|
||||
version: 9.5.5(astro@5.18.1(@types/node@25.4.0)(jiti@2.6.1)(rollup@4.59.0)(typescript@5.9.3))
|
||||
'@fastify/cors':
|
||||
specifier: ^10.0.2
|
||||
version: 10.1.0
|
||||
@ -47,6 +50,11 @@ packages:
|
||||
'@astrojs/markdown-remark@6.3.11':
|
||||
resolution: {integrity: sha512-hcaxX/5aC6lQgHeGh1i+aauvSwIT6cfyFjKWvExYSxUhZZBBdvCliOtu06gbQyhbe0pGJNoNmqNlQZ5zYUuIyQ==}
|
||||
|
||||
'@astrojs/node@9.5.5':
|
||||
resolution: {integrity: sha512-rtU2BGU5u3SfGURpANfMxVzCIoR86MkaN05ncza9rbtuMKJ/XnRJt/BbyVknDbOJ71hoci0SIsJwKcJR8vvi/A==}
|
||||
peerDependencies:
|
||||
astro: ^5.17.3
|
||||
|
||||
'@astrojs/prism@3.3.0':
|
||||
resolution: {integrity: sha512-q8VwfU/fDZNoDOf+r7jUnMC2//H2l0TuQ6FkGJL8vD8nw/q5KiL3DS1KKBI3QhI9UQhpJ5dc7AtqfbXWuOgLCQ==}
|
||||
engines: {node: 18.20.8 || ^20.3.0 || >=22.0.0}
|
||||
@ -989,6 +997,10 @@ packages:
|
||||
defu@6.1.4:
|
||||
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
|
||||
|
||||
depd@2.0.0:
|
||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
dequal@2.0.3:
|
||||
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
|
||||
engines: {node: '>=6'}
|
||||
@ -1038,12 +1050,19 @@ packages:
|
||||
resolution: {integrity: sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
ee-first@1.1.1:
|
||||
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
|
||||
|
||||
emoji-regex@10.6.0:
|
||||
resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==}
|
||||
|
||||
emoji-regex@8.0.0:
|
||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
||||
|
||||
encodeurl@2.0.0:
|
||||
resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
@ -1069,6 +1088,9 @@ packages:
|
||||
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
escape-html@1.0.3:
|
||||
resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==}
|
||||
|
||||
escape-string-regexp@5.0.0:
|
||||
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
|
||||
engines: {node: '>=12'}
|
||||
@ -1079,6 +1101,10 @@ packages:
|
||||
estree-walker@3.0.3:
|
||||
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
|
||||
|
||||
etag@1.8.1:
|
||||
resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
event-source-polyfill@1.0.31:
|
||||
resolution: {integrity: sha512-4IJSItgS/41IxN5UVAVuAyczwZF7ZIEsM1XAoUzIHA6A+xzusEZUutdXz2Nr+MQPLxfTiCvqE79/C8HT8fKFvA==}
|
||||
|
||||
@ -1149,6 +1175,10 @@ packages:
|
||||
resolution: {integrity: sha512-Wp1zXWPVUPBmfoa3Cqc9ctaKuzKAV6uLstRqlR56kSjplf5uAce+qeyYym7F+PHbGTk+tCEdkCW6RD7DX/gBZw==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
fresh@2.0.0:
|
||||
resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@ -1218,6 +1248,10 @@ packages:
|
||||
http-cache-semantics@4.2.0:
|
||||
resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==}
|
||||
|
||||
http-errors@2.0.1:
|
||||
resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
import-meta-resolve@4.2.0:
|
||||
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
|
||||
|
||||
@ -1423,6 +1457,14 @@ packages:
|
||||
micromark@4.0.2:
|
||||
resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==}
|
||||
|
||||
mime-db@1.54.0:
|
||||
resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
mime-types@3.0.2:
|
||||
resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
mimic-response@3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
@ -1475,6 +1517,10 @@ packages:
|
||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
on-finished@2.4.1:
|
||||
resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
oniguruma-parser@0.12.1:
|
||||
resolution: {integrity: sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==}
|
||||
|
||||
@ -1553,6 +1599,10 @@ packages:
|
||||
radix3@1.1.2:
|
||||
resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==}
|
||||
|
||||
range-parser@1.2.1:
|
||||
resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
readable-stream@3.6.2:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
@ -1663,9 +1713,19 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
send@1.2.1:
|
||||
resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
server-destroy@1.0.1:
|
||||
resolution: {integrity: sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==}
|
||||
|
||||
set-cookie-parser@2.7.2:
|
||||
resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==}
|
||||
|
||||
setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
sharp@0.34.5:
|
||||
resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==}
|
||||
engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
|
||||
@ -1698,6 +1758,10 @@ packages:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
|
||||
statuses@2.0.2:
|
||||
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
string-width@4.2.3:
|
||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
||||
engines: {node: '>=8'}
|
||||
@ -1764,6 +1828,10 @@ packages:
|
||||
resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
toidentifier@1.0.1:
|
||||
resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==}
|
||||
engines: {node: '>=0.6'}
|
||||
|
||||
tree-kill@1.2.2:
|
||||
resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
|
||||
hasBin: true
|
||||
@ -2061,6 +2129,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@astrojs/node@9.5.5(astro@5.18.1(@types/node@25.4.0)(jiti@2.6.1)(rollup@4.59.0)(typescript@5.9.3))':
|
||||
dependencies:
|
||||
'@astrojs/internal-helpers': 0.7.6
|
||||
astro: 5.18.1(@types/node@25.4.0)(jiti@2.6.1)(rollup@4.59.0)(typescript@5.9.3)
|
||||
send: 1.2.1
|
||||
server-destroy: 1.0.1
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@astrojs/prism@3.3.0':
|
||||
dependencies:
|
||||
prismjs: 1.30.0
|
||||
@ -2826,6 +2903,8 @@ snapshots:
|
||||
|
||||
defu@6.1.4: {}
|
||||
|
||||
depd@2.0.0: {}
|
||||
|
||||
dequal@2.0.3: {}
|
||||
|
||||
destr@2.0.5: {}
|
||||
@ -2869,10 +2948,14 @@ snapshots:
|
||||
|
||||
dset@3.1.4: {}
|
||||
|
||||
ee-first@1.1.1: {}
|
||||
|
||||
emoji-regex@10.6.0: {}
|
||||
|
||||
emoji-regex@8.0.0: {}
|
||||
|
||||
encodeurl@2.0.0: {}
|
||||
|
||||
entities@4.5.0: {}
|
||||
|
||||
entities@6.0.1: {}
|
||||
@ -2939,6 +3022,8 @@ snapshots:
|
||||
|
||||
escalade@3.2.0: {}
|
||||
|
||||
escape-html@1.0.3: {}
|
||||
|
||||
escape-string-regexp@5.0.0: {}
|
||||
|
||||
estree-walker@2.0.2: {}
|
||||
@ -2947,6 +3032,8 @@ snapshots:
|
||||
dependencies:
|
||||
'@types/estree': 1.0.8
|
||||
|
||||
etag@1.8.1: {}
|
||||
|
||||
event-source-polyfill@1.0.31: {}
|
||||
|
||||
eventemitter3@5.0.4: {}
|
||||
@ -3020,6 +3107,8 @@ snapshots:
|
||||
dependencies:
|
||||
tiny-inflate: 1.0.3
|
||||
|
||||
fresh@2.0.0: {}
|
||||
|
||||
fsevents@2.3.3:
|
||||
optional: true
|
||||
|
||||
@ -3149,6 +3238,14 @@ snapshots:
|
||||
|
||||
http-cache-semantics@4.2.0: {}
|
||||
|
||||
http-errors@2.0.1:
|
||||
dependencies:
|
||||
depd: 2.0.0
|
||||
inherits: 2.0.4
|
||||
setprototypeof: 1.2.0
|
||||
statuses: 2.0.2
|
||||
toidentifier: 1.0.1
|
||||
|
||||
import-meta-resolve@4.2.0: {}
|
||||
|
||||
inherits@2.0.4: {}
|
||||
@ -3525,6 +3622,12 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
mime-db@1.54.0: {}
|
||||
|
||||
mime-types@3.0.2:
|
||||
dependencies:
|
||||
mime-db: 1.54.0
|
||||
|
||||
mimic-response@3.1.0: {}
|
||||
|
||||
mnemonist@0.40.0:
|
||||
@ -3565,6 +3668,10 @@ snapshots:
|
||||
|
||||
on-exit-leak-free@2.1.2: {}
|
||||
|
||||
on-finished@2.4.1:
|
||||
dependencies:
|
||||
ee-first: 1.1.1
|
||||
|
||||
oniguruma-parser@0.12.1: {}
|
||||
|
||||
oniguruma-to-es@4.3.4:
|
||||
@ -3650,6 +3757,8 @@ snapshots:
|
||||
|
||||
radix3@1.1.2: {}
|
||||
|
||||
range-parser@1.2.1: {}
|
||||
|
||||
readable-stream@3.6.2:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
@ -3820,8 +3929,28 @@ snapshots:
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
send@1.2.1:
|
||||
dependencies:
|
||||
debug: 4.4.3
|
||||
encodeurl: 2.0.0
|
||||
escape-html: 1.0.3
|
||||
etag: 1.8.1
|
||||
fresh: 2.0.0
|
||||
http-errors: 2.0.1
|
||||
mime-types: 3.0.2
|
||||
ms: 2.1.3
|
||||
on-finished: 2.4.1
|
||||
range-parser: 1.2.1
|
||||
statuses: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
server-destroy@1.0.1: {}
|
||||
|
||||
set-cookie-parser@2.7.2: {}
|
||||
|
||||
setprototypeof@1.2.0: {}
|
||||
|
||||
sharp@0.34.5:
|
||||
dependencies:
|
||||
'@img/colour': 1.1.0
|
||||
@ -3881,6 +4010,8 @@ snapshots:
|
||||
|
||||
split2@4.2.0: {}
|
||||
|
||||
statuses@2.0.2: {}
|
||||
|
||||
string-width@4.2.3:
|
||||
dependencies:
|
||||
emoji-regex: 8.0.0
|
||||
@ -3951,6 +4082,8 @@ snapshots:
|
||||
|
||||
toad-cache@3.7.0: {}
|
||||
|
||||
toidentifier@1.0.1: {}
|
||||
|
||||
tree-kill@1.2.2: {}
|
||||
|
||||
trim-lines@3.0.1: {}
|
||||
|
||||
@ -131,7 +131,7 @@ app.get('/api/session/:id', async (request) => {
|
||||
|
||||
// ── Start ───────────────────────────────────────────────────────────────────
|
||||
try {
|
||||
await app.listen({ port: process.env.PORT ?? 3000, host: '0.0.0.0' })
|
||||
await app.listen({ port: process.env.FASTIFY_PORT ?? process.env.PORT ?? 3000, host: '0.0.0.0' })
|
||||
} catch (err) {
|
||||
app.log.error(err)
|
||||
process.exit(1)
|
||||
|
||||
@ -5,7 +5,7 @@ export const sanity = createClient({
|
||||
projectId: import.meta.env.SANITY_PROJECT_ID,
|
||||
dataset: import.meta.env.SANITY_DATASET || 'production',
|
||||
apiVersion: '2024-01-01',
|
||||
useCdn: true,
|
||||
useCdn: false,
|
||||
})
|
||||
|
||||
const builder = imageUrlBuilder(sanity)
|
||||
|
||||
@ -1,26 +1,21 @@
|
||||
---
|
||||
import Base from '../../layouts/Base.astro';
|
||||
import { getPublishedProducts, urlFor } from '../../lib/sanity.mjs';
|
||||
import { getPublishedProducts, getProductBySlug, urlFor } from '../../lib/sanity.mjs';
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const products = await getPublishedProducts();
|
||||
const { slug } = Astro.params;
|
||||
const product = await getProductBySlug(slug);
|
||||
|
||||
return products.map(p => ({
|
||||
params: { slug: p.slug },
|
||||
props: {
|
||||
slug: p.slug,
|
||||
name: p.name,
|
||||
title: p.seoTitle || `REBOURS — ${p.productDisplayName} | Collection 001`,
|
||||
description: p.seoDescription || p.description?.substring(0, 155) || '',
|
||||
ogImage: p.image ? urlFor(p.image).width(1200).url() : '',
|
||||
productName: p.productDisplayName,
|
||||
price: p.price ? String(p.price / 100) : null,
|
||||
availability: p.availability || 'https://schema.org/PreOrder',
|
||||
},
|
||||
}));
|
||||
if (!product) {
|
||||
return Astro.redirect('/');
|
||||
}
|
||||
|
||||
const { slug, title, description, ogImage, name, productName, price, availability } = Astro.props;
|
||||
const name = product.name;
|
||||
const title = product.seoTitle || `REBOURS — ${product.productDisplayName} | Collection 001`;
|
||||
const description = product.seoDescription || product.description?.substring(0, 155) || '';
|
||||
const ogImage = product.image ? urlFor(product.image).width(1200).url() : '';
|
||||
const productName = product.productDisplayName;
|
||||
const price = product.price ? String(product.price / 100) : null;
|
||||
const availability = product.availability || 'https://schema.org/PreOrder';
|
||||
|
||||
const allProducts = await getPublishedProducts();
|
||||
|
||||
@ -109,11 +104,11 @@ const schemaBreadcrumb = {
|
||||
<p id="panel-desc" class="panel-desc"></p>
|
||||
<hr>
|
||||
|
||||
<details class="accordion">
|
||||
<details class="accordion" open>
|
||||
<summary>SPÉCIFICATIONS TECHNIQUES <span>↓</span></summary>
|
||||
<div class="accordion-body" id="panel-specs"></div>
|
||||
</details>
|
||||
<details class="accordion">
|
||||
<details class="accordion" open>
|
||||
<summary>NOTES DE CONCEPTION <span>↓</span></summary>
|
||||
<div class="accordion-body" id="panel-notes"></div>
|
||||
</details>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user