jskelet 0.4.3 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/docs/02-mimari.md +2 -0
- package/docs/04-render-ve-sablonlar.md +9 -5
- package/docs/07-yapilandirma.md +36 -9
- package/docs/08-build.md +7 -0
- package/docs/09-dev-araclari.md +12 -3
- package/docs/10-dagitim.md +5 -2
- package/docs/11-tasima.md +4 -3
- package/docs/README.md +1 -1
- package/docs/en/02-architecture.md +2 -0
- package/docs/en/04-rendering.md +9 -5
- package/docs/en/07-configuration.md +37 -9
- package/docs/en/08-build.md +7 -0
- package/docs/en/09-dev-tools.md +13 -3
- package/docs/en/10-deployment.md +6 -3
- package/docs/en/11-migration.md +4 -3
- package/docs/en/README.md +1 -1
- package/package.json +1 -1
- package/src/client/devtools/overlay.js +233 -18
- package/src/client/devtools/seo.js +628 -0
- package/src/config/defaults.js +26 -0
- package/src/config/index.js +99 -2
- package/src/index.js +1 -0
- package/src/server/create-app.js +9 -0
- package/src/server/dev/devtools.js +7 -0
- package/src/server/image-optimizer.js +338 -0
- package/src/views/helpers/tags.js +52 -5
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,15 @@ one is listed under a **Breaking** heading.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Runtime remote image optimizer: set `images.remote.allowHosts` to proxy
|
|
14
|
+
allowlisted http(s) images through `/_jskelet/image?url=&w=&q=` as resized
|
|
15
|
+
webp (disk cache under `.jskelet/image-cache/`). `image()` rewrites matching
|
|
16
|
+
remote `src` values automatically; `remoteImageUrl()` builds URLs by hand.
|
|
17
|
+
Requires `sharp` at runtime; without it the endpoint 302-redirects to the
|
|
18
|
+
source.
|
|
19
|
+
|
|
11
20
|
### Breaking
|
|
12
21
|
|
|
13
22
|
- The cache admin panel moved to a top-level `admin()` config section at
|
|
@@ -34,6 +43,11 @@ one is listed under a **Breaking** heading.
|
|
|
34
43
|
|
|
35
44
|
### Added
|
|
36
45
|
|
|
46
|
+
- Devtools SEO check: an **SEO** tab in the overlay lists document, heading,
|
|
47
|
+
image, link and social-tag issues with error/warning severity. Optional page
|
|
48
|
+
highlights draw red or yellow boxes around the offending elements; the label
|
|
49
|
+
shows the short title and a click opens the full explanation. Served only in
|
|
50
|
+
development as `/__jskelet/dev/seo.js` beside the overlay.
|
|
37
51
|
- Marketing homepage ops storyboard: Redis L2, `/_jskelet/admin` panel mock and
|
|
38
52
|
Cloudflare purge flow, with tabbed visual scenes animated by the vanilla
|
|
39
53
|
`motion` API (Framer Motion’s non-React package) via an `ops-story` island.
|
package/docs/02-mimari.md
CHANGED
|
@@ -42,6 +42,8 @@ JSkelet bu gözlemi mimarinin merkezine alır:
|
|
|
42
42
|
├─ staticPrecompressed build'de üretilmiş .br/.gz kopyalar (kalite 11)
|
|
43
43
|
├─ express.static public/ altındaki dosyalar
|
|
44
44
|
├─ (dev) devtools yalnızca NODE_ENV=development
|
|
45
|
+
├─ admin (açıksa) /_jskelet/admin
|
|
46
|
+
├─ image optimizer (remote) /_jskelet/image — allowHosts doluysa
|
|
45
47
|
├─ body parser'lar urlencoded 64kb + json 256kb
|
|
46
48
|
├─ rewrites(afterFiles) statik denendikten sonra
|
|
47
49
|
├─ route'lar
|
|
@@ -383,12 +383,16 @@ Davranış:
|
|
|
383
383
|
|
|
384
384
|
- `public/` altındaki yerel raster görseller için build'de üretilen webp
|
|
385
385
|
varyantları (`.jskelet/images.json`) otomatik olarak `srcset` + intrinsic
|
|
386
|
-
`width`/`height` olarak eklenir. Manifest'te olmayan
|
|
387
|
-
|
|
388
|
-
- `
|
|
389
|
-
|
|
386
|
+
`width`/`height` olarak eklenir. Manifest'te olmayan yerel yollar olduğu
|
|
387
|
+
gibi basılır.
|
|
388
|
+
- `images.remote.allowHosts` açıksa uzak `http(s)` URL'leri
|
|
389
|
+
`/_jskelet/image?url=&w=` proxy'sine çevrilir (webp). `width` varsa 1x/2x
|
|
390
|
+
+ config `widths` ile `srcset` üretilir.
|
|
391
|
+
- `srcset` elle verilmişse ya da `unoptimized: true` ise ne manifest ne de
|
|
392
|
+
remote proxy kullanılır.
|
|
390
393
|
- Yalnızca **tek** varyant üretilmişse (kaynak zaten küçükse) `srcset`/`sizes`
|
|
391
|
-
yazılmaz; gürültüden ibaret olurdu.
|
|
394
|
+
yazılmaz; gürültüden ibaret olurdu. Remote'da tek genişlikte bile `src`
|
|
395
|
+
yine optimize URL'dir.
|
|
392
396
|
- `sizes` verilmezse makul bir varsayılan üretilir: görsel kendi intrinsic
|
|
393
397
|
genişliğinden büyütülmez, dar ekranlarda viewport'u kaplar
|
|
394
398
|
(`(max-width: Npx) 100vw, Npx`).
|
package/docs/07-yapilandirma.md
CHANGED
|
@@ -482,24 +482,51 @@ icons: { scan: ["views", "client", "routes", "lib", "content"] }
|
|
|
482
482
|
|
|
483
483
|
## `images`
|
|
484
484
|
|
|
485
|
-
**Tip:**
|
|
486
|
-
|
|
485
|
+
**Tip:**
|
|
486
|
+
`{ widths?: number[], quality?: number, skip?: string[], remote?: { allowHosts: string[], path?: string, maxWidth?: number, cacheMaxAge?: number, fetchTimeoutMs?: number, maxBytes?: number } | false } | false`
|
|
487
|
+
— **Varsayılan:** `{ widths, quality, skip, remote: false }` (remote kapalı)
|
|
488
|
+
|
|
489
|
+
`public/` altındaki png/jpg görsellerin webp varyantlarını **build**'de üretir.
|
|
490
|
+
`remote.allowHosts` verilirse çalışma anında uzak görselleri de proxy eder
|
|
491
|
+
(`/_jskelet/image?url=&w=&q=` → webp).
|
|
492
|
+
|
|
493
|
+
| Alan | Tip | Varsayılan | Anlamı |
|
|
494
|
+
| --- | --- | --- | --- |
|
|
495
|
+
| `widths` | `number[]` | `[400, 640, 960, 1280, 1920]` | Build ve remote `srcset` adayları. Kaynaktan büyük olanlar build'de elenir; kaynağın kendi genişliği (en fazla 1920) her zaman eklenir. |
|
|
496
|
+
| `quality` | `number` | `78` | webp kalitesi. Build'de imzaya girer; remote uçta `q` varsayılanı. |
|
|
497
|
+
| `skip` | `string[]` | `[]` | Build'de taranmayacak **dizin adları**. `assets` ve `fonts` her zaman atlanır. |
|
|
498
|
+
| `remote` | `object \| false` | kapalı | Runtime optimizer. `allowHosts` **zorunlu**; boşsa uç mount edilmez. |
|
|
487
499
|
|
|
488
|
-
`
|
|
500
|
+
### `images.remote`
|
|
489
501
|
|
|
490
502
|
| Alan | Tip | Varsayılan | Anlamı |
|
|
491
503
|
| --- | --- | --- | --- |
|
|
492
|
-
| `
|
|
493
|
-
| `
|
|
494
|
-
| `
|
|
504
|
+
| `allowHosts` | `string[]` | `[]` | Çekilebilecek host'lar. `*.cdn.example.com` sonek jokerini destekler. |
|
|
505
|
+
| `path` | `string` | `/_jskelet/image` | Optimizer GET yolu. |
|
|
506
|
+
| `maxWidth` | `number` | `1920` | `w` üst sınırı. |
|
|
507
|
+
| `cacheMaxAge` | `number` | `2592000` (30 gün) | Yanıt `Cache-Control` max-age (saniye). Disk önbelleği `.jskelet/image-cache/`. |
|
|
508
|
+
| `fetchTimeoutMs` | `number` | `10000` | Upstream fetch zaman aşımı. |
|
|
509
|
+
| `maxBytes` | `number` | `10485760` (10 MiB) | Upstream gövde üst sınırı. |
|
|
495
510
|
|
|
496
|
-
`false` verilirse görsel adımı hiç çalışmaz.
|
|
497
|
-
turunda hiç çalışmaz.
|
|
511
|
+
`false` verilirse görsel adımı hiç çalışmaz. Build adımı `sharp` gerektirir ve
|
|
512
|
+
watch turunda hiç çalışmaz. Remote açıksa `sharp` **runtime**'da da gerekir;
|
|
513
|
+
yoksa optimizer kaynak URL'ye 302 yönlendirir. Ayrıntı: [08-build.md](./08-build.md).
|
|
498
514
|
|
|
499
515
|
```js
|
|
500
|
-
images: {
|
|
516
|
+
images: {
|
|
517
|
+
widths: [400, 800, 1200],
|
|
518
|
+
quality: 82,
|
|
519
|
+
skip: ["indirmeler"],
|
|
520
|
+
remote: {
|
|
521
|
+
allowHosts: ["static.ornek.com", "*.cdn.ornek.com"],
|
|
522
|
+
},
|
|
523
|
+
}
|
|
501
524
|
```
|
|
502
525
|
|
|
526
|
+
`image({ src: "https://static.ornek.com/a.jpg", width: 96, alt: "…" })` bu
|
|
527
|
+
ayarla `src` / `srcset`'i `/_jskelet/image?url=…&w=96` biçimine çevirir.
|
|
528
|
+
Elle URL kurmak için `remoteImageUrl(src, { width })` (`jskelet`).
|
|
529
|
+
|
|
503
530
|
## `clientEnv`
|
|
504
531
|
|
|
505
532
|
**Tip:** `string[]` — **Varsayılan:** `[]`
|
package/docs/08-build.md
CHANGED
|
@@ -290,6 +290,13 @@ değiştirmez ([04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md)).
|
|
|
290
290
|
Bu adım `sharp` gerektirir. Kurulu değilse adım sessizce atlanır ve `image()`
|
|
291
291
|
orijinal dosyaya döner. Watch turunda hiç çalışmaz.
|
|
292
292
|
|
|
293
|
+
## Runtime uzak görsel proxy
|
|
294
|
+
|
|
295
|
+
`images.remote.allowHosts` verilirse `createApp` `/_jskelet/image` ucunu
|
|
296
|
+
mount eder. CMS / CDN kapakları build'e girmediği için `image()` bu host'lardaki
|
|
297
|
+
URL'leri `?url=&w=` biçiminde yeniden yazar; uç sharp ile webp üretir ve
|
|
298
|
+
`.jskelet/image-cache/` altına yazar. Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
|
|
299
|
+
|
|
293
300
|
## Precompress
|
|
294
301
|
|
|
295
302
|
Build çıktısı varlıkların brotli (kalite 11) ve gzip (seviye 9) kopyalarını
|
package/docs/09-dev-araclari.md
CHANGED
|
@@ -170,9 +170,9 @@ basılır:
|
|
|
170
170
|
```
|
|
171
171
|
|
|
172
172
|
Overlay dosyası **build'e dâhil değildir.** Sunucu onu framework paketinden ham
|
|
173
|
-
olarak servis eder;
|
|
174
|
-
|
|
175
|
-
CSS'i ile karışmaz.
|
|
173
|
+
olarak servis eder; bundler yoktur. Aynı dizindeki `seo.js` gibi kardeş
|
|
174
|
+
modüller native ESM import ile yüklenir ve prod çıktısına hiçbir şey eklenmez.
|
|
175
|
+
Tüm arayüz shadow DOM içinde durur, sayfanın CSS'i ile karışmaz.
|
|
176
176
|
|
|
177
177
|
Gösterdikleri:
|
|
178
178
|
|
|
@@ -180,6 +180,14 @@ Gösterdikleri:
|
|
|
180
180
|
(`img`/`script`/`link`), ve sunucudaki `console.error` / `console.warn`
|
|
181
181
|
çıktıları. Sunucu tarafında `console` sarılır, böylece uyarılar terminalde
|
|
182
182
|
kaybolmaz.
|
|
183
|
+
- **SEO:** açık sayfanın istemci tarafı taraması — title ve meta description
|
|
184
|
+
uzunluğu, `html lang`, viewport, canonical, robots/`noindex`, Open Graph ve
|
|
185
|
+
Twitter etiketleri, H1/outline, görsel `alt`, boş linkler ve JSON-LD parse
|
|
186
|
+
hataları. Bulgular panelde listelenir; **Highlight issues on the page**
|
|
187
|
+
açılınca sorunlu elemanların üzerine kırmızı (error) veya sarı (warning)
|
|
188
|
+
dikdörtgenler çizilir, kenarda kısa başlık durur. Etikete (ya da panel
|
|
189
|
+
satırına) tıklanınca ayrıntılı açıklama açılır. Tarama overlay'in yanındaki
|
|
190
|
+
`/seo.js` dosyasındadır; production paketine girmez.
|
|
183
191
|
- **İstekler:** her HTML isteğinin metodu, yolu, durumu, süresi ve
|
|
184
192
|
`X-JSkelet-Cache` değeri. Aynı satırlar terminale de basılır.
|
|
185
193
|
- **Web Vitals:** TTFB, FCP, LCP, CLS, INP, DCL, load, uzun task sayısı ve
|
|
@@ -261,6 +269,7 @@ Rapor katmanı yalnızca development'ta yüklenir, üretim çıktısına hiç gi
|
|
|
261
269
|
| Yol | Metot | İşi |
|
|
262
270
|
| --- | --- | --- |
|
|
263
271
|
| `/overlay.js` | GET | Overlay script'i |
|
|
272
|
+
| `/seo.js` | GET | SEO tarama + sayfa highlight yardımcısı (overlay import eder) |
|
|
264
273
|
| `/logo.png` | GET | Overlay logosu |
|
|
265
274
|
| `/ws` | GET (upgrade) | Canlı kanal: istatistikler, live reload ve CSS hot-swap olayları |
|
|
266
275
|
| `/events` | GET | SSE: yalnızca WebSocket kurulamazsa kullanılan yedek olay akışı |
|
package/docs/10-dagitim.md
CHANGED
|
@@ -97,6 +97,7 @@ ENV HOST=0.0.0.0
|
|
|
97
97
|
|
|
98
98
|
COPY package.json package-lock.json ./
|
|
99
99
|
# sharp ve tailwind yalnızca build zamanı gerekli; çalışma imajına girmesin.
|
|
100
|
+
# images.remote kullanıyorsanız sharp'ı production dependencies'e alın.
|
|
100
101
|
RUN npm ci --omit=dev && npm cache clean --force
|
|
101
102
|
|
|
102
103
|
COPY --from=build /app/jskelet.config.mjs ./jskelet.config.mjs
|
|
@@ -126,9 +127,11 @@ Notlar:
|
|
|
126
127
|
anında yapılıyor. `lib/` yalnızca projenizde varsa kopyalayın.
|
|
127
128
|
- **`.jskelet/` gerekir:** `manifest.json` olmadan `asset()` hash'li URL'leri
|
|
128
129
|
bulamaz ve `jskelet start` build'i baştan çalıştırmaya kalkar.
|
|
129
|
-
- **`sharp` çalışma imajında gerekmez:** yalnızca build zamanı görsel
|
|
130
|
+
- **`sharp` çalışma imajında genelde gerekmez:** yalnızca build zamanı görsel
|
|
130
131
|
optimizasyonu için. `--omit=dev` ile dışarıda kalır (devDependency olarak
|
|
131
|
-
kurulmuşsa).
|
|
132
|
+
kurulmuşsa). **`images.remote` açıksa** sharp runtime bağımlılığıdır —
|
|
133
|
+
production `dependencies`'e alın ya da runtime imajında ayrıca kurun; yoksa
|
|
134
|
+
optimizer kaynak URL'ye 302 yönlendirir.
|
|
132
135
|
- `jskelet start`ı `npx` olmadan çağırmak isterseniz
|
|
133
136
|
`CMD ["node", "node_modules/jskelet/bin/jskelet.mjs", "start"]` de çalışır.
|
|
134
137
|
|
package/docs/11-tasima.md
CHANGED
|
@@ -96,9 +96,10 @@ Bunları taşıma planında baştan hesaba katın:
|
|
|
96
96
|
önce belgeyi hazırlar, `viewTransition` geçişi yumuşatır
|
|
97
97
|
([07](./07-yapilandirma.md)).
|
|
98
98
|
- **Server Actions.** Form gönderimleri normal `app.post(...)` handler'larıdır.
|
|
99
|
-
- **Otomatik görsel optimizasyonu (istek anında).**
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
- **Otomatik görsel optimizasyonu (istek anında).** Yerel `public/` görselleri
|
|
100
|
+
hâlâ build zamanında optimize edilir. Uzak `http(s)` görseller
|
|
101
|
+
`images.remote.allowHosts` verilirse çalışma anında proxy edilir
|
|
102
|
+
(`/_jskelet/image` → webp); config yoksa olduğu gibi basılır.
|
|
102
103
|
|
|
103
104
|
## Yan yana örnek
|
|
104
105
|
|
package/docs/README.md
CHANGED
|
@@ -24,7 +24,7 @@ eşlenik tutuluyor; birini değiştiriyorsan diğerini de değiştir.
|
|
|
24
24
|
| [06-cache.md](./06-cache.md) | `withHtmlCache`, `revalidate`, stale-while-revalidate, cache anahtarı, `X-JSkelet-Cache`, istek içi cache, degraded render, prewarm |
|
|
25
25
|
| [07-yapilandirma.md](./07-yapilandirma.md) | `jskelet.config.mjs` tam referansı, `source` desen sözdizimi, ortam değişkenleri tablosu |
|
|
26
26
|
| [08-build.md](./08-build.md) | Build hattı, manifest, hash'li varlıklar, CSS/Tailwind `@source`, fontlar, ikon sprite, görsel optimizasyonu, precompress |
|
|
27
|
-
| [09-dev-araclari.md](./09-dev-araclari.md) | `jskelet dev` akışı, watch dizinleri, CSS hot-swap, devtools overlay (Alt+D), rapor sayfası, dev gate |
|
|
27
|
+
| [09-dev-araclari.md](./09-dev-araclari.md) | `jskelet dev` akışı, watch dizinleri, CSS hot-swap, devtools overlay (Alt+D, SEO highlight), rapor sayfası, dev gate |
|
|
28
28
|
| [10-dagitim.md](./10-dagitim.md) | Prod build + start, ortam değişkenleri, Docker, ters proxy, sağlık kontrolü |
|
|
29
29
|
| [11-tasima.md](./11-tasima.md) | Next.js'ten taşıma: karşılık tablosu ve adım adım plan |
|
|
30
30
|
| [12-panel-ve-oturum.md](./12-panel-ve-oturum.md) | Kişiye özel sayfalar: `private: true`, imzalı cookie oturumu, CSRF, `fragment()`, parça takası ve form döngüsü |
|
|
@@ -42,6 +42,8 @@ Request
|
|
|
42
42
|
├─ staticPrecompressed .br/.gz copies produced at build (quality 11)
|
|
43
43
|
├─ express.static files under public/
|
|
44
44
|
├─ (dev) devtools only when NODE_ENV=development
|
|
45
|
+
├─ admin (if enabled) /_jskelet/admin
|
|
46
|
+
├─ image optimizer (remote) /_jskelet/image — when allowHosts is set
|
|
45
47
|
├─ body parsers urlencoded 64kb + json 256kb
|
|
46
48
|
├─ rewrites(afterFiles) after static has been tried
|
|
47
49
|
├─ routes
|
package/docs/en/04-rendering.md
CHANGED
|
@@ -389,12 +389,16 @@ Behaviour:
|
|
|
389
389
|
|
|
390
390
|
- For local raster images under `public/`, the webp variants generated at build
|
|
391
391
|
time (`.jskelet/images.json`) are added automatically as `srcset` plus
|
|
392
|
-
intrinsic `width`/`height`.
|
|
393
|
-
|
|
394
|
-
-
|
|
395
|
-
|
|
392
|
+
intrinsic `width`/`height`. Local paths missing from the manifest are emitted
|
|
393
|
+
as-is.
|
|
394
|
+
- When `images.remote.allowHosts` is set, remote `http(s)` URLs are rewritten to
|
|
395
|
+
the `/_jskelet/image?url=&w=` proxy (webp). If `width` is set, `srcset`
|
|
396
|
+
includes 1x/2x plus config `widths`.
|
|
397
|
+
- If `srcset` is given by hand, or `unoptimized: true` is set, neither the
|
|
398
|
+
manifest nor the remote proxy is used.
|
|
396
399
|
- If only **one** variant was produced (because the source is already small),
|
|
397
|
-
`srcset`/`sizes` are not written; they would be pure noise.
|
|
400
|
+
`srcset`/`sizes` are not written; they would be pure noise. For remote images,
|
|
401
|
+
a single width still rewrites `src` to the optimized URL.
|
|
398
402
|
- If `sizes` is not given a reasonable default is produced: the image is not
|
|
399
403
|
scaled beyond its own intrinsic width, and it fills the viewport on narrow
|
|
400
404
|
screens (`(max-width: Npx) 100vw, Npx`).
|
|
@@ -494,24 +494,52 @@ icons: { scan: ["views", "client", "routes", "lib", "content"] }
|
|
|
494
494
|
|
|
495
495
|
## `images`
|
|
496
496
|
|
|
497
|
-
**Type:**
|
|
498
|
-
|
|
497
|
+
**Type:**
|
|
498
|
+
`{ widths?: number[], quality?: number, skip?: string[], remote?: { allowHosts: string[], path?: string, maxWidth?: number, cacheMaxAge?: number, fetchTimeoutMs?: number, maxBytes?: number } | false } | false`
|
|
499
|
+
— **Default:** `{ widths, quality, skip, remote: false }` (remote off)
|
|
499
500
|
|
|
500
|
-
Generates webp variants of
|
|
501
|
+
Generates webp variants of png/jpg files under `public/` at **build** time.
|
|
502
|
+
When `remote.allowHosts` is set, also proxies remote images at runtime
|
|
503
|
+
(`/_jskelet/image?url=&w=&q=` → webp).
|
|
501
504
|
|
|
502
505
|
| Field | Type | Default | Meaning |
|
|
503
506
|
| --- | --- | --- | --- |
|
|
504
|
-
| `widths` | `number[]` | `[400, 640, 960, 1280, 1920]` |
|
|
505
|
-
| `quality` | `number` | `78` | webp quality.
|
|
506
|
-
| `skip` | `string[]` | `[]` | **Directory names** not to scan. `assets` and `fonts` are always skipped. |
|
|
507
|
+
| `widths` | `number[]` | `[400, 640, 960, 1280, 1920]` | Candidates for build and remote `srcset`. Ones larger than the source are dropped at build; the source's own width (at most 1920) is always added. |
|
|
508
|
+
| `quality` | `number` | `78` | webp quality. Part of the build encoder signature; default `q` on the remote endpoint. |
|
|
509
|
+
| `skip` | `string[]` | `[]` | **Directory names** not to scan at build. `assets` and `fonts` are always skipped. |
|
|
510
|
+
| `remote` | `object \| false` | off | Runtime optimizer. `allowHosts` is **required**; empty disables the route. |
|
|
511
|
+
|
|
512
|
+
### `images.remote`
|
|
507
513
|
|
|
508
|
-
|
|
509
|
-
|
|
514
|
+
| Field | Type | Default | Meaning |
|
|
515
|
+
| --- | --- | --- | --- |
|
|
516
|
+
| `allowHosts` | `string[]` | `[]` | Hosts that may be fetched. Supports a `*.cdn.example.com` suffix wildcard. |
|
|
517
|
+
| `path` | `string` | `/_jskelet/image` | Optimizer GET path. |
|
|
518
|
+
| `maxWidth` | `number` | `1920` | Cap for `w`. |
|
|
519
|
+
| `cacheMaxAge` | `number` | `2592000` (30 days) | Response `Cache-Control` max-age (seconds). Disk cache under `.jskelet/image-cache/`. |
|
|
520
|
+
| `fetchTimeoutMs` | `number` | `10000` | Upstream fetch timeout. |
|
|
521
|
+
| `maxBytes` | `number` | `10485760` (10 MiB) | Upstream body size limit. |
|
|
522
|
+
|
|
523
|
+
If `false` is given, neither surface runs. The build step requires `sharp` and
|
|
524
|
+
never runs on a watch pass. With remote enabled, `sharp` is also needed at
|
|
525
|
+
**runtime**; without it the optimizer 302-redirects to the source URL. Details:
|
|
526
|
+
[08-build.md](./08-build.md).
|
|
510
527
|
|
|
511
528
|
```js
|
|
512
|
-
images: {
|
|
529
|
+
images: {
|
|
530
|
+
widths: [400, 800, 1200],
|
|
531
|
+
quality: 82,
|
|
532
|
+
skip: ["downloads"],
|
|
533
|
+
remote: {
|
|
534
|
+
allowHosts: ["static.example.com", "*.cdn.example.com"],
|
|
535
|
+
},
|
|
536
|
+
}
|
|
513
537
|
```
|
|
514
538
|
|
|
539
|
+
`image({ src: "https://static.example.com/a.jpg", width: 96, alt: "…" })`
|
|
540
|
+
rewrites `src` / `srcset` to `/_jskelet/image?url=…&w=96`. To build URLs by
|
|
541
|
+
hand, use `remoteImageUrl(src, { width })` from `jskelet`.
|
|
542
|
+
|
|
515
543
|
## `clientEnv`
|
|
516
544
|
|
|
517
545
|
**Type:** `string[]` — **Default:** `[]`
|
package/docs/en/08-build.md
CHANGED
|
@@ -305,6 +305,13 @@ to the `.jskelet/images.json` manifest. `image()` looks at that manifest and add
|
|
|
305
305
|
This step requires `sharp`. If it is not installed the step is silently skipped
|
|
306
306
|
and `image()` falls back to the original file. It never runs on a watch pass.
|
|
307
307
|
|
|
308
|
+
## Runtime remote image proxy
|
|
309
|
+
|
|
310
|
+
When `images.remote.allowHosts` is set, `createApp` mounts `/_jskelet/image`.
|
|
311
|
+
CMS / CDN covers never enter the build, so `image()` rewrites those host URLs to
|
|
312
|
+
`?url=&w=`; the endpoint encodes webp with sharp and stores files under
|
|
313
|
+
`.jskelet/image-cache/`. Details: [07-configuration.md](./07-configuration.md).
|
|
314
|
+
|
|
308
315
|
## Precompress
|
|
309
316
|
|
|
310
317
|
Produces brotli (quality 11) and gzip (level 9) copies of the built assets:
|
package/docs/en/09-dev-tools.md
CHANGED
|
@@ -173,9 +173,10 @@ by clicking the backdrop. It is only emitted by the layout when
|
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
The overlay file is **not part of the build.** The server serves it raw from the
|
|
176
|
-
framework package; that is why there is no bundler involved
|
|
177
|
-
|
|
178
|
-
inside a shadow DOM and does not mix with
|
|
176
|
+
framework package; that is why there is no bundler involved. It loads sibling
|
|
177
|
+
modules such as `seo.js` with native ESM imports, and it adds nothing to the
|
|
178
|
+
production output. The entire UI lives inside a shadow DOM and does not mix with
|
|
179
|
+
the page's CSS.
|
|
179
180
|
|
|
180
181
|
What it shows:
|
|
181
182
|
|
|
@@ -183,6 +184,14 @@ What it shows:
|
|
|
183
184
|
(`img`/`script`/`link`), and the server's `console.error` / `console.warn`
|
|
184
185
|
output. On the server side `console` is wrapped so warnings do not get lost in
|
|
185
186
|
the terminal.
|
|
187
|
+
- **SEO:** a client-side scan of the current page — title and meta description
|
|
188
|
+
length, `html lang`, viewport, canonical, robots/`noindex`, Open Graph and
|
|
189
|
+
Twitter tags, H1/outline, image `alt`, empty links, and JSON-LD parse errors.
|
|
190
|
+
Findings appear in the panel; turning on **Highlight issues on the page**
|
|
191
|
+
draws red (error) or yellow (warning) boxes on the elements, with a short
|
|
192
|
+
title on the border. Clicking the label (or a row in the panel) opens the
|
|
193
|
+
full explanation. The scan lives in `/seo.js` next to the overlay and is not
|
|
194
|
+
part of the production bundle.
|
|
186
195
|
- **Requests:** the method, path, status, duration and `X-JSkelet-Cache` value
|
|
187
196
|
of every HTML request. The same lines are printed to the terminal too.
|
|
188
197
|
- **Web Vitals:** TTFB, FCP, LCP, CLS, INP, DCL, load, long task count and
|
|
@@ -265,6 +274,7 @@ Under `brand.devBasePath` (default `/__jskelet/dev`):
|
|
|
265
274
|
| Path | Method | Job |
|
|
266
275
|
| --- | --- | --- |
|
|
267
276
|
| `/overlay.js` | GET | The overlay script |
|
|
277
|
+
| `/seo.js` | GET | SEO scan + page highlight helper (imported by the overlay) |
|
|
268
278
|
| `/logo.png` | GET | The overlay logo |
|
|
269
279
|
| `/ws` | GET (upgrade) | Live channel: statistics, live reload and CSS hot-swap events |
|
|
270
280
|
| `/events` | GET | SSE: the fallback event stream, used only when WebSocket cannot be established |
|
package/docs/en/10-deployment.md
CHANGED
|
@@ -98,6 +98,7 @@ ENV HOST=0.0.0.0
|
|
|
98
98
|
|
|
99
99
|
COPY package.json package-lock.json ./
|
|
100
100
|
# sharp and tailwind are only needed at build time; keep them out of the runtime image.
|
|
101
|
+
# If you use images.remote, move sharp to production dependencies.
|
|
101
102
|
RUN npm ci --omit=dev && npm cache clean --force
|
|
102
103
|
|
|
103
104
|
COPY --from=build /app/jskelet.config.mjs ./jskelet.config.mjs
|
|
@@ -127,9 +128,11 @@ Notes:
|
|
|
127
128
|
rendering happens at runtime. Copy `lib/` only if your project has one.
|
|
128
129
|
- **`.jskelet/` is needed:** without `manifest.json`, `asset()` cannot find the
|
|
129
130
|
hashed URLs and `jskelet start` will try to run the build from scratch.
|
|
130
|
-
- **`sharp` is not needed in the runtime image:** it is only for
|
|
131
|
-
optimization. `--omit=dev` leaves it out (if it was installed
|
|
132
|
-
devDependency).
|
|
131
|
+
- **`sharp` is usually not needed in the runtime image:** it is only for
|
|
132
|
+
build-time image optimization. `--omit=dev` leaves it out (if it was installed
|
|
133
|
+
as a devDependency). **If `images.remote` is enabled**, sharp is a runtime
|
|
134
|
+
dependency — move it to production `dependencies` or install it in the
|
|
135
|
+
runtime image; otherwise the optimizer 302-redirects to the source URL.
|
|
133
136
|
- If you would rather call `jskelet start` without `npx`,
|
|
134
137
|
`CMD ["node", "node_modules/jskelet/bin/jskelet.mjs", "start"]` works too.
|
|
135
138
|
|
package/docs/en/11-migration.md
CHANGED
|
@@ -99,9 +99,10 @@ Account for these from the start in your migration plan:
|
|
|
99
99
|
`viewTransition` smooths the transition
|
|
100
100
|
([07](./07-configuration.md)).
|
|
101
101
|
- **Server Actions.** Form submissions are ordinary `app.post(...)` handlers.
|
|
102
|
-
- **Automatic image optimization (at request time).**
|
|
103
|
-
build time
|
|
104
|
-
|
|
102
|
+
- **Automatic image optimization (at request time).** Local `public/` images
|
|
103
|
+
are still optimized at build time. Remote `http(s)` images can be proxied at
|
|
104
|
+
runtime when `images.remote.allowHosts` is set (`/_jskelet/image` → webp);
|
|
105
|
+
without that config they are emitted as-is.
|
|
105
106
|
|
|
106
107
|
## A side-by-side example
|
|
107
108
|
|
package/docs/en/README.md
CHANGED
|
@@ -27,7 +27,7 @@ change one, change the other.
|
|
|
27
27
|
| [06-caching.md](./06-caching.md) | `withHtmlCache`, `revalidate`, stale-while-revalidate, the cache key, `X-JSkelet-Cache`, in-request cache, degraded render, prewarm |
|
|
28
28
|
| [07-configuration.md](./07-configuration.md) | Full `jskelet.config.mjs` reference, the `source` pattern syntax, environment variable table |
|
|
29
29
|
| [08-build.md](./08-build.md) | The build pipeline, the manifest, hashed assets, CSS/Tailwind `@source`, fonts, icon sprite, image optimization, precompress |
|
|
30
|
-
| [09-dev-tools.md](./09-dev-tools.md) | The `jskelet dev` flow, watch directories, CSS hot-swap, devtools overlay (Alt+D), the report page, the dev gate |
|
|
30
|
+
| [09-dev-tools.md](./09-dev-tools.md) | The `jskelet dev` flow, watch directories, CSS hot-swap, devtools overlay (Alt+D, SEO highlight), the report page, the dev gate |
|
|
31
31
|
| [10-deployment.md](./10-deployment.md) | Prod build + start, environment variables, Docker, reverse proxy, health check |
|
|
32
32
|
| [11-migration.md](./11-migration.md) | Migrating from Next.js: the equivalence table and a step-by-step plan |
|
|
33
33
|
| [12-dashboards-and-sessions.md](./12-dashboards-and-sessions.md) | Per-visitor pages: `private: true`, signed cookie sessions, CSRF, `fragment()`, swapping regions and the form loop |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jskelet",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "A framework that feels like no framework: Express 5 + build-time .jsk (or EJS) SSR, vanilla JS islands, Tailwind v4 and an in-process HTML TTL cache.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|