jskelet 0.4.6 → 0.4.8
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 +10 -0
- package/docs/06-cache.md +64 -10
- package/docs/07-yapilandirma.md +24 -1
- package/docs/09-dev-araclari.md +11 -5
- package/docs/en/06-caching.md +65 -13
- package/docs/en/07-configuration.md +24 -1
- package/docs/en/09-dev-tools.md +11 -6
- package/package.json +1 -1
- package/src/client/devtools/overlay.js +194 -5
- package/src/client/devtools/report.js +20 -0
- package/src/client/registry.js +8 -0
- package/src/config/defaults.js +40 -1
- package/src/config/index.js +106 -1
- package/src/http/request-context.js +4 -1
- package/src/index.js +1 -1
- package/src/server/dev/devtools.js +118 -5
- package/src/server/dev/report.js +131 -15
- package/src/server/html-cache.js +14 -0
- package/src/server/prewarm.js +268 -19
- package/src/server/render.js +22 -3
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,16 @@ one is listed under a **Breaking** heading.
|
|
|
10
10
|
|
|
11
11
|
### Added
|
|
12
12
|
|
|
13
|
+
- Dev overlay Errors tab now lists failed SSR and browser `fetch` calls with
|
|
14
|
+
page path, API URL, optional island name, and expandable response-body
|
|
15
|
+
details (JSON instead of `[object Object]`). Server `console.error` /
|
|
16
|
+
`console.warn` records also carry the current page when they fire during
|
|
17
|
+
render.
|
|
18
|
+
- Visit-driven HTML prewarm (`cache().prewarm.onVisit`): after each public
|
|
19
|
+
cacheable page response, same-origin links in the HTML are warmed in the
|
|
20
|
+
background (document order, `perPage` cap). Mutually exclusive with classic
|
|
21
|
+
prewarm (`max` / `priority` / `rotate` / `hooks.prewarmPaths`, etc.) — mixing
|
|
22
|
+
them fails at config load.
|
|
13
23
|
- Runtime remote image optimizer: set `images.remote.allowHosts` to proxy
|
|
14
24
|
allowlisted http(s) images through `/_jskelet/image?url=&w=&q=` as resized
|
|
15
25
|
webp (disk cache under `.jskelet/image-cache/`). `image()` rewrites matching
|
package/docs/06-cache.md
CHANGED
|
@@ -1052,19 +1052,68 @@ yönlenen gerçek bir istekle o edge'in önbelleğine giriyor; sunucudan
|
|
|
1052
1052
|
cache'lememe kararının en sık sebepleri, ve bu panelde `dynamic` olarak
|
|
1053
1053
|
görünür.
|
|
1054
1054
|
|
|
1055
|
-
## Prewarm — açılışta ısıtma
|
|
1055
|
+
## Prewarm — açılışta veya ziyarette ısıtma
|
|
1056
1056
|
|
|
1057
1057
|
Next'teki build-time prerender'ın karşılığı, ama çıktı diske yazılmaz: önbellek
|
|
1058
|
-
süreç belleğinde yaşadığı için ısıtma da süreç ayağa kalkınca
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
tazelenir.
|
|
1058
|
+
süreç belleğinde yaşadığı için ısıtma da süreç ayağa kalkınca (klasik mod) ya
|
|
1059
|
+
da trafik geldikçe (`onVisit`) yapılır. Kazanç aynı — tıklanan / komşu sayfa
|
|
1060
|
+
soğuk render'ı beklemez — fakat veri dondurulmaz; her girdi route'un
|
|
1061
|
+
`revalidate` süresiyle yaşlanır ve stale-while-revalidate ile arkada tazelenir.
|
|
1062
1062
|
|
|
1063
1063
|
Isıtma **gerçek HTTP istekleriyle** yapılır (`http://127.0.0.1:<port>`), çünkü
|
|
1064
1064
|
cache anahtarı, sıkıştırma ve middleware zinciri normal trafikle bire bir aynı
|
|
1065
1065
|
olsun.
|
|
1066
1066
|
|
|
1067
|
-
|
|
1067
|
+
İki mod **karşılıklı dışlayıcıdır**. `cache().prewarm.onVisit` açıksa klasik
|
|
1068
|
+
alanlar (`max`, `priority`, `rotate`, `intervalSeconds`, …) ve
|
|
1069
|
+
`hooks.prewarmPaths` birlikte verilemez — config yüklenirken hata fırlar.
|
|
1070
|
+
Tersi de geçerli: klasik liste ısıtması kullanıyorsanız `onVisit` yazmayın.
|
|
1071
|
+
|
|
1072
|
+
### Mod: `onVisit` — ziyaret edilen sayfanın linkleri
|
|
1073
|
+
|
|
1074
|
+
Bir kullanıcı herkese açık, önbelleklenebilir bir sayfayı (`public` HTML, 200)
|
|
1075
|
+
aldığında framework yanıt HTML'indeki aynı-origin `<a href>` yollarını (üstten
|
|
1076
|
+
alta, `perPage` kadar) kuyruğa alır ve arka planda ısıtır. Bir sonraki tıklama
|
|
1077
|
+
veya aynı sayfaya gelen başka ziyaretçi çoğu zaman `HIT` görür.
|
|
1078
|
+
|
|
1079
|
+
```js
|
|
1080
|
+
// jskelet.config.mjs
|
|
1081
|
+
export default {
|
|
1082
|
+
async cache() {
|
|
1083
|
+
return {
|
|
1084
|
+
html: { "/": 60, "/haber/:slug": 300 },
|
|
1085
|
+
prewarm: {
|
|
1086
|
+
onVisit: {
|
|
1087
|
+
perPage: 20, // sayfa başına en fazla link
|
|
1088
|
+
concurrency: 2, // opsiyonel
|
|
1089
|
+
rps: 4, // opsiyonel; 0 = sınırsız
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
};
|
|
1093
|
+
},
|
|
1094
|
+
};
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
`onVisit: true` de yeterlidir (varsayılan `perPage: 20`).
|
|
1098
|
+
|
|
1099
|
+
Kurallar:
|
|
1100
|
+
|
|
1101
|
+
- Yalnızca `route()` ile giden **public + cache'lenebilir** 200 HTML tetikler;
|
|
1102
|
+
`private`, degraded veya `no-store` yanıtlar link çıkarmaz.
|
|
1103
|
+
- Isıtma isteğinin kendi UA'sı (`brand.prewarmUserAgent`) tetiklemez — sonsuz
|
|
1104
|
+
crawl olmaz.
|
|
1105
|
+
- Zaten taze olan yollar kuyruğa girmez.
|
|
1106
|
+
- `nofollow`, `target="_blank"`, `data-no-prefetch`, `prewarmSkip` ve
|
|
1107
|
+
`navigation.exclude` Speculation Rules ile aynı muafiyetleri paylaşır.
|
|
1108
|
+
- Query string ısıtılmaz (varsayılan cache politikası query'yi dinamik sayar).
|
|
1109
|
+
- Açılışta otomatik tur yoktur; ilk ziyaretçi o sayfa için hâlâ MISS
|
|
1110
|
+
ödeyebilir. Kritik yolları deploy öncesi sıcak tutmak istiyorsanız klasik
|
|
1111
|
+
modu veya readiness + seed tercih edin.
|
|
1112
|
+
- `PREWARM=0` onVisit'i de kapatır. `PREWARM_MAX` / `PREWARM_INTERVAL_SECONDS`
|
|
1113
|
+
/ `PREWARM_DELAY_MS` / `PREWARM_RETRY_DELAY_MS` onVisit ile birlikte
|
|
1114
|
+
kullanılamaz (hata).
|
|
1115
|
+
|
|
1116
|
+
### Mod: klasik — `hooks.prewarmPaths()`
|
|
1068
1117
|
|
|
1069
1118
|
Hangi yolların ısıtılacağını uygulama bildirir; genelde sitemap üreten
|
|
1070
1119
|
fonksiyonun aynısıdır.
|
|
@@ -1089,9 +1138,10 @@ Kurallar:
|
|
|
1089
1138
|
`/api/`, `/_fragment/`, `/__jskelet/`. Oturuma bağlı sayfalar ısıtılmamalı.
|
|
1090
1139
|
- Tekilleştirme **sırayı korur**: `priority` verilmediğinde uygulamanın verdiği
|
|
1091
1140
|
sıra anlamlıdır — en önemli sayfaları başa koyun.
|
|
1092
|
-
- Bu hook tanımlı değilse ısıtma hiç kurulmaz; zamanlayıcı bile açılmaz.
|
|
1141
|
+
- Bu hook tanımlı değilse klasik ısıtma hiç kurulmaz; zamanlayıcı bile açılmaz.
|
|
1142
|
+
(`onVisit` modunda hook **yasaktır**, yukarıya bakın.)
|
|
1093
1143
|
|
|
1094
|
-
### Tur mantığı
|
|
1144
|
+
### Tur mantığı (klasik)
|
|
1095
1145
|
|
|
1096
1146
|
1. Liste toplanır. `max`'tan (varsayılan 400) uzunsa bir dilim seçilir:
|
|
1097
1147
|
`priority` eşleşenler **her turda** başa alınır, kalan yerler kuyruktan
|
|
@@ -1272,8 +1322,12 @@ turunun gerçekten `MISS` → önbellek doldurup doldurmadığını buradan gör
|
|
|
1272
1322
|
fazla `revalidate` + bir tazeleme turudur.
|
|
1273
1323
|
- **Önbellek şişiyor.** Query parametreleri anahtara girdiği için kampanya
|
|
1274
1324
|
parametreleri girdi çoğaltıyor olabilir.
|
|
1275
|
-
- **Isıtma hiç çalışmıyor.** `hooks.prewarmPaths` tanımlı değil,
|
|
1276
|
-
ayarlı ya da `cache().prewarm.enabled === false`.
|
|
1325
|
+
- **Isıtma hiç çalışmıyor.** Klasik modda `hooks.prewarmPaths` tanımlı değil,
|
|
1326
|
+
`PREWARM=0` ayarlı ya da `cache().prewarm.enabled === false`. `onVisit`
|
|
1327
|
+
modunda `listen` sonrası logda `onVisit mode` satırını ve public cache'li
|
|
1328
|
+
bir sayfa gezildiğini doğrulayın.
|
|
1329
|
+
- **Config `onVisit` + `max` / `prewarmPaths` ile düşüyor.** İki mod karşılıklı
|
|
1330
|
+
dışlayıcı; yalnızca birini kullanın.
|
|
1277
1331
|
- **Isıtma turu API'yi 429'a sokuyor.** `rps` verilmemiş. `concurrency`
|
|
1278
1332
|
düşürmek yeterli değil; kotayı koruyan ayar toplam hız. Kalıcı çözüm veri
|
|
1279
1333
|
önbelleği: ikinci turdan sonra ısıtma upstream'e gitmez.
|
package/docs/07-yapilandirma.md
CHANGED
|
@@ -882,6 +882,11 @@ tam cevabı olmadığı — [06-cache.md](./06-cache.md) içinde.
|
|
|
882
882
|
|
|
883
883
|
### `cache().prewarm`
|
|
884
884
|
|
|
885
|
+
İki mod: **klasik** (liste + açılış turu) veya **`onVisit`** (ziyaret edilen
|
|
886
|
+
sayfadaki linkler). Birlikte verilemez — config yüklenirken hata.
|
|
887
|
+
|
|
888
|
+
#### Klasik alanlar
|
|
889
|
+
|
|
885
890
|
| Alan | Tip | Varsayılan | Anlamı |
|
|
886
891
|
| --- | --- | --- | --- |
|
|
887
892
|
| `enabled` | `boolean` | `true` | `false` ise ısıtma yapılmaz (`PREWARM=1` ile ezilebilir) |
|
|
@@ -910,6 +915,24 @@ prewarm: {
|
|
|
910
915
|
}
|
|
911
916
|
```
|
|
912
917
|
|
|
918
|
+
#### `onVisit`
|
|
919
|
+
|
|
920
|
+
| Alan | Tip | Varsayılan | Anlamı |
|
|
921
|
+
| --- | --- | --- | --- |
|
|
922
|
+
| `onVisit` | `true \| false \| object` | kapalı | Ziyaret tabanlı ısıtma |
|
|
923
|
+
| `onVisit.perPage` | `number` | `20` | Sayfa başına üstten alta en fazla link |
|
|
924
|
+
| `onVisit.concurrency` | `number` | klasik ile aynı | Paralel işçi |
|
|
925
|
+
| `onVisit.rps` | `number` | klasik ile aynı | Saniyedeki tavan; `0` sınırsız |
|
|
926
|
+
|
|
927
|
+
```js
|
|
928
|
+
prewarm: {
|
|
929
|
+
onVisit: { perPage: 20, rps: 4 },
|
|
930
|
+
}
|
|
931
|
+
```
|
|
932
|
+
|
|
933
|
+
`hooks.prewarmPaths` ve klasik alanlar (`max`, `priority`, …) `onVisit` ile
|
|
934
|
+
**yasaktır**. Ayrıntı: [06-cache.md](./06-cache.md).
|
|
935
|
+
|
|
913
936
|
Sayısal alanların her biri aynı adı taşıyan ortam değişkeniyle ezilebilir; env
|
|
914
937
|
önceliklidir. Ayrıntı: [06-cache.md](./06-cache.md).
|
|
915
938
|
|
|
@@ -926,7 +949,7 @@ varsayılanına döner ve uyarır — sayfa düşmez.
|
|
|
926
949
|
| `layoutContext` | `({ pathname, metadata }) => object` | Layout local'leri; `lang`, `structuredData`, `extraHead`, `bodyClass` özel yorumlanır | [04](./04-render-ve-sablonlar.md) |
|
|
927
950
|
| `notFound` | `() => object \| null` | 404 sayfa tanımı; `null` ise framework'ün hata sayfası | [03](./03-routing.md) |
|
|
928
951
|
| `error` | `({ status, error }) => object \| string \| null` | 404 dışındaki hata sayfaları (ve `notFound` yoksa 404); sayfa tanımı ya da doğrudan HTML | [03](./03-routing.md) |
|
|
929
|
-
| `prewarmPaths` | `() => string[]` |
|
|
952
|
+
| `prewarmPaths` | `() => string[]` | Klasik ısıtmada ısıtılacak yollar; tanımlı değilse klasik tur kurulmaz. `onVisit` ile birlikte **yasak** | [06](./06-cache.md) |
|
|
930
953
|
|
|
931
954
|
```js
|
|
932
955
|
hooks: {
|
package/docs/09-dev-araclari.md
CHANGED
|
@@ -177,9 +177,13 @@ Tüm arayüz shadow DOM içinde durur, sayfanın CSS'i ile karışmaz.
|
|
|
177
177
|
Gösterdikleri:
|
|
178
178
|
|
|
179
179
|
- **Hatalar:** tarayıcı tarafındaki JS hataları, kaynak yükleme hataları
|
|
180
|
-
(`img`/`script`/`link`),
|
|
181
|
-
çıktılar
|
|
182
|
-
|
|
180
|
+
(`img`/`script`/`link`), sunucudaki `console.error` / `console.warn`
|
|
181
|
+
çıktıları, ve SSR / tarayıcı `fetch` çağrılarının 4xx/5xx ya da ağ
|
|
182
|
+
başarısızlıkları. Her kayıt mümkün olduğunca **sayfa yolu**, **API URL** ve
|
|
183
|
+
(istemcide) **island adı** taşır; yanıt gövdesi **show details** ile açılır —
|
|
184
|
+
`[object Object]` yerine JSON. Sunucu tarafında `console` sarılır, böylece
|
|
185
|
+
uyarılar terminalde kaybolmaz; upstream hataları uygulamanın kendi logger'ı
|
|
186
|
+
stderr'e yazsa bile overlay'e düşer.
|
|
183
187
|
- **SEO:** açık sayfanın istemci tarafı taraması — title ve meta description
|
|
184
188
|
uzunluğu, `html lang`, viewport, canonical, robots/`noindex`, Open Graph ve
|
|
185
189
|
Twitter etiketleri, H1/outline, görsel `alt`, boş linkler ve JSON-LD parse
|
|
@@ -244,9 +248,11 @@ http://localhost:3000/__jskelet/dev/report
|
|
|
244
248
|
gezilmemiş ama ısıtılmış sayfalar da listelenir: SSR tarafı bilinir, istemci
|
|
245
249
|
ölçümleri boş kalır.
|
|
246
250
|
- **Sunucu API çağrıları:** SSR sırasında yapılan dış `fetch` çağrıları — URL,
|
|
247
|
-
host, metot, durum, süre, bayt
|
|
251
|
+
host, metot, durum, süre, bayt, hangi sayfa render edilirken yapıldığı ve
|
|
252
|
+
başarısız cevaplarda gövde özeti. `globalThis.fetch` yalnızca development'ta
|
|
248
253
|
sarılır; üretim yolu dokunulmaz kalır. Kendi sunucumuza yapılan istekler
|
|
249
|
-
(ısıtma, sağlık kontrolü) API sayılmaz.
|
|
254
|
+
(ısıtma, sağlık kontrolü) API sayılmaz. Başarısız çağrılar overlay Errors
|
|
255
|
+
sekmesine de düşer.
|
|
250
256
|
- **Build çıktısı:** manifest'teki her varlığın ham/gzip/brotli boyutu, ve
|
|
251
257
|
esbuild metafile'ından chunk analizi — her çıktının boyutu, hangi kaynaklardan
|
|
252
258
|
oluştuğu, hangi chunk'ları import ettiği. Kaynaklar okunur gruplara indirgenir
|
package/docs/en/06-caching.md
CHANGED
|
@@ -1051,20 +1051,69 @@ before anything else: `Cache-Control: private`, `Set-Cookie` and query string
|
|
|
1051
1051
|
settings are the most common reasons an edge decides not to cache, and they
|
|
1052
1052
|
show up as `dynamic` in this panel.
|
|
1053
1053
|
|
|
1054
|
-
## Prewarm — warming
|
|
1054
|
+
## Prewarm — warming at startup or on visit
|
|
1055
1055
|
|
|
1056
1056
|
The equivalent of Next's build-time prerender, except the output is not written
|
|
1057
|
-
to disk: since the cache lives in process memory, the warm-up
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
stale-while-revalidate.
|
|
1057
|
+
to disk: since the cache lives in process memory, the warm-up happens when the
|
|
1058
|
+
process comes up (classic mode) or as traffic arrives (`onVisit`). The gain is
|
|
1059
|
+
the same — the clicked / neighbouring page does not wait for a cold render —
|
|
1060
|
+
but the data is not frozen; every entry ages with the route's `revalidate` and
|
|
1061
|
+
is refreshed in the background with stale-while-revalidate.
|
|
1062
1062
|
|
|
1063
1063
|
The warm-up is done with **real HTTP requests**
|
|
1064
1064
|
(`http://127.0.0.1:<port>`), so that the cache key, the compression and the
|
|
1065
1065
|
middleware chain are exactly the same as with normal traffic.
|
|
1066
1066
|
|
|
1067
|
-
|
|
1067
|
+
The two modes are **mutually exclusive**. If `cache().prewarm.onVisit` is on,
|
|
1068
|
+
classic fields (`max`, `priority`, `rotate`, `intervalSeconds`, …) and
|
|
1069
|
+
`hooks.prewarmPaths` must not be set together — config load throws. The reverse
|
|
1070
|
+
holds too: if you use classic list warming, do not set `onVisit`.
|
|
1071
|
+
|
|
1072
|
+
### Mode: `onVisit` — links from the page just visited
|
|
1073
|
+
|
|
1074
|
+
When a user receives a public, cacheable page (`public` HTML, 200), the
|
|
1075
|
+
framework takes same-origin `<a href>` paths from the response HTML (top to
|
|
1076
|
+
bottom, up to `perPage`) and warms them in the background. The next click, or
|
|
1077
|
+
another visitor to the same neighbourhood, usually sees a `HIT`.
|
|
1078
|
+
|
|
1079
|
+
```js
|
|
1080
|
+
// jskelet.config.mjs
|
|
1081
|
+
export default {
|
|
1082
|
+
async cache() {
|
|
1083
|
+
return {
|
|
1084
|
+
html: { "/": 60, "/news/:slug": 300 },
|
|
1085
|
+
prewarm: {
|
|
1086
|
+
onVisit: {
|
|
1087
|
+
perPage: 20, // at most this many links per page
|
|
1088
|
+
concurrency: 2, // optional
|
|
1089
|
+
rps: 4, // optional; 0 = unlimited
|
|
1090
|
+
},
|
|
1091
|
+
},
|
|
1092
|
+
};
|
|
1093
|
+
},
|
|
1094
|
+
};
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
`onVisit: true` is enough (default `perPage: 20`).
|
|
1098
|
+
|
|
1099
|
+
Rules:
|
|
1100
|
+
|
|
1101
|
+
- Only **public + cacheable** 200 HTML from `route()` triggers it; `private`,
|
|
1102
|
+
degraded or `no-store` responses do not extract links.
|
|
1103
|
+
- The warmer's own UA (`brand.prewarmUserAgent`) does not trigger — no crawl
|
|
1104
|
+
loop.
|
|
1105
|
+
- Paths that are already fresh are not enqueued.
|
|
1106
|
+
- `nofollow`, `target="_blank"`, `data-no-prefetch`, `prewarmSkip` and
|
|
1107
|
+
`navigation.exclude` share the same exemptions as Speculation Rules.
|
|
1108
|
+
- Query strings are not warmed (default cache policy treats query as dynamic).
|
|
1109
|
+
- There is no automatic startup pass; the first visitor to a page may still pay
|
|
1110
|
+
a MISS. If you need critical paths hot before traffic, prefer classic mode or
|
|
1111
|
+
readiness + a seed.
|
|
1112
|
+
- `PREWARM=0` turns onVisit off too. `PREWARM_MAX` / `PREWARM_INTERVAL_SECONDS`
|
|
1113
|
+
/ `PREWARM_DELAY_MS` / `PREWARM_RETRY_DELAY_MS` cannot be used with onVisit
|
|
1114
|
+
(error).
|
|
1115
|
+
|
|
1116
|
+
### Mode: classic — `hooks.prewarmPaths()`
|
|
1068
1117
|
|
|
1069
1118
|
The application declares which paths get warmed; usually it is the very same
|
|
1070
1119
|
function that produces the sitemap.
|
|
@@ -1090,11 +1139,10 @@ Rules:
|
|
|
1090
1139
|
not be warmed.
|
|
1091
1140
|
- Deduplication **preserves order**: when no `priority` is given, the order the
|
|
1092
1141
|
application provides is meaningful — put the most important pages first.
|
|
1093
|
-
- If this hook is not defined the warm-up is never set up; not even the
|
|
1094
|
-
is started.
|
|
1095
|
-
|
|
1096
|
-
### Round logic
|
|
1142
|
+
- If this hook is not defined the classic warm-up is never set up; not even the
|
|
1143
|
+
timer is started. (In `onVisit` mode the hook is **forbidden** — see above.)
|
|
1097
1144
|
|
|
1145
|
+
### Round logic (classic)
|
|
1098
1146
|
1. The list is collected. If it is longer than `max` (400 by default) a slice is
|
|
1099
1147
|
selected: the paths matching `priority` are taken first **on every round**,
|
|
1100
1148
|
and the remaining slots are filled from the queue.
|
|
@@ -1277,8 +1325,12 @@ filled the cache.
|
|
|
1277
1325
|
lag is at most `revalidate` + one refresh round.
|
|
1278
1326
|
- **The cache is bloating.** Because query parameters go into the key, campaign
|
|
1279
1327
|
parameters may be multiplying entries.
|
|
1280
|
-
- **The warm-up never runs.** `hooks.prewarmPaths` is not
|
|
1281
|
-
is set, or `cache().prewarm.enabled === false`.
|
|
1328
|
+
- **The warm-up never runs.** In classic mode `hooks.prewarmPaths` is not
|
|
1329
|
+
defined, `PREWARM=0` is set, or `cache().prewarm.enabled === false`. In
|
|
1330
|
+
`onVisit` mode check the `onVisit mode` log line after `listen` and that a
|
|
1331
|
+
public cacheable page was visited.
|
|
1332
|
+
- **Config fails with `onVisit` + `max` / `prewarmPaths`.** The two modes are
|
|
1333
|
+
mutually exclusive; use only one.
|
|
1282
1334
|
- **The warm-up round pushes the API into 429.** No `rps` was given. Lowering
|
|
1283
1335
|
`concurrency` is not enough; the setting that protects the quota is the total
|
|
1284
1336
|
rate. The lasting fix is the data cache: after the second round the warm-up
|
|
@@ -902,6 +902,11 @@ edges hold this page" has no exact answer — is in
|
|
|
902
902
|
|
|
903
903
|
### `cache().prewarm`
|
|
904
904
|
|
|
905
|
+
Two modes: **classic** (list + startup pass) or **`onVisit`** (links from the
|
|
906
|
+
page just visited). They cannot be combined — config load throws.
|
|
907
|
+
|
|
908
|
+
#### Classic fields
|
|
909
|
+
|
|
905
910
|
| Field | Type | Default | Meaning |
|
|
906
911
|
| --- | --- | --- | --- |
|
|
907
912
|
| `enabled` | `boolean` | `true` | If `false`, no prewarming happens (can be overridden with `PREWARM=1`) |
|
|
@@ -930,6 +935,24 @@ prewarm: {
|
|
|
930
935
|
}
|
|
931
936
|
```
|
|
932
937
|
|
|
938
|
+
#### `onVisit`
|
|
939
|
+
|
|
940
|
+
| Field | Type | Default | Meaning |
|
|
941
|
+
| --- | --- | --- | --- |
|
|
942
|
+
| `onVisit` | `true \| false \| object` | off | Visit-driven warming |
|
|
943
|
+
| `onVisit.perPage` | `number` | `20` | At most how many links per page (top to bottom) |
|
|
944
|
+
| `onVisit.concurrency` | `number` | same as classic | Parallel workers |
|
|
945
|
+
| `onVisit.rps` | `number` | same as classic | Requests per second cap; `0` unlimited |
|
|
946
|
+
|
|
947
|
+
```js
|
|
948
|
+
prewarm: {
|
|
949
|
+
onVisit: { perPage: 20, rps: 4 },
|
|
950
|
+
}
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
`hooks.prewarmPaths` and classic fields (`max`, `priority`, …) are **forbidden**
|
|
954
|
+
with `onVisit`. Details: [06-caching.md](./06-caching.md).
|
|
955
|
+
|
|
933
956
|
Each numeric field can be overridden by an environment variable of the same
|
|
934
957
|
name; env takes precedence. Details: [06-caching.md](./06-caching.md).
|
|
935
958
|
|
|
@@ -946,7 +969,7 @@ its own default and warns — the page does not go down.
|
|
|
946
969
|
| `layoutContext` | `({ pathname, metadata }) => object` | Layout locals; `lang`, `structuredData`, `extraHead` and `bodyClass` get special treatment | [04](./04-rendering.md) |
|
|
947
970
|
| `notFound` | `() => object \| null` | 404 page definition; if `null`, the framework's error page | [03](./03-routing.md) |
|
|
948
971
|
| `error` | `({ status, error }) => object \| string \| null` | Error pages other than 404 (and 404 when there is no `notFound`); a page definition or HTML directly | [03](./03-routing.md) |
|
|
949
|
-
| `prewarmPaths` | `() => string[]` | Paths
|
|
972
|
+
| `prewarmPaths` | `() => string[]` | Paths for classic prewarm; if omitted, the classic pass is never set up. **Forbidden** with `onVisit` | [06](./06-caching.md) |
|
|
950
973
|
|
|
951
974
|
```js
|
|
952
975
|
hooks: {
|
package/docs/en/09-dev-tools.md
CHANGED
|
@@ -181,9 +181,13 @@ the page's CSS.
|
|
|
181
181
|
What it shows:
|
|
182
182
|
|
|
183
183
|
- **Errors:** browser-side JS errors, resource loading errors
|
|
184
|
-
(`img`/`script`/`link`),
|
|
185
|
-
output
|
|
186
|
-
the
|
|
184
|
+
(`img`/`script`/`link`), the server's `console.error` / `console.warn`
|
|
185
|
+
output, and failed SSR / browser `fetch` calls (4xx/5xx or network). Each
|
|
186
|
+
record carries a **page path**, **API URL**, and (on the client) an **island
|
|
187
|
+
name** when known; the response body opens under **show details** as JSON
|
|
188
|
+
instead of `[object Object]`. On the server side `console` is wrapped so
|
|
189
|
+
warnings do not get lost in the terminal; upstream failures still land in the
|
|
190
|
+
overlay even when the app's own logger writes them only to stderr.
|
|
187
191
|
- **SEO:** a client-side scan of the current page — title and meta description
|
|
188
192
|
length, `html lang`, viewport, canonical, robots/`noindex`, Open Graph and
|
|
189
193
|
Twitter tags, H1/outline, image `alt`, empty links, and JSON-LD parse errors.
|
|
@@ -248,9 +252,10 @@ Its contents:
|
|
|
248
252
|
status of the SSR output. Pages that were never visited but were warmed are
|
|
249
253
|
listed too: the SSR side is known, the client measurements stay empty.
|
|
250
254
|
- **Server API calls:** outbound `fetch` calls made during SSR — URL, host,
|
|
251
|
-
method, status, duration, bytes
|
|
252
|
-
|
|
253
|
-
(warming, health check) do
|
|
255
|
+
method, status, duration, bytes, which page was rendering, and a body summary
|
|
256
|
+
on failures. `globalThis.fetch` is only wrapped in development; the production
|
|
257
|
+
path is left untouched. Requests to our own server (warming, health check) do
|
|
258
|
+
not count as API calls. Failures also appear on the overlay Errors tab.
|
|
254
259
|
- **Build output:** the raw/gzip/brotli size of every asset in the manifest, and
|
|
255
260
|
chunk analysis from esbuild's metafile — the size of each output, which
|
|
256
261
|
sources it is made of, which chunks it imports. Sources are reduced to
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jskelet",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.8",
|
|
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",
|