jskelet 0.6.3 → 0.6.4
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/AGENTS.md +136 -136
- package/CHANGELOG.md +628 -620
- package/LICENSE +21 -21
- package/README.md +2 -0
- package/bin/jskelet.mjs +130 -130
- package/docs/01-baslangic.md +291 -291
- package/docs/02-mimari.md +310 -310
- package/docs/03-routing.md +515 -515
- package/docs/04-render-ve-sablonlar.md +667 -661
- package/docs/05-islands.md +486 -486
- package/docs/06-cache.md +1467 -1443
- package/docs/07-yapilandirma.md +1208 -1197
- package/docs/08-build.md +429 -429
- package/docs/09-dev-araclari.md +364 -364
- package/docs/10-dagitim.md +348 -338
- package/docs/12-panel-ve-oturum.md +479 -478
- package/docs/README.md +83 -83
- package/docs/en/01-getting-started.md +298 -298
- package/docs/en/02-architecture.md +329 -329
- package/docs/en/03-routing.md +531 -531
- package/docs/en/04-rendering.md +675 -669
- package/docs/en/05-islands.md +497 -497
- package/docs/en/06-caching.md +1476 -1453
- package/docs/en/07-configuration.md +1229 -1219
- package/docs/en/08-build.md +447 -447
- package/docs/en/09-dev-tools.md +373 -373
- package/docs/en/10-deployment.md +351 -340
- package/docs/en/11-migration.md +398 -398
- package/docs/en/12-dashboards-and-sessions.md +489 -488
- package/docs/en/README.md +87 -87
- package/package.json +137 -137
- package/src/build/ensure-build.mjs +19 -19
- package/src/build/paths.mjs +153 -153
- package/src/build/resolve-peer.mjs +36 -36
- package/src/build/tasks/client.mjs +349 -349
- package/src/build/tasks/css.mjs +235 -235
- package/src/build/tasks/fonts.mjs +146 -146
- package/src/build/tasks/icons.mjs +357 -357
- package/src/build/tasks/images.mjs +244 -244
- package/src/build/tasks/precompress.mjs +78 -78
- package/src/build/tasks/templates.mjs +20 -20
- package/src/client/admin/i18n.js +764 -764
- package/src/client/admin/login.html +74 -74
- package/src/client/admin/panel.css +809 -809
- package/src/client/admin/panel.html +495 -495
- package/src/client/admin/panel.js +1251 -1251
- package/src/client/devtools/report.html +185 -185
- package/src/client/devtools/report.js +745 -745
- package/src/client/devtools/seo.js +628 -628
- package/src/client/dom.js +95 -95
- package/src/client/form.js +192 -192
- package/src/client/index.js +45 -45
- package/src/client/registry.js +305 -305
- package/src/client/safe-image.js +91 -91
- package/src/client/shared-cookie.js +225 -225
- package/src/client/store.js +36 -36
- package/src/client/swap.js +188 -188
- package/src/compile/codegen.js +336 -336
- package/src/compile/compile-all.js +149 -149
- package/src/compile/errors.js +66 -66
- package/src/compile/expr.js +409 -409
- package/src/compile/index.js +17 -17
- package/src/compile/parse.js +541 -541
- package/src/compile/resolve.js +211 -211
- package/src/compile/scan-exports.js +51 -51
- package/src/config/defaults.js +541 -534
- package/src/config/index.js +1500 -1469
- package/src/config/pattern.js +107 -107
- package/src/generate.mjs +163 -163
- package/src/http/control-flow.js +71 -71
- package/src/http/cookies-entry.js +21 -21
- package/src/http/cookies.js +277 -277
- package/src/http/request-cache.js +46 -46
- package/src/http/request-context.js +165 -165
- package/src/http/shared-cookie.js +178 -178
- package/src/index.js +101 -101
- package/src/init.mjs +232 -230
- package/src/migrate/apply.mjs +262 -262
- package/src/migrate/babel.mjs +79 -79
- package/src/migrate/classify.mjs +155 -155
- package/src/migrate/config.mjs +126 -126
- package/src/migrate/fs-walk.mjs +191 -191
- package/src/migrate/parse.mjs +26 -26
- package/src/migrate/scan.mjs +177 -177
- package/src/migrate/transform/expr-source.mjs +168 -168
- package/src/migrate/transform/island.mjs +67 -67
- package/src/migrate/transform/jsx-to-component.mjs +302 -302
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
- package/src/migrate/transform/page-split.mjs +435 -435
- package/src/migrate/write.mjs +81 -81
- package/src/migrate.mjs +171 -171
- package/src/runtime/alias-hooks.mjs +119 -119
- package/src/runtime/register.mjs +4 -4
- package/src/server/admin/actions.js +229 -229
- package/src/server/admin/auth.js +125 -125
- package/src/server/admin/event-log.js +151 -151
- package/src/server/admin/gate.js +209 -209
- package/src/server/admin/inventory.js +188 -188
- package/src/server/admin/mount.js +56 -56
- package/src/server/admin/router.js +216 -216
- package/src/server/admin/snapshot.js +241 -241
- package/src/server/assets.js +147 -147
- package/src/server/auth/handoff.js +309 -309
- package/src/server/cache-blob.js +70 -70
- package/src/server/cache-control.js +45 -0
- package/src/server/cache-deps.js +42 -42
- package/src/server/cache-vary.js +113 -113
- package/src/server/cloudflare.js +607 -607
- package/src/server/create-app.js +366 -366
- package/src/server/data-cache.js +553 -553
- package/src/server/dev/report.js +485 -485
- package/src/server/dev/socket.js +170 -170
- package/src/server/dev/version-check.mjs +139 -139
- package/src/server/disk-cache.js +233 -233
- package/src/server/ejs-adapter.js +59 -59
- package/src/server/html-cache.js +1196 -1196
- package/src/server/image-optimizer.js +500 -500
- package/src/server/logs/access-middleware.js +66 -66
- package/src/server/logs/file-sink.js +193 -193
- package/src/server/logs/pipeline.js +165 -165
- package/src/server/logs/s3-put.js +214 -214
- package/src/server/logs/s3-sink.js +112 -112
- package/src/server/metadata.js +102 -102
- package/src/server/middleware/compression.js +205 -205
- package/src/server/middleware/csrf.js +134 -134
- package/src/server/middleware/dev-gate.js +75 -75
- package/src/server/middleware/headers.js +37 -37
- package/src/server/middleware/redirects.js +32 -32
- package/src/server/middleware/robots-txt.js +341 -341
- package/src/server/middleware/static-precompressed.js +121 -121
- package/src/server/middleware/trailing-slash.js +53 -53
- package/src/server/middleware/upstream-proxy.js +141 -141
- package/src/server/og-image.js +369 -356
- package/src/server/port-guard.js +255 -255
- package/src/server/prewarm.js +1082 -1082
- package/src/server/redis.js +588 -588
- package/src/server/render.js +910 -910
- package/src/server/router.js +157 -157
- package/src/server/status-page.js +265 -265
- package/src/server/upstream-limiter.js +376 -376
- package/src/server/upstream-tracking.js +166 -166
- package/src/shared/cookie-domain.js +66 -66
- package/src/start.mjs +22 -22
- package/src/templates/layout.ejs +30 -30
- package/src/templates/layout.jsk +30 -30
- package/src/version.mjs +31 -31
- package/src/views/components/loader.js +101 -101
- package/src/views/helpers/html.js +102 -102
- package/src/views/helpers/tags.js +375 -375
- package/types/config/defaults.d.ts +6 -0
- package/types/config/index.d.ts +6 -0
- package/types/server/cache-control.d.ts +28 -0
- package/types/server/og-image.d.ts +5 -0
package/docs/09-dev-araclari.md
CHANGED
|
@@ -1,364 +1,364 @@
|
|
|
1
|
-
# 09 — Geliştirme araçları
|
|
2
|
-
|
|
3
|
-
Bu belge `jskelet dev`in ne yaptığını ve neden böyle yaptığını anlatır: iki alt
|
|
4
|
-
sürecin yönetimi, terminal çıktısının biçimi, izlenen dizinler ve `node --watch`
|
|
5
|
-
yerine kendi watcher'ının yazılma sebebi, CSS hot-swap ile tam yenileme ayrımı,
|
|
6
|
-
`Alt+D` ile açılan devtools overlay'i, detaylı rapor sayfası ve `DEV_TOKEN` ile
|
|
7
|
-
kurulan dev gate. Build adımlarının kendisi [08-build.md](./08-build.md)'de.
|
|
8
|
-
|
|
9
|
-
## `jskelet dev` akışı
|
|
10
|
-
|
|
11
|
-
Komut tek terminalde iki uzun ömürlü alt süreç yönetir:
|
|
12
|
-
|
|
13
|
-
```
|
|
14
|
-
jskelet dev
|
|
15
|
-
├─ build watch node src/build/build.mjs --watch
|
|
16
|
-
└─ sunucu node [--env-file=.env] --import <register.mjs> src/start.mjs
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
`NODE_ENV=development` ataması platformdan bağımsız olarak burada yapılır —
|
|
20
|
-
`cross-env` gerekmez. Alt süreçlere ayrıca `JSKELET_CHILD=1` (build banner'ını
|
|
21
|
-
bastırır) ve TTY varsa `JSKELET_COLOR=1` (borulanmış çıktıda renk zorlar)
|
|
22
|
-
geçirilir.
|
|
23
|
-
|
|
24
|
-
Port (`PORT`, varsayılan `3000`) doluysa sunucu **başlamaz**; hata satırında
|
|
25
|
-
PID ve `--murder` ipucu vardır. `jskelet dev --murder` dinleyiciyi öldürüp aynı
|
|
26
|
-
porta bağlanır (başka bir terminalde unutulmuş süreç için).
|
|
27
|
-
|
|
28
|
-
Açılış sırası: banner → build adımları → sunucu hazır → `Ready` özeti. Özet hem
|
|
29
|
-
build hem sunucu hazır olduğunda basılır; aksi hâlde arkadan gelen build
|
|
30
|
-
satırlarının arasında kalıyordu.
|
|
31
|
-
|
|
32
|
-
Sunucunun hazır olduğu, `startServer` içindeki tek satırdan anlaşılır:
|
|
33
|
-
|
|
34
|
-
```
|
|
35
|
-
jskelet → http://localhost:3000 (development)
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Bu satırın biçimi bir sözleşmedir; dev script'i onu ayrıştırıp özet satırını ona
|
|
39
|
-
göre basar.
|
|
40
|
-
|
|
41
|
-
### Terminal çıktısının biçimi
|
|
42
|
-
|
|
43
|
-
Alt süreçlerin çıktısı olduğu gibi akmaz. İki bölge vardır ve karışmazlar:
|
|
44
|
-
|
|
45
|
-
1. **Başlangıç:** banner, hizalı build satırları, `Ready` özeti.
|
|
46
|
-
2. **Çalışma anı:** zaman damgalı, tek satırlık olaylar (HTTP istekleri, CSS
|
|
47
|
-
rebuild, sunucu restart).
|
|
48
|
-
|
|
49
|
-
Hata yığınları çerçeveli bir kutuya dönüşür: yığın satırları parça parça geldiği
|
|
50
|
-
için kısa bir sessizlikten (60 ms) sonra toplanır, hata adı ve mesajı
|
|
51
|
-
ayrıştırılır, ilk üç frame gösterilir ve proje kökü `.` ile kısaltılır. Kendi
|
|
52
|
-
framework'ünü geliştirirken hatanın akış içinde kaybolmaması gerçekten fark
|
|
53
|
-
yaratan ayrıntı.
|
|
54
|
-
|
|
55
|
-
Renk anlam taşır: `✓` yeşil, `✖` kırmızı, `⚠` sarı, `↻` cyan; süre ve yol gri.
|
|
56
|
-
Dekoratif renk kullanılmaz. `NO_COLOR` ayarlıysa renk hiç kullanılmaz.
|
|
57
|
-
|
|
58
|
-
`Ctrl+C` (SIGINT/SIGTERM) tüm alt süreçleri kapatır. Bir alt süreç sıfır dışı
|
|
59
|
-
kodla çıkarsa (beklenen restart hariç) hata basılır ve dev süreci de kapanır.
|
|
60
|
-
|
|
61
|
-
## Watch dizinleri
|
|
62
|
-
|
|
63
|
-
Sunucu yeniden başlatma framework'ün kendi watcher'ıyla yönetilir.
|
|
64
|
-
|
|
65
|
-
```js
|
|
66
|
-
WATCH_DIRS = [
|
|
67
|
-
config.dirs.routes,
|
|
68
|
-
config.dirs.views,
|
|
69
|
-
<root>/lib,
|
|
70
|
-
...config.watch, // jskelet.config.mjs → watch
|
|
71
|
-
]
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Ayrıca `jskelet.config.mjs` dosyasının kendisi izlenir: config değişince hem
|
|
75
|
-
sunucu hem build yeni ayarlarla açılmalı.
|
|
76
|
-
|
|
77
|
-
İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.jsk`, `.ejs`.
|
|
78
|
-
|
|
79
|
-
`views` de izlenir çünkü bileşenlerin çoğu `views/components/**.js` içinde ve bu
|
|
80
|
-
modüller sunucuya bir kez import edildiği için, restart olmadan yapılan
|
|
81
|
-
değişiklik tarayıcıya hiç yansımıyordu (şablon düzenleyip "hiçbir şey değişmedi"
|
|
82
|
-
hissi buradan geliyor).
|
|
83
|
-
|
|
84
|
-
`client/` ve `styles/` bu listede **yoktur**: onları esbuild ve CSS watcher'ları
|
|
85
|
-
kendi içinde hallediyor ([08-build.md](./08-build.md)).
|
|
86
|
-
|
|
87
|
-
Bir dizin izlenemezse uyarı basılır ve o dizinde otomatik restart olmaz; gerisi
|
|
88
|
-
çalışır.
|
|
89
|
-
|
|
90
|
-
### Neden `node --watch` kullanılmadı
|
|
91
|
-
|
|
92
|
-
`--watch-path` verilse bile Node bu kurulumda proje kökünü izliyordu. Build
|
|
93
|
-
çıktısı (`public/assets`, `manifest.json`) ya da dev araçlarının günlüğü
|
|
94
|
-
yazıldığında sunucu boşuna yeniden başlıyor, hatta kendini besleyen bir döngü
|
|
95
|
-
kuruluyordu: restart → açılış uyarısı → yazma → restart.
|
|
96
|
-
|
|
97
|
-
Kendi watcher'ı üç şey yapar:
|
|
98
|
-
|
|
99
|
-
1. **Yalnızca sunucu kaynaklarını izler.**
|
|
100
|
-
2. **Değişiklikleri birleştirir** (250 ms) ve hangi dosyaların değiştiğini
|
|
101
|
-
bildirir.
|
|
102
|
-
3. **Sahte olayları eler.** Windows'ta `fs.watch` bir dosya yazıldığında
|
|
103
|
-
komşuları için de olay üretebiliyor; `mtime` karşılaştırılmazsa tek kaydetme
|
|
104
|
-
iki restart'a dönüşüyordu. Açılışta mevcut zamanlar önden okunur, böylece ilk
|
|
105
|
-
sahte olay da elenir.
|
|
106
|
-
|
|
107
|
-
Restart satırı değişen dosyayı ya da sayısını gösterir:
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
21:04:12 ↻ server restarting… routes/10-pages.mjs
|
|
111
|
-
21:04:12 server restarted 412ms
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
`JSKELET_VERBOSE=1` ayarlıysa birden fazla dosya değiştiğinde tamamı listelenir.
|
|
115
|
-
|
|
116
|
-
## CSS hot-swap ve tam yenileme
|
|
117
|
-
|
|
118
|
-
Dev sunucusu `.jskelet/manifest.json` dosyasını izler ve olayları canlı kanal
|
|
119
|
-
(`<devBasePath>/ws`) üzerinden tarayıcıya yayınlar. Manifest her build turunda
|
|
120
|
-
yeniden yazıldığı için değişiklik tespiti manifest üzerinden yapılır.
|
|
121
|
-
|
|
122
|
-
| Değişen | Davranış |
|
|
123
|
-
| --- | --- |
|
|
124
|
-
| Yalnızca `.css` anahtarları | **CSS hot-swap:** değişen her stylesheet takas edilir, sayfa yenilenmez. Durum ve kaydırma korunur. |
|
|
125
|
-
| `main.js`, sprite, başka bir varlık ya da birden fazla anahtar | **Tam yenileme** |
|
|
126
|
-
|
|
127
|
-
Her iki durumda önce HTML önbelleği temizlenir: saklanan HTML eski hash'li varlık
|
|
128
|
-
URL'lerini taşıyor olur ve temizlenmezse sayfa silinmiş dosyayı istemeye devam
|
|
129
|
-
eder.
|
|
130
|
-
|
|
131
|
-
Manifest olayları 120 ms birleştirilir. Watch desteklenmiyorsa live reload devre
|
|
132
|
-
dışı kalır ve gerisi çalışır.
|
|
133
|
-
|
|
134
|
-
Sunucu yeniden başladığında overlay bunu **boot kimliğinden** anlar: her süreç
|
|
135
|
-
kendine özgü bir `boot` değeri yayınlar, overlay değişikliği görüp "restarted"
|
|
136
|
-
bilgisini gösterir ve kendi durumunu sıfırlamaz.
|
|
137
|
-
|
|
138
|
-
## Canlı kanal
|
|
139
|
-
|
|
140
|
-
Overlay'e giden her şey — istatistikler, live reload ve CSS hot-swap olayları —
|
|
141
|
-
tek bir WebSocket üzerinden gelir (`<devBasePath>/ws`). Panel eskiden
|
|
142
|
-
istatistikleri iki saniyede bir çekiyordu; açık her sekme, panel kapalıyken bile
|
|
143
|
-
sunucuya sürekli istek atıyordu. Artık sunucu değişiklik oldukça iter: bir istek
|
|
144
|
-
ya da hata kaydedildiğinde (120 ms birleştirilerek), ısıtma sürerken saniyede
|
|
145
|
-
ve zamana bağlı alanlar (uptime, bellek, ısıtma sayacı) tazelensin diye iki
|
|
146
|
-
saniyede bir. Kalp atışı bilinçli olarak ısıtmadan bağımsız: kanalın temposu bir
|
|
147
|
-
arka plan işine göre değişirse panel de o işin ritmine bağlanmış olur. Bağlı
|
|
148
|
-
panel yoksa hiçbir şey hesaplanmaz.
|
|
149
|
-
|
|
150
|
-
El sıkışma HTTP `upgrade` olayında geçtiği ve o olay middleware zincirine hiç
|
|
151
|
-
uğramadığı için kanal `listen` sonrası doğrudan sunucuya bağlanır
|
|
152
|
-
(`attachDevSocket`). Sunucu tarafı `ws` gibi bir bağımlılık kullanmaz: yalnızca
|
|
153
|
-
sunucu→istemci metin çerçevesi yazmak ve istemcinin ping/close çerçevelerini
|
|
154
|
-
yanıtlamak gerekiyor.
|
|
155
|
-
|
|
156
|
-
Soket kurulup sonra düşerse — yani sunucu yeniden başlıyorsa — yarım saniyede
|
|
157
|
-
bir yeniden bağlanır ve gösterge bu sırada "bağlantı yok" der. Hiç açılamazsa
|
|
158
|
-
aralığı kademeli açarak dört kez denenir; sayfa, sunucunun yeniden başlama
|
|
159
|
-
penceresinde açılmış olabilir ve tek bir başarısızlık kanalın çalışmadığı
|
|
160
|
-
anlamına gelmez. Denemeler de tutmazsa (araya giren bir proxy WebSocket'i
|
|
161
|
-
geçirmiyor olabilir) overlay eski yola düşer: `/events` SSE akışı + `/stats`
|
|
162
|
-
yoklaması.
|
|
163
|
-
|
|
164
|
-
## Devtools overlay
|
|
165
|
-
|
|
166
|
-
Sağ altta yüzen bir baloncuk; `Alt+D` ile açılır, `Esc` ya da karartma alanına
|
|
167
|
-
tıklamak kapatır. Yalnızca `NODE_ENV=development` iken layout tarafından
|
|
168
|
-
basılır:
|
|
169
|
-
|
|
170
|
-
```ejs
|
|
171
|
-
<% if (devtools) { %>
|
|
172
|
-
<script type="module" src="<%= devBasePath %>/overlay.js"></script>
|
|
173
|
-
<% } %>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Overlay dosyası **build'e dâhil değildir.** Sunucu onu framework paketinden ham
|
|
177
|
-
olarak servis eder; bundler yoktur. Aynı dizindeki `seo.js` gibi kardeş
|
|
178
|
-
modüller native ESM import ile yüklenir ve prod çıktısına hiçbir şey eklenmez.
|
|
179
|
-
Tüm arayüz shadow DOM içinde durur, sayfanın CSS'i ile karışmaz.
|
|
180
|
-
|
|
181
|
-
Gösterdikleri:
|
|
182
|
-
|
|
183
|
-
- **Hatalar:** tarayıcı tarafındaki JS hataları, kaynak yükleme hataları
|
|
184
|
-
(`img`/`script`/`link`), sunucudaki `console.error` / `console.warn`
|
|
185
|
-
çıktıları, ve SSR / tarayıcı `fetch` çağrılarının 4xx/5xx ya da ağ
|
|
186
|
-
başarısızlıkları. Her kayıt mümkün olduğunca **sayfa yolu**, **API URL** ve
|
|
187
|
-
(istemcide) **island adı** taşır; yanıt gövdesi **show details** ile açılır —
|
|
188
|
-
`[object Object]` yerine JSON. Sunucu tarafında `console` sarılır, böylece
|
|
189
|
-
uyarılar terminalde kaybolmaz; upstream hataları uygulamanın kendi logger'ı
|
|
190
|
-
stderr'e yazsa bile overlay'e düşer.
|
|
191
|
-
- **SEO:** açık sayfanın istemci tarafı taraması — title ve meta description
|
|
192
|
-
uzunluğu, `html lang`, viewport, canonical, robots/`noindex`, Open Graph ve
|
|
193
|
-
Twitter etiketleri, H1/outline, görsel `alt`, boş linkler ve JSON-LD parse
|
|
194
|
-
hataları. Bulgular panelde listelenir; **Highlight issues on the page**
|
|
195
|
-
açılınca sorunlu elemanların üzerine kırmızı (error) veya sarı (warning)
|
|
196
|
-
dikdörtgenler çizilir, kenarda kısa başlık durur. Etikete (ya da panel
|
|
197
|
-
satırına) tıklanınca ayrıntılı açıklama açılır. Tarama overlay'in yanındaki
|
|
198
|
-
`/seo.js` dosyasındadır; production paketine girmez.
|
|
199
|
-
- **İstekler:** her HTML isteğinin metodu, yolu, durumu, süresi ve
|
|
200
|
-
`X-JSkelet-Cache` değeri. Aynı satırlar terminale de basılır.
|
|
201
|
-
- **Web Vitals:** TTFB, FCP, LCP, CLS, INP, DCL, load, uzun task sayısı ve
|
|
202
|
-
bloke süresi.
|
|
203
|
-
- **Prewarm:** ısıtma turunun ilerlemesi; panelden elle tetiklenebilir, tek tek
|
|
204
|
-
yollar tekrar denenebilir.
|
|
205
|
-
- **Süreç:** pid, Node sürümü, uptime, RSS ve heap kullanımı.
|
|
206
|
-
- **Sürüm:** kurulu JSkelet sürümü ve npm'deki `latest` ile karşılaştırması.
|
|
207
|
-
Yeni bir sürüm varsa **Server** sekmesinde `update` rozeti ve yükseltme
|
|
208
|
-
komutunu kopyalayan bir satır çıkar. Yoklama açılıştan 1,5 saniye sonra bir
|
|
209
|
-
kez yapılır, sonucu 6 saat boyunca `os.tmpdir()` içinde saklanır ve ağ yoksa
|
|
210
|
-
sessizce atlanır. `JSKELET_VERSION_CHECK=0` ile tamamen kapatılır.
|
|
211
|
-
|
|
212
|
-
Isıtma istekleri (`user-agent: jskelet-prewarm`) hem terminalden hem istek
|
|
213
|
-
listesinden filtrelenir: yüzlerce istek görünümü doldurmasın. İlerleme baloncuğun
|
|
214
|
-
yanındaki rozette görünür.
|
|
215
|
-
|
|
216
|
-
### Durum neden `os.tmpdir()`'e yazılıyor
|
|
217
|
-
|
|
218
|
-
İstek ve hata kayıtları süreç belleğinde durursa her yeniden başlatmada geçmiş
|
|
219
|
-
silinir ve overlay boşalır. Bu yüzden kayıtlar restart'lar arasında bir dosyada
|
|
220
|
-
taşınır.
|
|
221
|
-
|
|
222
|
-
Dosya **proje ağacına yazılmaz**: her yazma watcher'ı tetikleyip sunucuyu
|
|
223
|
-
yeniden başlatıyordu ve bu kendini besleyen bir döngü kuruyordu (restart →
|
|
224
|
-
açılış uyarısı → yazma → restart). Bunun yerine dosya
|
|
225
|
-
`os.tmpdir()/jskelet-devtools-<proje kökünün hash'i>.json` yoluna yazılır;
|
|
226
|
-
hash sayesinde aynı makinede birden fazla JSKelet projesi birbirinin kaydını
|
|
227
|
-
ezmez.
|
|
228
|
-
|
|
229
|
-
Yazma her istekte değil, 300 ms sessizlikten sonra yapılır ve başarısızlığı dev
|
|
230
|
-
akışını durdurmaz. En fazla 50 istek ve 50 hata tutulur.
|
|
231
|
-
|
|
232
|
-
Panelin açık/kapalı durumu, aktif sekmesi ve tarayıcı hata günlüğü ise sekme
|
|
233
|
-
belleğinde (`sessionStorage`) saklanır, böylece yenileme sonrası panel aynı
|
|
234
|
-
sekmeyle geri gelir.
|
|
235
|
-
|
|
236
|
-
## Rapor sayfası
|
|
237
|
-
|
|
238
|
-
Baloncuk anlık durumu gösterir; rapor sayfası sitenin tamamına bakan bir görünüm
|
|
239
|
-
üretir. Adres:
|
|
240
|
-
|
|
241
|
-
```
|
|
242
|
-
http://localhost:3000/__jskelet/dev/report
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
(`brand.devBasePath` değiştirilmişse ona göre.)
|
|
246
|
-
|
|
247
|
-
İçeriği:
|
|
248
|
-
|
|
249
|
-
- **Sayfalar:** gezilen her sayfanın Web Vitals ölçümleri, kaynak sayısı ve
|
|
250
|
-
toplam bayt (tür kırılımıyla), island durumu (kaç tanesi hazır, adları),
|
|
251
|
-
tarayıcıdaki API çağrıları ve SSR çıktısının boyutu/süresi/cache durumu. Hiç
|
|
252
|
-
gezilmemiş ama ısıtılmış sayfalar da listelenir: SSR tarafı bilinir, istemci
|
|
253
|
-
ölçümleri boş kalır.
|
|
254
|
-
- **Sunucu API çağrıları:** SSR sırasında yapılan dış `fetch` çağrıları — URL,
|
|
255
|
-
host, metot, durum, süre, bayt, hangi sayfa render edilirken yapıldığı ve
|
|
256
|
-
başarısız cevaplarda gövde özeti. `globalThis.fetch` yalnızca development'ta
|
|
257
|
-
sarılır; üretim yolu dokunulmaz kalır. Kendi sunucumuza yapılan istekler
|
|
258
|
-
(ısıtma, sağlık kontrolü) API sayılmaz. Başarısız çağrılar overlay Errors
|
|
259
|
-
sekmesine de düşer.
|
|
260
|
-
- **Build çıktısı:** manifest'teki her varlığın ham/gzip/brotli boyutu, ve
|
|
261
|
-
esbuild metafile'ından chunk analizi — her çıktının boyutu, hangi kaynaklardan
|
|
262
|
-
oluştuğu, hangi chunk'ları import ettiği. Kaynaklar okunur gruplara indirgenir
|
|
263
|
-
(paket adı ya da üst klasör), böylece "bu chunk'ın 40 kB'ı hangi kütüphaneden"
|
|
264
|
-
sorusu yanıtlanabilir.
|
|
265
|
-
- **HTML önbelleği:** girdi sayısı ve döküm (anahtar, bayt, durum, bayat mı, kaç
|
|
266
|
-
saniye sonra dolacak, hangi encoding'ler saklanmış).
|
|
267
|
-
- **Prewarm:** son turun tam sonucu.
|
|
268
|
-
- **İstek ve hata günlükleri.**
|
|
269
|
-
|
|
270
|
-
Ölçümler tarayıcı sekmesinde değil sunucuda durur; sıfırlama da sunucudan
|
|
271
|
-
yapılır. Boyut hesapları dosya değişmedikçe tekrarlanmaz.
|
|
272
|
-
|
|
273
|
-
Rapor katmanı yalnızca development'ta yüklenir, üretim çıktısına hiç girmez.
|
|
274
|
-
|
|
275
|
-
## Dev uçları
|
|
276
|
-
|
|
277
|
-
`brand.devBasePath` (varsayılan `/__jskelet/dev`) altında:
|
|
278
|
-
|
|
279
|
-
| Yol | Metot | İşi |
|
|
280
|
-
| --- | --- | --- |
|
|
281
|
-
| `/overlay.js` | GET | Overlay script'i |
|
|
282
|
-
| `/seo.js` | GET | SEO tarama + sayfa highlight yardımcısı (overlay import eder) |
|
|
283
|
-
| `/logo.png` | GET | Overlay logosu |
|
|
284
|
-
| `/ws` | GET (upgrade) | Canlı kanal: istatistikler, live reload ve CSS hot-swap olayları |
|
|
285
|
-
| `/events` | GET | SSE: yalnızca WebSocket kurulamazsa kullanılan yedek olay akışı |
|
|
286
|
-
| `/stats` | GET | Anlık istatistikler; aynı yedek yolun veri ucu |
|
|
287
|
-
| `/report` | GET | Rapor sayfası (HTML) |
|
|
288
|
-
| `/report.js` | GET | Rapor sayfasının script'i |
|
|
289
|
-
| `/report/data` | GET | Raporun tek veri kaynağı (JSON) |
|
|
290
|
-
| `/vitals` | POST | Overlay'in gönderdiği ölçüm paketi |
|
|
291
|
-
| `/report/clear` | POST | Sayfa ölçümlerini ve sunucu API kayıtlarını sıfırlar |
|
|
292
|
-
| `/prewarm` | POST | Isıtmayı elle tetikler. Gövdede `paths` varsa yalnızca o yollar; ısıtma zaten çalışıyorsa 409. |
|
|
293
|
-
| `/clear` | POST | İstek ve hata günlüklerini sıfırlar |
|
|
294
|
-
|
|
295
|
-
Bu uçların tamamı `mountDevtools()` tarafından yalnızca
|
|
296
|
-
`NODE_ENV=development` iken bağlanır; prod sürecine dinamik import sayesinde
|
|
297
|
-
hiçbir şey yüklenmez.
|
|
298
|
-
|
|
299
|
-
## Dev gate — `DEV_TOKEN`
|
|
300
|
-
|
|
301
|
-
Yayına açılmamış bir ortamı gizlemek için. **Framework token'ı zorunlu tutmaz:**
|
|
302
|
-
`DEV_TOKEN` ortamda durması siteyi kilitlemez. Gate'i siz açarsınız.
|
|
303
|
-
|
|
304
|
-
```bash
|
|
305
|
-
DEV_GATE=1 DEV_TOKEN=uzun-rastgele-bir-dize npm start
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
Aynı şey config ile:
|
|
309
|
-
|
|
310
|
-
```js
|
|
311
|
-
export default {
|
|
312
|
-
devGate: true,
|
|
313
|
-
};
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
Erişim:
|
|
317
|
-
|
|
318
|
-
```
|
|
319
|
-
https://staging.ornek.com/?dev_token=uzun-rastgele-bir-dize
|
|
320
|
-
```
|
|
321
|
-
|
|
322
|
-
Davranış:
|
|
323
|
-
|
|
324
|
-
- **403 değil 404.** 403 ortamın var olduğunu doğrular; 404 hiç yokmuş gibi
|
|
325
|
-
davranır.
|
|
326
|
-
- Token bir kez query parametresiyle gelirse çereze yazılır (`Path=/`,
|
|
327
|
-
`SameSite=Lax`, 14 gün), böylece link paylaşımı yeterli olur. Çerez ve
|
|
328
|
-
parametre adı `brand.devTokenCookie` (varsayılan `dev_token`).
|
|
329
|
-
- `devGateBypass` listesindeki **tam** yollar her koşulda açıktır. Varsayılan:
|
|
330
|
-
`/api/healthcheck`, `/robots.txt`, `/sitemap.xml`, `/site.webmanifest`,
|
|
331
|
-
`/favicon.ico`. Sağlık kontrolünüz farklı bir yolda ise bu listeye eklemeyi
|
|
332
|
-
unutmayın, aksi hâlde orkestratör 404 görür.
|
|
333
|
-
- `devGate` kapalıyken (varsayılan) veya `DEV_TOKEN` boşken middleware isteği
|
|
334
|
-
olduğu gibi geçirir. Production task'ına sızmış bir `DEV_TOKEN` ziyaretçiden
|
|
335
|
-
token istemez; açılışta bir uyarı basılır.
|
|
336
|
-
- `DEV_GATE=0` config'te `devGate: true` olsa da gate'i kapatır.
|
|
337
|
-
- Isıtma, gate açıkken token'ı çerez olarak taşır; yoksa tüm sayfalar 404 alır
|
|
338
|
-
ve önbellek hiç dolmaz ([06-cache.md](./06-cache.md)).
|
|
339
|
-
|
|
340
|
-
Gate middleware zincirinde `headers`tan sonra, `redirects`ten **önce** durur:
|
|
341
|
-
yayına açılmamış bir ortam yönlendirme kurallarını bile dışarıya sızdırmamalı.
|
|
342
|
-
|
|
343
|
-
## Development ile production farkları
|
|
344
|
-
|
|
345
|
-
| Konu | Development | Production |
|
|
346
|
-
| --- | --- | --- |
|
|
347
|
-
| EJS şablon cache'i | Kapalı | Açık |
|
|
348
|
-
| Manifest okuma | Her istekte | Bir kez |
|
|
349
|
-
| Görsel manifest'i | Her çağrıda | Bir kez |
|
|
350
|
-
| Bozuk route modülü | Uyarı + atla | Fırlat |
|
|
351
|
-
| Devtools ve rapor | Mount edilir | Hiç yüklenmez |
|
|
352
|
-
| `globalThis.fetch` | Sarılır (ölçüm) | Dokunulmaz |
|
|
353
|
-
| Prewarm paralelliği | 1 | 4 |
|
|
354
|
-
| Prewarm hız freni | saniyede 4 istek | Sınırsız |
|
|
355
|
-
| Prewarm gecikmesi | 3000 ms | 500 ms |
|
|
356
|
-
| Eksik ikon uyarısı | Verilir | Verilmez |
|
|
357
|
-
| Precompress | Watch'ta çalışmaz | Çalışır |
|
|
358
|
-
| Görsel optimizasyonu | Watch'ta çalışmaz | Çalışır |
|
|
359
|
-
|
|
360
|
-
## Sırada ne var
|
|
361
|
-
|
|
362
|
-
- Build adımlarının ayrıntısı: [08-build.md](./08-build.md)
|
|
363
|
-
- Prod'a alma: [10-dagitim.md](./10-dagitim.md)
|
|
364
|
-
- Önbelleği okumak ve temizlemek: [06-cache.md](./06-cache.md)
|
|
1
|
+
# 09 — Geliştirme araçları
|
|
2
|
+
|
|
3
|
+
Bu belge `jskelet dev`in ne yaptığını ve neden böyle yaptığını anlatır: iki alt
|
|
4
|
+
sürecin yönetimi, terminal çıktısının biçimi, izlenen dizinler ve `node --watch`
|
|
5
|
+
yerine kendi watcher'ının yazılma sebebi, CSS hot-swap ile tam yenileme ayrımı,
|
|
6
|
+
`Alt+D` ile açılan devtools overlay'i, detaylı rapor sayfası ve `DEV_TOKEN` ile
|
|
7
|
+
kurulan dev gate. Build adımlarının kendisi [08-build.md](./08-build.md)'de.
|
|
8
|
+
|
|
9
|
+
## `jskelet dev` akışı
|
|
10
|
+
|
|
11
|
+
Komut tek terminalde iki uzun ömürlü alt süreç yönetir:
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
jskelet dev
|
|
15
|
+
├─ build watch node src/build/build.mjs --watch
|
|
16
|
+
└─ sunucu node [--env-file=.env] --import <register.mjs> src/start.mjs
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`NODE_ENV=development` ataması platformdan bağımsız olarak burada yapılır —
|
|
20
|
+
`cross-env` gerekmez. Alt süreçlere ayrıca `JSKELET_CHILD=1` (build banner'ını
|
|
21
|
+
bastırır) ve TTY varsa `JSKELET_COLOR=1` (borulanmış çıktıda renk zorlar)
|
|
22
|
+
geçirilir.
|
|
23
|
+
|
|
24
|
+
Port (`PORT`, varsayılan `3000`) doluysa sunucu **başlamaz**; hata satırında
|
|
25
|
+
PID ve `--murder` ipucu vardır. `jskelet dev --murder` dinleyiciyi öldürüp aynı
|
|
26
|
+
porta bağlanır (başka bir terminalde unutulmuş süreç için).
|
|
27
|
+
|
|
28
|
+
Açılış sırası: banner → build adımları → sunucu hazır → `Ready` özeti. Özet hem
|
|
29
|
+
build hem sunucu hazır olduğunda basılır; aksi hâlde arkadan gelen build
|
|
30
|
+
satırlarının arasında kalıyordu.
|
|
31
|
+
|
|
32
|
+
Sunucunun hazır olduğu, `startServer` içindeki tek satırdan anlaşılır:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
jskelet → http://localhost:3000 (development)
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Bu satırın biçimi bir sözleşmedir; dev script'i onu ayrıştırıp özet satırını ona
|
|
39
|
+
göre basar.
|
|
40
|
+
|
|
41
|
+
### Terminal çıktısının biçimi
|
|
42
|
+
|
|
43
|
+
Alt süreçlerin çıktısı olduğu gibi akmaz. İki bölge vardır ve karışmazlar:
|
|
44
|
+
|
|
45
|
+
1. **Başlangıç:** banner, hizalı build satırları, `Ready` özeti.
|
|
46
|
+
2. **Çalışma anı:** zaman damgalı, tek satırlık olaylar (HTTP istekleri, CSS
|
|
47
|
+
rebuild, sunucu restart).
|
|
48
|
+
|
|
49
|
+
Hata yığınları çerçeveli bir kutuya dönüşür: yığın satırları parça parça geldiği
|
|
50
|
+
için kısa bir sessizlikten (60 ms) sonra toplanır, hata adı ve mesajı
|
|
51
|
+
ayrıştırılır, ilk üç frame gösterilir ve proje kökü `.` ile kısaltılır. Kendi
|
|
52
|
+
framework'ünü geliştirirken hatanın akış içinde kaybolmaması gerçekten fark
|
|
53
|
+
yaratan ayrıntı.
|
|
54
|
+
|
|
55
|
+
Renk anlam taşır: `✓` yeşil, `✖` kırmızı, `⚠` sarı, `↻` cyan; süre ve yol gri.
|
|
56
|
+
Dekoratif renk kullanılmaz. `NO_COLOR` ayarlıysa renk hiç kullanılmaz.
|
|
57
|
+
|
|
58
|
+
`Ctrl+C` (SIGINT/SIGTERM) tüm alt süreçleri kapatır. Bir alt süreç sıfır dışı
|
|
59
|
+
kodla çıkarsa (beklenen restart hariç) hata basılır ve dev süreci de kapanır.
|
|
60
|
+
|
|
61
|
+
## Watch dizinleri
|
|
62
|
+
|
|
63
|
+
Sunucu yeniden başlatma framework'ün kendi watcher'ıyla yönetilir.
|
|
64
|
+
|
|
65
|
+
```js
|
|
66
|
+
WATCH_DIRS = [
|
|
67
|
+
config.dirs.routes,
|
|
68
|
+
config.dirs.views,
|
|
69
|
+
<root>/lib,
|
|
70
|
+
...config.watch, // jskelet.config.mjs → watch
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Ayrıca `jskelet.config.mjs` dosyasının kendisi izlenir: config değişince hem
|
|
75
|
+
sunucu hem build yeni ayarlarla açılmalı.
|
|
76
|
+
|
|
77
|
+
İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.jsk`, `.ejs`.
|
|
78
|
+
|
|
79
|
+
`views` de izlenir çünkü bileşenlerin çoğu `views/components/**.js` içinde ve bu
|
|
80
|
+
modüller sunucuya bir kez import edildiği için, restart olmadan yapılan
|
|
81
|
+
değişiklik tarayıcıya hiç yansımıyordu (şablon düzenleyip "hiçbir şey değişmedi"
|
|
82
|
+
hissi buradan geliyor).
|
|
83
|
+
|
|
84
|
+
`client/` ve `styles/` bu listede **yoktur**: onları esbuild ve CSS watcher'ları
|
|
85
|
+
kendi içinde hallediyor ([08-build.md](./08-build.md)).
|
|
86
|
+
|
|
87
|
+
Bir dizin izlenemezse uyarı basılır ve o dizinde otomatik restart olmaz; gerisi
|
|
88
|
+
çalışır.
|
|
89
|
+
|
|
90
|
+
### Neden `node --watch` kullanılmadı
|
|
91
|
+
|
|
92
|
+
`--watch-path` verilse bile Node bu kurulumda proje kökünü izliyordu. Build
|
|
93
|
+
çıktısı (`public/assets`, `manifest.json`) ya da dev araçlarının günlüğü
|
|
94
|
+
yazıldığında sunucu boşuna yeniden başlıyor, hatta kendini besleyen bir döngü
|
|
95
|
+
kuruluyordu: restart → açılış uyarısı → yazma → restart.
|
|
96
|
+
|
|
97
|
+
Kendi watcher'ı üç şey yapar:
|
|
98
|
+
|
|
99
|
+
1. **Yalnızca sunucu kaynaklarını izler.**
|
|
100
|
+
2. **Değişiklikleri birleştirir** (250 ms) ve hangi dosyaların değiştiğini
|
|
101
|
+
bildirir.
|
|
102
|
+
3. **Sahte olayları eler.** Windows'ta `fs.watch` bir dosya yazıldığında
|
|
103
|
+
komşuları için de olay üretebiliyor; `mtime` karşılaştırılmazsa tek kaydetme
|
|
104
|
+
iki restart'a dönüşüyordu. Açılışta mevcut zamanlar önden okunur, böylece ilk
|
|
105
|
+
sahte olay da elenir.
|
|
106
|
+
|
|
107
|
+
Restart satırı değişen dosyayı ya da sayısını gösterir:
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
21:04:12 ↻ server restarting… routes/10-pages.mjs
|
|
111
|
+
21:04:12 server restarted 412ms
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`JSKELET_VERBOSE=1` ayarlıysa birden fazla dosya değiştiğinde tamamı listelenir.
|
|
115
|
+
|
|
116
|
+
## CSS hot-swap ve tam yenileme
|
|
117
|
+
|
|
118
|
+
Dev sunucusu `.jskelet/manifest.json` dosyasını izler ve olayları canlı kanal
|
|
119
|
+
(`<devBasePath>/ws`) üzerinden tarayıcıya yayınlar. Manifest her build turunda
|
|
120
|
+
yeniden yazıldığı için değişiklik tespiti manifest üzerinden yapılır.
|
|
121
|
+
|
|
122
|
+
| Değişen | Davranış |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| Yalnızca `.css` anahtarları | **CSS hot-swap:** değişen her stylesheet takas edilir, sayfa yenilenmez. Durum ve kaydırma korunur. |
|
|
125
|
+
| `main.js`, sprite, başka bir varlık ya da birden fazla anahtar | **Tam yenileme** |
|
|
126
|
+
|
|
127
|
+
Her iki durumda önce HTML önbelleği temizlenir: saklanan HTML eski hash'li varlık
|
|
128
|
+
URL'lerini taşıyor olur ve temizlenmezse sayfa silinmiş dosyayı istemeye devam
|
|
129
|
+
eder.
|
|
130
|
+
|
|
131
|
+
Manifest olayları 120 ms birleştirilir. Watch desteklenmiyorsa live reload devre
|
|
132
|
+
dışı kalır ve gerisi çalışır.
|
|
133
|
+
|
|
134
|
+
Sunucu yeniden başladığında overlay bunu **boot kimliğinden** anlar: her süreç
|
|
135
|
+
kendine özgü bir `boot` değeri yayınlar, overlay değişikliği görüp "restarted"
|
|
136
|
+
bilgisini gösterir ve kendi durumunu sıfırlamaz.
|
|
137
|
+
|
|
138
|
+
## Canlı kanal
|
|
139
|
+
|
|
140
|
+
Overlay'e giden her şey — istatistikler, live reload ve CSS hot-swap olayları —
|
|
141
|
+
tek bir WebSocket üzerinden gelir (`<devBasePath>/ws`). Panel eskiden
|
|
142
|
+
istatistikleri iki saniyede bir çekiyordu; açık her sekme, panel kapalıyken bile
|
|
143
|
+
sunucuya sürekli istek atıyordu. Artık sunucu değişiklik oldukça iter: bir istek
|
|
144
|
+
ya da hata kaydedildiğinde (120 ms birleştirilerek), ısıtma sürerken saniyede
|
|
145
|
+
ve zamana bağlı alanlar (uptime, bellek, ısıtma sayacı) tazelensin diye iki
|
|
146
|
+
saniyede bir. Kalp atışı bilinçli olarak ısıtmadan bağımsız: kanalın temposu bir
|
|
147
|
+
arka plan işine göre değişirse panel de o işin ritmine bağlanmış olur. Bağlı
|
|
148
|
+
panel yoksa hiçbir şey hesaplanmaz.
|
|
149
|
+
|
|
150
|
+
El sıkışma HTTP `upgrade` olayında geçtiği ve o olay middleware zincirine hiç
|
|
151
|
+
uğramadığı için kanal `listen` sonrası doğrudan sunucuya bağlanır
|
|
152
|
+
(`attachDevSocket`). Sunucu tarafı `ws` gibi bir bağımlılık kullanmaz: yalnızca
|
|
153
|
+
sunucu→istemci metin çerçevesi yazmak ve istemcinin ping/close çerçevelerini
|
|
154
|
+
yanıtlamak gerekiyor.
|
|
155
|
+
|
|
156
|
+
Soket kurulup sonra düşerse — yani sunucu yeniden başlıyorsa — yarım saniyede
|
|
157
|
+
bir yeniden bağlanır ve gösterge bu sırada "bağlantı yok" der. Hiç açılamazsa
|
|
158
|
+
aralığı kademeli açarak dört kez denenir; sayfa, sunucunun yeniden başlama
|
|
159
|
+
penceresinde açılmış olabilir ve tek bir başarısızlık kanalın çalışmadığı
|
|
160
|
+
anlamına gelmez. Denemeler de tutmazsa (araya giren bir proxy WebSocket'i
|
|
161
|
+
geçirmiyor olabilir) overlay eski yola düşer: `/events` SSE akışı + `/stats`
|
|
162
|
+
yoklaması.
|
|
163
|
+
|
|
164
|
+
## Devtools overlay
|
|
165
|
+
|
|
166
|
+
Sağ altta yüzen bir baloncuk; `Alt+D` ile açılır, `Esc` ya da karartma alanına
|
|
167
|
+
tıklamak kapatır. Yalnızca `NODE_ENV=development` iken layout tarafından
|
|
168
|
+
basılır:
|
|
169
|
+
|
|
170
|
+
```ejs
|
|
171
|
+
<% if (devtools) { %>
|
|
172
|
+
<script type="module" src="<%= devBasePath %>/overlay.js"></script>
|
|
173
|
+
<% } %>
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Overlay dosyası **build'e dâhil değildir.** Sunucu onu framework paketinden ham
|
|
177
|
+
olarak servis eder; bundler yoktur. Aynı dizindeki `seo.js` gibi kardeş
|
|
178
|
+
modüller native ESM import ile yüklenir ve prod çıktısına hiçbir şey eklenmez.
|
|
179
|
+
Tüm arayüz shadow DOM içinde durur, sayfanın CSS'i ile karışmaz.
|
|
180
|
+
|
|
181
|
+
Gösterdikleri:
|
|
182
|
+
|
|
183
|
+
- **Hatalar:** tarayıcı tarafındaki JS hataları, kaynak yükleme hataları
|
|
184
|
+
(`img`/`script`/`link`), sunucudaki `console.error` / `console.warn`
|
|
185
|
+
çıktıları, ve SSR / tarayıcı `fetch` çağrılarının 4xx/5xx ya da ağ
|
|
186
|
+
başarısızlıkları. Her kayıt mümkün olduğunca **sayfa yolu**, **API URL** ve
|
|
187
|
+
(istemcide) **island adı** taşır; yanıt gövdesi **show details** ile açılır —
|
|
188
|
+
`[object Object]` yerine JSON. Sunucu tarafında `console` sarılır, böylece
|
|
189
|
+
uyarılar terminalde kaybolmaz; upstream hataları uygulamanın kendi logger'ı
|
|
190
|
+
stderr'e yazsa bile overlay'e düşer.
|
|
191
|
+
- **SEO:** açık sayfanın istemci tarafı taraması — title ve meta description
|
|
192
|
+
uzunluğu, `html lang`, viewport, canonical, robots/`noindex`, Open Graph ve
|
|
193
|
+
Twitter etiketleri, H1/outline, görsel `alt`, boş linkler ve JSON-LD parse
|
|
194
|
+
hataları. Bulgular panelde listelenir; **Highlight issues on the page**
|
|
195
|
+
açılınca sorunlu elemanların üzerine kırmızı (error) veya sarı (warning)
|
|
196
|
+
dikdörtgenler çizilir, kenarda kısa başlık durur. Etikete (ya da panel
|
|
197
|
+
satırına) tıklanınca ayrıntılı açıklama açılır. Tarama overlay'in yanındaki
|
|
198
|
+
`/seo.js` dosyasındadır; production paketine girmez.
|
|
199
|
+
- **İstekler:** her HTML isteğinin metodu, yolu, durumu, süresi ve
|
|
200
|
+
`X-JSkelet-Cache` değeri. Aynı satırlar terminale de basılır.
|
|
201
|
+
- **Web Vitals:** TTFB, FCP, LCP, CLS, INP, DCL, load, uzun task sayısı ve
|
|
202
|
+
bloke süresi.
|
|
203
|
+
- **Prewarm:** ısıtma turunun ilerlemesi; panelden elle tetiklenebilir, tek tek
|
|
204
|
+
yollar tekrar denenebilir.
|
|
205
|
+
- **Süreç:** pid, Node sürümü, uptime, RSS ve heap kullanımı.
|
|
206
|
+
- **Sürüm:** kurulu JSkelet sürümü ve npm'deki `latest` ile karşılaştırması.
|
|
207
|
+
Yeni bir sürüm varsa **Server** sekmesinde `update` rozeti ve yükseltme
|
|
208
|
+
komutunu kopyalayan bir satır çıkar. Yoklama açılıştan 1,5 saniye sonra bir
|
|
209
|
+
kez yapılır, sonucu 6 saat boyunca `os.tmpdir()` içinde saklanır ve ağ yoksa
|
|
210
|
+
sessizce atlanır. `JSKELET_VERSION_CHECK=0` ile tamamen kapatılır.
|
|
211
|
+
|
|
212
|
+
Isıtma istekleri (`user-agent: jskelet-prewarm`) hem terminalden hem istek
|
|
213
|
+
listesinden filtrelenir: yüzlerce istek görünümü doldurmasın. İlerleme baloncuğun
|
|
214
|
+
yanındaki rozette görünür.
|
|
215
|
+
|
|
216
|
+
### Durum neden `os.tmpdir()`'e yazılıyor
|
|
217
|
+
|
|
218
|
+
İstek ve hata kayıtları süreç belleğinde durursa her yeniden başlatmada geçmiş
|
|
219
|
+
silinir ve overlay boşalır. Bu yüzden kayıtlar restart'lar arasında bir dosyada
|
|
220
|
+
taşınır.
|
|
221
|
+
|
|
222
|
+
Dosya **proje ağacına yazılmaz**: her yazma watcher'ı tetikleyip sunucuyu
|
|
223
|
+
yeniden başlatıyordu ve bu kendini besleyen bir döngü kuruyordu (restart →
|
|
224
|
+
açılış uyarısı → yazma → restart). Bunun yerine dosya
|
|
225
|
+
`os.tmpdir()/jskelet-devtools-<proje kökünün hash'i>.json` yoluna yazılır;
|
|
226
|
+
hash sayesinde aynı makinede birden fazla JSKelet projesi birbirinin kaydını
|
|
227
|
+
ezmez.
|
|
228
|
+
|
|
229
|
+
Yazma her istekte değil, 300 ms sessizlikten sonra yapılır ve başarısızlığı dev
|
|
230
|
+
akışını durdurmaz. En fazla 50 istek ve 50 hata tutulur.
|
|
231
|
+
|
|
232
|
+
Panelin açık/kapalı durumu, aktif sekmesi ve tarayıcı hata günlüğü ise sekme
|
|
233
|
+
belleğinde (`sessionStorage`) saklanır, böylece yenileme sonrası panel aynı
|
|
234
|
+
sekmeyle geri gelir.
|
|
235
|
+
|
|
236
|
+
## Rapor sayfası
|
|
237
|
+
|
|
238
|
+
Baloncuk anlık durumu gösterir; rapor sayfası sitenin tamamına bakan bir görünüm
|
|
239
|
+
üretir. Adres:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
http://localhost:3000/__jskelet/dev/report
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
(`brand.devBasePath` değiştirilmişse ona göre.)
|
|
246
|
+
|
|
247
|
+
İçeriği:
|
|
248
|
+
|
|
249
|
+
- **Sayfalar:** gezilen her sayfanın Web Vitals ölçümleri, kaynak sayısı ve
|
|
250
|
+
toplam bayt (tür kırılımıyla), island durumu (kaç tanesi hazır, adları),
|
|
251
|
+
tarayıcıdaki API çağrıları ve SSR çıktısının boyutu/süresi/cache durumu. Hiç
|
|
252
|
+
gezilmemiş ama ısıtılmış sayfalar da listelenir: SSR tarafı bilinir, istemci
|
|
253
|
+
ölçümleri boş kalır.
|
|
254
|
+
- **Sunucu API çağrıları:** SSR sırasında yapılan dış `fetch` çağrıları — URL,
|
|
255
|
+
host, metot, durum, süre, bayt, hangi sayfa render edilirken yapıldığı ve
|
|
256
|
+
başarısız cevaplarda gövde özeti. `globalThis.fetch` yalnızca development'ta
|
|
257
|
+
sarılır; üretim yolu dokunulmaz kalır. Kendi sunucumuza yapılan istekler
|
|
258
|
+
(ısıtma, sağlık kontrolü) API sayılmaz. Başarısız çağrılar overlay Errors
|
|
259
|
+
sekmesine de düşer.
|
|
260
|
+
- **Build çıktısı:** manifest'teki her varlığın ham/gzip/brotli boyutu, ve
|
|
261
|
+
esbuild metafile'ından chunk analizi — her çıktının boyutu, hangi kaynaklardan
|
|
262
|
+
oluştuğu, hangi chunk'ları import ettiği. Kaynaklar okunur gruplara indirgenir
|
|
263
|
+
(paket adı ya da üst klasör), böylece "bu chunk'ın 40 kB'ı hangi kütüphaneden"
|
|
264
|
+
sorusu yanıtlanabilir.
|
|
265
|
+
- **HTML önbelleği:** girdi sayısı ve döküm (anahtar, bayt, durum, bayat mı, kaç
|
|
266
|
+
saniye sonra dolacak, hangi encoding'ler saklanmış).
|
|
267
|
+
- **Prewarm:** son turun tam sonucu.
|
|
268
|
+
- **İstek ve hata günlükleri.**
|
|
269
|
+
|
|
270
|
+
Ölçümler tarayıcı sekmesinde değil sunucuda durur; sıfırlama da sunucudan
|
|
271
|
+
yapılır. Boyut hesapları dosya değişmedikçe tekrarlanmaz.
|
|
272
|
+
|
|
273
|
+
Rapor katmanı yalnızca development'ta yüklenir, üretim çıktısına hiç girmez.
|
|
274
|
+
|
|
275
|
+
## Dev uçları
|
|
276
|
+
|
|
277
|
+
`brand.devBasePath` (varsayılan `/__jskelet/dev`) altında:
|
|
278
|
+
|
|
279
|
+
| Yol | Metot | İşi |
|
|
280
|
+
| --- | --- | --- |
|
|
281
|
+
| `/overlay.js` | GET | Overlay script'i |
|
|
282
|
+
| `/seo.js` | GET | SEO tarama + sayfa highlight yardımcısı (overlay import eder) |
|
|
283
|
+
| `/logo.png` | GET | Overlay logosu |
|
|
284
|
+
| `/ws` | GET (upgrade) | Canlı kanal: istatistikler, live reload ve CSS hot-swap olayları |
|
|
285
|
+
| `/events` | GET | SSE: yalnızca WebSocket kurulamazsa kullanılan yedek olay akışı |
|
|
286
|
+
| `/stats` | GET | Anlık istatistikler; aynı yedek yolun veri ucu |
|
|
287
|
+
| `/report` | GET | Rapor sayfası (HTML) |
|
|
288
|
+
| `/report.js` | GET | Rapor sayfasının script'i |
|
|
289
|
+
| `/report/data` | GET | Raporun tek veri kaynağı (JSON) |
|
|
290
|
+
| `/vitals` | POST | Overlay'in gönderdiği ölçüm paketi |
|
|
291
|
+
| `/report/clear` | POST | Sayfa ölçümlerini ve sunucu API kayıtlarını sıfırlar |
|
|
292
|
+
| `/prewarm` | POST | Isıtmayı elle tetikler. Gövdede `paths` varsa yalnızca o yollar; ısıtma zaten çalışıyorsa 409. |
|
|
293
|
+
| `/clear` | POST | İstek ve hata günlüklerini sıfırlar |
|
|
294
|
+
|
|
295
|
+
Bu uçların tamamı `mountDevtools()` tarafından yalnızca
|
|
296
|
+
`NODE_ENV=development` iken bağlanır; prod sürecine dinamik import sayesinde
|
|
297
|
+
hiçbir şey yüklenmez.
|
|
298
|
+
|
|
299
|
+
## Dev gate — `DEV_TOKEN`
|
|
300
|
+
|
|
301
|
+
Yayına açılmamış bir ortamı gizlemek için. **Framework token'ı zorunlu tutmaz:**
|
|
302
|
+
`DEV_TOKEN` ortamda durması siteyi kilitlemez. Gate'i siz açarsınız.
|
|
303
|
+
|
|
304
|
+
```bash
|
|
305
|
+
DEV_GATE=1 DEV_TOKEN=uzun-rastgele-bir-dize npm start
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
Aynı şey config ile:
|
|
309
|
+
|
|
310
|
+
```js
|
|
311
|
+
export default {
|
|
312
|
+
devGate: true,
|
|
313
|
+
};
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Erişim:
|
|
317
|
+
|
|
318
|
+
```
|
|
319
|
+
https://staging.ornek.com/?dev_token=uzun-rastgele-bir-dize
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Davranış:
|
|
323
|
+
|
|
324
|
+
- **403 değil 404.** 403 ortamın var olduğunu doğrular; 404 hiç yokmuş gibi
|
|
325
|
+
davranır.
|
|
326
|
+
- Token bir kez query parametresiyle gelirse çereze yazılır (`Path=/`,
|
|
327
|
+
`SameSite=Lax`, 14 gün), böylece link paylaşımı yeterli olur. Çerez ve
|
|
328
|
+
parametre adı `brand.devTokenCookie` (varsayılan `dev_token`).
|
|
329
|
+
- `devGateBypass` listesindeki **tam** yollar her koşulda açıktır. Varsayılan:
|
|
330
|
+
`/api/healthcheck`, `/robots.txt`, `/sitemap.xml`, `/site.webmanifest`,
|
|
331
|
+
`/favicon.ico`. Sağlık kontrolünüz farklı bir yolda ise bu listeye eklemeyi
|
|
332
|
+
unutmayın, aksi hâlde orkestratör 404 görür.
|
|
333
|
+
- `devGate` kapalıyken (varsayılan) veya `DEV_TOKEN` boşken middleware isteği
|
|
334
|
+
olduğu gibi geçirir. Production task'ına sızmış bir `DEV_TOKEN` ziyaretçiden
|
|
335
|
+
token istemez; açılışta bir uyarı basılır.
|
|
336
|
+
- `DEV_GATE=0` config'te `devGate: true` olsa da gate'i kapatır.
|
|
337
|
+
- Isıtma, gate açıkken token'ı çerez olarak taşır; yoksa tüm sayfalar 404 alır
|
|
338
|
+
ve önbellek hiç dolmaz ([06-cache.md](./06-cache.md)).
|
|
339
|
+
|
|
340
|
+
Gate middleware zincirinde `headers`tan sonra, `redirects`ten **önce** durur:
|
|
341
|
+
yayına açılmamış bir ortam yönlendirme kurallarını bile dışarıya sızdırmamalı.
|
|
342
|
+
|
|
343
|
+
## Development ile production farkları
|
|
344
|
+
|
|
345
|
+
| Konu | Development | Production |
|
|
346
|
+
| --- | --- | --- |
|
|
347
|
+
| EJS şablon cache'i | Kapalı | Açık |
|
|
348
|
+
| Manifest okuma | Her istekte | Bir kez |
|
|
349
|
+
| Görsel manifest'i | Her çağrıda | Bir kez |
|
|
350
|
+
| Bozuk route modülü | Uyarı + atla | Fırlat |
|
|
351
|
+
| Devtools ve rapor | Mount edilir | Hiç yüklenmez |
|
|
352
|
+
| `globalThis.fetch` | Sarılır (ölçüm) | Dokunulmaz |
|
|
353
|
+
| Prewarm paralelliği | 1 | 4 |
|
|
354
|
+
| Prewarm hız freni | saniyede 4 istek | Sınırsız |
|
|
355
|
+
| Prewarm gecikmesi | 3000 ms | 500 ms |
|
|
356
|
+
| Eksik ikon uyarısı | Verilir | Verilmez |
|
|
357
|
+
| Precompress | Watch'ta çalışmaz | Çalışır |
|
|
358
|
+
| Görsel optimizasyonu | Watch'ta çalışmaz | Çalışır |
|
|
359
|
+
|
|
360
|
+
## Sırada ne var
|
|
361
|
+
|
|
362
|
+
- Build adımlarının ayrıntısı: [08-build.md](./08-build.md)
|
|
363
|
+
- Prod'a alma: [10-dagitim.md](./10-dagitim.md)
|
|
364
|
+
- Önbelleği okumak ve temizlemek: [06-cache.md](./06-cache.md)
|