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.
Files changed (153) hide show
  1. package/AGENTS.md +136 -136
  2. package/CHANGELOG.md +628 -620
  3. package/LICENSE +21 -21
  4. package/README.md +2 -0
  5. package/bin/jskelet.mjs +130 -130
  6. package/docs/01-baslangic.md +291 -291
  7. package/docs/02-mimari.md +310 -310
  8. package/docs/03-routing.md +515 -515
  9. package/docs/04-render-ve-sablonlar.md +667 -661
  10. package/docs/05-islands.md +486 -486
  11. package/docs/06-cache.md +1467 -1443
  12. package/docs/07-yapilandirma.md +1208 -1197
  13. package/docs/08-build.md +429 -429
  14. package/docs/09-dev-araclari.md +364 -364
  15. package/docs/10-dagitim.md +348 -338
  16. package/docs/12-panel-ve-oturum.md +479 -478
  17. package/docs/README.md +83 -83
  18. package/docs/en/01-getting-started.md +298 -298
  19. package/docs/en/02-architecture.md +329 -329
  20. package/docs/en/03-routing.md +531 -531
  21. package/docs/en/04-rendering.md +675 -669
  22. package/docs/en/05-islands.md +497 -497
  23. package/docs/en/06-caching.md +1476 -1453
  24. package/docs/en/07-configuration.md +1229 -1219
  25. package/docs/en/08-build.md +447 -447
  26. package/docs/en/09-dev-tools.md +373 -373
  27. package/docs/en/10-deployment.md +351 -340
  28. package/docs/en/11-migration.md +398 -398
  29. package/docs/en/12-dashboards-and-sessions.md +489 -488
  30. package/docs/en/README.md +87 -87
  31. package/package.json +137 -137
  32. package/src/build/ensure-build.mjs +19 -19
  33. package/src/build/paths.mjs +153 -153
  34. package/src/build/resolve-peer.mjs +36 -36
  35. package/src/build/tasks/client.mjs +349 -349
  36. package/src/build/tasks/css.mjs +235 -235
  37. package/src/build/tasks/fonts.mjs +146 -146
  38. package/src/build/tasks/icons.mjs +357 -357
  39. package/src/build/tasks/images.mjs +244 -244
  40. package/src/build/tasks/precompress.mjs +78 -78
  41. package/src/build/tasks/templates.mjs +20 -20
  42. package/src/client/admin/i18n.js +764 -764
  43. package/src/client/admin/login.html +74 -74
  44. package/src/client/admin/panel.css +809 -809
  45. package/src/client/admin/panel.html +495 -495
  46. package/src/client/admin/panel.js +1251 -1251
  47. package/src/client/devtools/report.html +185 -185
  48. package/src/client/devtools/report.js +745 -745
  49. package/src/client/devtools/seo.js +628 -628
  50. package/src/client/dom.js +95 -95
  51. package/src/client/form.js +192 -192
  52. package/src/client/index.js +45 -45
  53. package/src/client/registry.js +305 -305
  54. package/src/client/safe-image.js +91 -91
  55. package/src/client/shared-cookie.js +225 -225
  56. package/src/client/store.js +36 -36
  57. package/src/client/swap.js +188 -188
  58. package/src/compile/codegen.js +336 -336
  59. package/src/compile/compile-all.js +149 -149
  60. package/src/compile/errors.js +66 -66
  61. package/src/compile/expr.js +409 -409
  62. package/src/compile/index.js +17 -17
  63. package/src/compile/parse.js +541 -541
  64. package/src/compile/resolve.js +211 -211
  65. package/src/compile/scan-exports.js +51 -51
  66. package/src/config/defaults.js +541 -534
  67. package/src/config/index.js +1500 -1469
  68. package/src/config/pattern.js +107 -107
  69. package/src/generate.mjs +163 -163
  70. package/src/http/control-flow.js +71 -71
  71. package/src/http/cookies-entry.js +21 -21
  72. package/src/http/cookies.js +277 -277
  73. package/src/http/request-cache.js +46 -46
  74. package/src/http/request-context.js +165 -165
  75. package/src/http/shared-cookie.js +178 -178
  76. package/src/index.js +101 -101
  77. package/src/init.mjs +232 -230
  78. package/src/migrate/apply.mjs +262 -262
  79. package/src/migrate/babel.mjs +79 -79
  80. package/src/migrate/classify.mjs +155 -155
  81. package/src/migrate/config.mjs +126 -126
  82. package/src/migrate/fs-walk.mjs +191 -191
  83. package/src/migrate/parse.mjs +26 -26
  84. package/src/migrate/scan.mjs +177 -177
  85. package/src/migrate/transform/expr-source.mjs +168 -168
  86. package/src/migrate/transform/island.mjs +67 -67
  87. package/src/migrate/transform/jsx-to-component.mjs +302 -302
  88. package/src/migrate/transform/jsx-to-jsk.mjs +330 -330
  89. package/src/migrate/transform/page-split.mjs +435 -435
  90. package/src/migrate/write.mjs +81 -81
  91. package/src/migrate.mjs +171 -171
  92. package/src/runtime/alias-hooks.mjs +119 -119
  93. package/src/runtime/register.mjs +4 -4
  94. package/src/server/admin/actions.js +229 -229
  95. package/src/server/admin/auth.js +125 -125
  96. package/src/server/admin/event-log.js +151 -151
  97. package/src/server/admin/gate.js +209 -209
  98. package/src/server/admin/inventory.js +188 -188
  99. package/src/server/admin/mount.js +56 -56
  100. package/src/server/admin/router.js +216 -216
  101. package/src/server/admin/snapshot.js +241 -241
  102. package/src/server/assets.js +147 -147
  103. package/src/server/auth/handoff.js +309 -309
  104. package/src/server/cache-blob.js +70 -70
  105. package/src/server/cache-control.js +45 -0
  106. package/src/server/cache-deps.js +42 -42
  107. package/src/server/cache-vary.js +113 -113
  108. package/src/server/cloudflare.js +607 -607
  109. package/src/server/create-app.js +366 -366
  110. package/src/server/data-cache.js +553 -553
  111. package/src/server/dev/report.js +485 -485
  112. package/src/server/dev/socket.js +170 -170
  113. package/src/server/dev/version-check.mjs +139 -139
  114. package/src/server/disk-cache.js +233 -233
  115. package/src/server/ejs-adapter.js +59 -59
  116. package/src/server/html-cache.js +1196 -1196
  117. package/src/server/image-optimizer.js +500 -500
  118. package/src/server/logs/access-middleware.js +66 -66
  119. package/src/server/logs/file-sink.js +193 -193
  120. package/src/server/logs/pipeline.js +165 -165
  121. package/src/server/logs/s3-put.js +214 -214
  122. package/src/server/logs/s3-sink.js +112 -112
  123. package/src/server/metadata.js +102 -102
  124. package/src/server/middleware/compression.js +205 -205
  125. package/src/server/middleware/csrf.js +134 -134
  126. package/src/server/middleware/dev-gate.js +75 -75
  127. package/src/server/middleware/headers.js +37 -37
  128. package/src/server/middleware/redirects.js +32 -32
  129. package/src/server/middleware/robots-txt.js +341 -341
  130. package/src/server/middleware/static-precompressed.js +121 -121
  131. package/src/server/middleware/trailing-slash.js +53 -53
  132. package/src/server/middleware/upstream-proxy.js +141 -141
  133. package/src/server/og-image.js +369 -356
  134. package/src/server/port-guard.js +255 -255
  135. package/src/server/prewarm.js +1082 -1082
  136. package/src/server/redis.js +588 -588
  137. package/src/server/render.js +910 -910
  138. package/src/server/router.js +157 -157
  139. package/src/server/status-page.js +265 -265
  140. package/src/server/upstream-limiter.js +376 -376
  141. package/src/server/upstream-tracking.js +166 -166
  142. package/src/shared/cookie-domain.js +66 -66
  143. package/src/start.mjs +22 -22
  144. package/src/templates/layout.ejs +30 -30
  145. package/src/templates/layout.jsk +30 -30
  146. package/src/version.mjs +31 -31
  147. package/src/views/components/loader.js +101 -101
  148. package/src/views/helpers/html.js +102 -102
  149. package/src/views/helpers/tags.js +375 -375
  150. package/types/config/defaults.d.ts +6 -0
  151. package/types/config/index.d.ts +6 -0
  152. package/types/server/cache-control.d.ts +28 -0
  153. package/types/server/og-image.d.ts +5 -0
@@ -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)