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/01-baslangic.md
CHANGED
|
@@ -1,291 +1,291 @@
|
|
|
1
|
-
# 01 — Başlangıç
|
|
2
|
-
|
|
3
|
-
Bu belge JSkelet'i sıfırdan çalıştırmayı anlatır: paket kurulumu, `jskelet init`
|
|
4
|
-
ile iskeletin oluşturulması, ilk route ve ilk island'ın yazılması, oluşan dizin
|
|
5
|
-
yapısının ne anlama geldiği ve CLI komutları. Sonunda tarayıcıda sunucuda
|
|
6
|
-
render edilmiş, önbelleğe alınmış ve island'ı görünürlükte hidre olan bir sayfa
|
|
7
|
-
olacak. Kararların *nedenleri* için [02-mimari.md](./02-mimari.md)'ye, buradaki
|
|
8
|
-
her config alanının tam referansı için
|
|
9
|
-
[07-yapilandirma.md](./07-yapilandirma.md)'ye bakın.
|
|
10
|
-
|
|
11
|
-
## Gereksinimler
|
|
12
|
-
|
|
13
|
-
- **Node.js 22 veya üstü.** `package.json` → `engines` bunu zorunlu tutuyor.
|
|
14
|
-
Framework `node:async_hooks`, `fs.readdirSync(..., { recursive: true })`,
|
|
15
|
-
`--env-file-if-exists` ve `module.register()` gibi yeni Node yüzeylerini
|
|
16
|
-
doğrudan kullanıyor.
|
|
17
|
-
- Tailwind CSS kullanacaksanız `postcss`, `@tailwindcss/postcss` ve
|
|
18
|
-
`tailwindcss` paketleri. Bunlar framework'ün **opsiyonel peer
|
|
19
|
-
bağımlılıkları**dır; kurulu değilse CSS adımı atlanır ve site stilsiz ama
|
|
20
|
-
çalışır durumda kalır (ayrıntı: [08-build.md](./08-build.md)).
|
|
21
|
-
|
|
22
|
-
## Kurulum
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
mkdir benim-sitem && cd benim-sitem
|
|
26
|
-
npm init -y
|
|
27
|
-
npm pkg set type=module
|
|
28
|
-
npm install jskelet
|
|
29
|
-
npm install -D postcss @tailwindcss/postcss tailwindcss lightningcss
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
`type: "module"` şart: route modülleri, bileşenler ve config dosyası ESM olarak
|
|
33
|
-
yüklenir.
|
|
34
|
-
|
|
35
|
-
Ardından `package.json` içine script'leri ekleyin:
|
|
36
|
-
|
|
37
|
-
```json
|
|
38
|
-
{
|
|
39
|
-
"scripts": {
|
|
40
|
-
"dev": "jskelet dev",
|
|
41
|
-
"build": "jskelet build",
|
|
42
|
-
"start": "jskelet start"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## `jskelet init`
|
|
48
|
-
|
|
49
|
-
```bash
|
|
50
|
-
npx jskelet init
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Bu komut bulunduğunuz dizine çalışan bir minimum iskelet kurar. **Var olan
|
|
54
|
-
dosyaların üzerine yazmaz**: ikinci kez çalıştırmak yalnızca eksikleri
|
|
55
|
-
tamamlar, atlanan dosyaların sayısını uyarı olarak basar. Amaç, "kurulumu
|
|
56
|
-
yaptım ama hiçbir şey çalışmıyor" aşamasını tamamen atlamak — `jskelet dev`
|
|
57
|
-
hemen ardından çalışır.
|
|
58
|
-
|
|
59
|
-
Oluşturulan dosyalar (feature-first + `.jsk`):
|
|
60
|
-
|
|
61
|
-
```
|
|
62
|
-
jskelet.config.mjs config: brand, preconnect, cache(), hooks
|
|
63
|
-
features/home/index.js "/" route'u
|
|
64
|
-
features/home/views/pages/home.jsk ana sayfa şablonu
|
|
65
|
-
features/home/views/components/button.js örnek bileşen (<Button />)
|
|
66
|
-
features/home/client/counter.js örnek island
|
|
67
|
-
features/home/server/.gitkeep
|
|
68
|
-
views/pages/not-found.jsk uygulama geneli 404
|
|
69
|
-
client/entries/main.js island bootstrap'ı
|
|
70
|
-
styles/globals.css Tailwind girişi + @source direktifleri
|
|
71
|
-
jsconfig.json checkJs + "@/*" alias'ı
|
|
72
|
-
.gitignore node_modules/, .jskelet/, public/assets/, .env
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Büyümek için: `npx jskelet generate feature <name>` (veya `page` / `island`).
|
|
76
|
-
|
|
77
|
-
Sonra:
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
npm run dev
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Terminalde banner, hizalı build satırları ve bir `Ready` özeti görürsünüz;
|
|
84
|
-
`http://localhost:3000` sayfayı verir. Sağ altta dev overlay baloncuğu durur,
|
|
85
|
-
`Alt+D` ile açılır ([09-dev-araclari.md](./09-dev-araclari.md)).
|
|
86
|
-
|
|
87
|
-
## Dizin yapısı
|
|
88
|
-
|
|
89
|
-
Dizin adlarının hiçbiri sabit değildir; hepsi `jskelet.config.mjs` → `paths`
|
|
90
|
-
ile ezilebilir. Aşağıdaki değerler varsayılanlardır (`src/config/defaults.js`).
|
|
91
|
-
|
|
92
|
-
| Dizin | Varsayılan | İçeriği |
|
|
93
|
-
| --- | --- | --- |
|
|
94
|
-
| `views` | `views` | Uygulama geneli layout, sayfalar ve bileşenler |
|
|
95
|
-
| `features` | `features` | Feature dilimleri (`<name>/{server,views,client}`) |
|
|
96
|
-
| `shared` | `shared` | Feature'lar arası paylaşılan server/views/client |
|
|
97
|
-
| `public` | `public` | Statik dosyalar; build çıktısı da buraya yazılır |
|
|
98
|
-
| `client` | `client` | Island runtime kaynakları ve entry'ler |
|
|
99
|
-
| `routes` | `routes` | Route modülleri (feature'lardan önce yüklenir) |
|
|
100
|
-
| `styles` | `styles/globals.css` | Tailwind/PostCSS giriş **dosyası** |
|
|
101
|
-
| `generated` | `.jskelet` | Build ara çıktıları: `manifest.json`, `metafile.json`, `images.json`, `templates/` |
|
|
102
|
-
|
|
103
|
-
Bunlara ek olarak framework iki yolu her zaman türetir ve ayrı ayar kabul
|
|
104
|
-
etmez: `public/assets` (hash'li build çıktısı) ve `public/fonts` (self-host
|
|
105
|
-
fontlar).
|
|
106
|
-
|
|
107
|
-
Tipik bir proje (`jskelet init` çıktısına yakın):
|
|
108
|
-
|
|
109
|
-
```
|
|
110
|
-
benim-sitem/
|
|
111
|
-
├── jskelet.config.mjs
|
|
112
|
-
├── jsconfig.json
|
|
113
|
-
├── features/
|
|
114
|
-
│ └── home/
|
|
115
|
-
│ ├── index.js
|
|
116
|
-
│ ├── server/
|
|
117
|
-
│ ├── views/
|
|
118
|
-
│ │ ├── pages/home.jsk
|
|
119
|
-
│ │ └── components/button.js
|
|
120
|
-
│ └── client/counter.js
|
|
121
|
-
├── views/
|
|
122
|
-
│ └── pages/not-found.jsk
|
|
123
|
-
├── client/
|
|
124
|
-
│ └── entries/main.js
|
|
125
|
-
├── styles/
|
|
126
|
-
│ └── globals.css
|
|
127
|
-
├── public/
|
|
128
|
-
│ └── (statik dosyalar; build → public/assets)
|
|
129
|
-
└── .jskelet/
|
|
130
|
-
├── manifest.json
|
|
131
|
-
└── templates/
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
## İlk route
|
|
135
|
-
|
|
136
|
-
Route modülleri **dosya sistemine dayalı otomatik URL türetmez**; her modül
|
|
137
|
-
kendi yollarını `app.get(...)` ile açıkça yazar. Modül sözleşmesi: default
|
|
138
|
-
export ya da `register` adlı named export, `(app, api)` imzasıyla.
|
|
139
|
-
|
|
140
|
-
```js
|
|
141
|
-
// features/home/index.js
|
|
142
|
-
export default function register(app, { route }) {
|
|
143
|
-
app.get(
|
|
144
|
-
"/",
|
|
145
|
-
route(
|
|
146
|
-
async () => ({
|
|
147
|
-
view: "pages/home",
|
|
148
|
-
metadata: { title: "Ana sayfa" },
|
|
149
|
-
data: { message: "JSkelet çalışıyor" },
|
|
150
|
-
}),
|
|
151
|
-
{ revalidate: 60 },
|
|
152
|
-
),
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
`api` nesnesi içinde `route`, `renderView`, `renderPage`, `notFound`, `redirect`
|
|
158
|
-
ve `permanentRedirect` hazır gelir; route dosyaları framework'ten tek tek import
|
|
159
|
-
yapmak zorunda kalmaz. `route()` controller'ı sarar: HTML cache'i,
|
|
160
|
-
notFound/redirect kontrol akışı, sıkıştırma ve `X-JSkelet-Cache` başlığı ondan
|
|
161
|
-
gelir. Controller'ın tek işi bir sayfa tanımı döndürmektir.
|
|
162
|
-
|
|
163
|
-
`routes/` kullanıyorsanız dosya adındaki `10-` öneki yükleme sırasını belirler;
|
|
164
|
-
`/:slug` gibi yakalayıcı route'ları daha yüksek numaralı bir dosyaya koyun.
|
|
165
|
-
Feature `index.js` dosyaları `routes/` tarandıktan sonra alfabetik eklenir.
|
|
166
|
-
Ayrıntı: [03-routing.md](./03-routing.md).
|
|
167
|
-
|
|
168
|
-
Şablon tarafı `.jsk` (build-time derlenir):
|
|
169
|
-
|
|
170
|
-
```html
|
|
171
|
-
{# features/home/views/pages/home.jsk #}
|
|
172
|
-
<section class="wrapper">
|
|
173
|
-
<h1>{{ metadata.title }}</h1>
|
|
174
|
-
<p>{{ message }}</p>
|
|
175
|
-
<Button text="Örnek bileşen" />
|
|
176
|
-
<div data-island="counter" data-island-props='{"start":0}'></div>
|
|
177
|
-
</section>
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
`Button`, `features/home/views/components/button.js` içindeki `button` named
|
|
181
|
-
export'undan gelir — PascalCase etiket; import gerekmez
|
|
182
|
-
([04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md)).
|
|
183
|
-
|
|
184
|
-
## İlk island
|
|
185
|
-
|
|
186
|
-
Island, sunucunun ürettiği HTML'e davranış ekleyen küçük bir modüldür. Sözleşme
|
|
187
|
-
iki parçadan oluşur.
|
|
188
|
-
|
|
189
|
-
**1. Şablonda işaret:** bir elemente `data-island="ad"` verin. Props JSON olarak
|
|
190
|
-
`data-island-props` içinde taşınır.
|
|
191
|
-
|
|
192
|
-
```ejs
|
|
193
|
-
<div data-island="counter" data-island-props='{"start":5}'></div>
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**2. Modülde `mount`:** island `mount(element, props)` adlı bir named export
|
|
197
|
-
verir.
|
|
198
|
-
|
|
199
|
-
```js
|
|
200
|
-
// features/home/client/counter.js
|
|
201
|
-
/**
|
|
202
|
-
* @param {HTMLElement} element
|
|
203
|
-
* @param {{ start?: number }} props
|
|
204
|
-
*/
|
|
205
|
-
export function mount(element, props) {
|
|
206
|
-
let value = props.start ?? 0;
|
|
207
|
-
|
|
208
|
-
const button = document.createElement("button");
|
|
209
|
-
button.type = "button";
|
|
210
|
-
|
|
211
|
-
const paint = () => {
|
|
212
|
-
button.textContent = `Tıklama: ${value}`;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
button.addEventListener("click", () => {
|
|
216
|
-
value += 1;
|
|
217
|
-
paint();
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
paint();
|
|
221
|
-
element.append(button);
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
**3. Kayıt:** `client/entries/main.js` island adını dinamik import'a bağlar ve
|
|
226
|
-
runtime'ı başlatır.
|
|
227
|
-
|
|
228
|
-
```js
|
|
229
|
-
import { registerAll, start } from "jskelet/client";
|
|
230
|
-
|
|
231
|
-
registerAll({
|
|
232
|
-
counter: () => import("../../features/home/client/counter.js"),
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
start();
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
Değerlerin dinamik import olması kritik: modül yalnızca sayfada o island
|
|
239
|
-
gerçekten varsa **ve** element görünür hâle geldiğinde indirilir. Yani bu
|
|
240
|
-
haritayı büyütmek ilk yükü büyütmez. Hidrasyon stratejileri
|
|
241
|
-
(`data-island-eager`, `data-island-idle`) ve runtime API'sinin tamamı
|
|
242
|
-
[05-islands.md](./05-islands.md)'de.
|
|
243
|
-
|
|
244
|
-
## CLI komutları
|
|
245
|
-
|
|
246
|
-
`bin/jskelet.mjs` şu alt komutları sunar. Her biri ayrı bir Node sürecinde
|
|
247
|
-
çalışır; sebebi `dev`in iki uzun ömürlü süreci yönetmesi ve sunucunun ESM
|
|
248
|
-
resolve hook'larına (`--import`) süreç başlangıcında ihtiyaç duyması.
|
|
249
|
-
|
|
250
|
-
| Komut | Ne yapar |
|
|
251
|
-
| --- | --- |
|
|
252
|
-
| `jskelet dev` | Build watch + sunucu, tek terminalde. Canlı yenileme, CSS hot-swap, dev overlay. `NODE_ENV=development`. Port doluysa başlamaz; `--murder` dinleyiciyi öldürüp bağlar. |
|
|
253
|
-
| `jskelet build` | Tek seferlik prod build: fontlar → ikon sprite → CSS → client JS → görseller → manifest → precompress. `NODE_ENV` verilmemişse `production`. |
|
|
254
|
-
| `jskelet start` | Prod sunucu. Build çıktısı yoksa önce üretir. `NODE_ENV` verilmemişse `production`. Port davranışı `dev` ile aynı (`--murder`). |
|
|
255
|
-
| `jskelet init` | Bulunduğun dizine feature-first `.jsk` iskeleti kurar; var olan dosyalara dokunmaz. |
|
|
256
|
-
| `jskelet generate` | `feature` / `page` / `island` iskeleti üretir. |
|
|
257
|
-
| `jskelet migrate` | Next.js App Router → JSkelet codemod (`scan` / `apply` / `config`). [11-tasima.md](./11-tasima.md). |
|
|
258
|
-
|
|
259
|
-
Bilinmeyen bir komut ya da argümansız çağrı kullanım metnini basar.
|
|
260
|
-
|
|
261
|
-
Her komut iki Node bayrağıyla çalışır:
|
|
262
|
-
|
|
263
|
-
- `--env-file=.env` — yalnızca dosya gerçekten varsa geçilir; yoksa hiçbir
|
|
264
|
-
bayrak eklenmez ve uyarı basılmaz.
|
|
265
|
-
- `--import <register.mjs>` — `jsconfig.json` / `tsconfig.json` içindeki
|
|
266
|
-
`compilerOptions.paths` alias'larını (`@/lib/x`) ve uzantısız göreli
|
|
267
|
-
import'ları (`./cache` → `./cache.js`) çözen ESM hook'larını kurar.
|
|
268
|
-
(`jskelet dev` bu hook'ları kendi alt süreçlerinde kurar, dış süreçte kurmaz.)
|
|
269
|
-
|
|
270
|
-
## İthal yolları
|
|
271
|
-
|
|
272
|
-
`package.json` → `exports` haritası kararlı yüzeyi tanımlar. Örneklerde
|
|
273
|
-
yalnızca bu belirteçleri kullanın:
|
|
274
|
-
|
|
275
|
-
| Belirteç | İçeriği |
|
|
276
|
-
| --- | --- |
|
|
277
|
-
| `jskelet` | Sunucu API'si: `route`, `renderPage`, `renderView`, `renderNotFound`, `createApp`, `startServer`, `notFound`, `redirect`, `permanentRedirect`, `cache`, `withRequestCache`, `reportUpstreamFailure`, `asset`, `hasAsset`, `optimizedImage`, `getSpriteIds`, `headHints`, `renderHeadMeta`, HTML cache fonksiyonları, `prewarm`, `createProxy`, `getConfig`, `loadConfig` ve html/tag yardımcıları |
|
|
278
|
-
| `jskelet/server` | `jskelet` ile aynı modül (okunurluk için takma ad) |
|
|
279
|
-
| `jskelet/client` | Tarayıcı runtime'ı: `register`, `registerAll`, `hydrate`, `observeDocument`, `start`, `createStore`, DOM yardımcıları, `startSafeImages` |
|
|
280
|
-
| `jskelet/html` | `esc`, `attrs`, `cx`, `cn`, `jsonScript` |
|
|
281
|
-
| `jskelet/tags` | `link`, `image`, `icon`, `preloadImage`, `toKebab` |
|
|
282
|
-
| `jskelet/log` | Konsol çıktısı yardımcıları (`banner`, `event`, `task`, `size`, `ms`, …) |
|
|
283
|
-
| `jskelet/register` | `node --import jskelet/register` ile alias + uzantı hook'ları |
|
|
284
|
-
| `jskelet/layout` | Framework'ün varsayılan `layout.jsk` dosyasının yolu |
|
|
285
|
-
|
|
286
|
-
## Sırada ne var
|
|
287
|
-
|
|
288
|
-
- Neden bu şekilde çalışıyor: [02-mimari.md](./02-mimari.md)
|
|
289
|
-
- Daha fazla route ve yakalayıcı desenler: [03-routing.md](./03-routing.md)
|
|
290
|
-
- Layout'u devralmak ve metadata: [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md)
|
|
291
|
-
- Önbelleği ayarlamak: [06-cache.md](./06-cache.md)
|
|
1
|
+
# 01 — Başlangıç
|
|
2
|
+
|
|
3
|
+
Bu belge JSkelet'i sıfırdan çalıştırmayı anlatır: paket kurulumu, `jskelet init`
|
|
4
|
+
ile iskeletin oluşturulması, ilk route ve ilk island'ın yazılması, oluşan dizin
|
|
5
|
+
yapısının ne anlama geldiği ve CLI komutları. Sonunda tarayıcıda sunucuda
|
|
6
|
+
render edilmiş, önbelleğe alınmış ve island'ı görünürlükte hidre olan bir sayfa
|
|
7
|
+
olacak. Kararların *nedenleri* için [02-mimari.md](./02-mimari.md)'ye, buradaki
|
|
8
|
+
her config alanının tam referansı için
|
|
9
|
+
[07-yapilandirma.md](./07-yapilandirma.md)'ye bakın.
|
|
10
|
+
|
|
11
|
+
## Gereksinimler
|
|
12
|
+
|
|
13
|
+
- **Node.js 22 veya üstü.** `package.json` → `engines` bunu zorunlu tutuyor.
|
|
14
|
+
Framework `node:async_hooks`, `fs.readdirSync(..., { recursive: true })`,
|
|
15
|
+
`--env-file-if-exists` ve `module.register()` gibi yeni Node yüzeylerini
|
|
16
|
+
doğrudan kullanıyor.
|
|
17
|
+
- Tailwind CSS kullanacaksanız `postcss`, `@tailwindcss/postcss` ve
|
|
18
|
+
`tailwindcss` paketleri. Bunlar framework'ün **opsiyonel peer
|
|
19
|
+
bağımlılıkları**dır; kurulu değilse CSS adımı atlanır ve site stilsiz ama
|
|
20
|
+
çalışır durumda kalır (ayrıntı: [08-build.md](./08-build.md)).
|
|
21
|
+
|
|
22
|
+
## Kurulum
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mkdir benim-sitem && cd benim-sitem
|
|
26
|
+
npm init -y
|
|
27
|
+
npm pkg set type=module
|
|
28
|
+
npm install jskelet
|
|
29
|
+
npm install -D postcss @tailwindcss/postcss tailwindcss lightningcss
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`type: "module"` şart: route modülleri, bileşenler ve config dosyası ESM olarak
|
|
33
|
+
yüklenir.
|
|
34
|
+
|
|
35
|
+
Ardından `package.json` içine script'leri ekleyin:
|
|
36
|
+
|
|
37
|
+
```json
|
|
38
|
+
{
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "jskelet dev",
|
|
41
|
+
"build": "jskelet build",
|
|
42
|
+
"start": "jskelet start"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## `jskelet init`
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npx jskelet init
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Bu komut bulunduğunuz dizine çalışan bir minimum iskelet kurar. **Var olan
|
|
54
|
+
dosyaların üzerine yazmaz**: ikinci kez çalıştırmak yalnızca eksikleri
|
|
55
|
+
tamamlar, atlanan dosyaların sayısını uyarı olarak basar. Amaç, "kurulumu
|
|
56
|
+
yaptım ama hiçbir şey çalışmıyor" aşamasını tamamen atlamak — `jskelet dev`
|
|
57
|
+
hemen ardından çalışır.
|
|
58
|
+
|
|
59
|
+
Oluşturulan dosyalar (feature-first + `.jsk`):
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
jskelet.config.mjs config: brand, preconnect, cache(), hooks
|
|
63
|
+
features/home/index.js "/" route'u
|
|
64
|
+
features/home/views/pages/home.jsk ana sayfa şablonu
|
|
65
|
+
features/home/views/components/button.js örnek bileşen (<Button />)
|
|
66
|
+
features/home/client/counter.js örnek island
|
|
67
|
+
features/home/server/.gitkeep
|
|
68
|
+
views/pages/not-found.jsk uygulama geneli 404
|
|
69
|
+
client/entries/main.js island bootstrap'ı
|
|
70
|
+
styles/globals.css Tailwind girişi + @source direktifleri
|
|
71
|
+
jsconfig.json checkJs + "@/*" alias'ı
|
|
72
|
+
.gitignore node_modules/, .jskelet/, public/assets/, .env
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Büyümek için: `npx jskelet generate feature <name>` (veya `page` / `island`).
|
|
76
|
+
|
|
77
|
+
Sonra:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
npm run dev
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Terminalde banner, hizalı build satırları ve bir `Ready` özeti görürsünüz;
|
|
84
|
+
`http://localhost:3000` sayfayı verir. Sağ altta dev overlay baloncuğu durur,
|
|
85
|
+
`Alt+D` ile açılır ([09-dev-araclari.md](./09-dev-araclari.md)).
|
|
86
|
+
|
|
87
|
+
## Dizin yapısı
|
|
88
|
+
|
|
89
|
+
Dizin adlarının hiçbiri sabit değildir; hepsi `jskelet.config.mjs` → `paths`
|
|
90
|
+
ile ezilebilir. Aşağıdaki değerler varsayılanlardır (`src/config/defaults.js`).
|
|
91
|
+
|
|
92
|
+
| Dizin | Varsayılan | İçeriği |
|
|
93
|
+
| --- | --- | --- |
|
|
94
|
+
| `views` | `views` | Uygulama geneli layout, sayfalar ve bileşenler |
|
|
95
|
+
| `features` | `features` | Feature dilimleri (`<name>/{server,views,client}`) |
|
|
96
|
+
| `shared` | `shared` | Feature'lar arası paylaşılan server/views/client |
|
|
97
|
+
| `public` | `public` | Statik dosyalar; build çıktısı da buraya yazılır |
|
|
98
|
+
| `client` | `client` | Island runtime kaynakları ve entry'ler |
|
|
99
|
+
| `routes` | `routes` | Route modülleri (feature'lardan önce yüklenir) |
|
|
100
|
+
| `styles` | `styles/globals.css` | Tailwind/PostCSS giriş **dosyası** |
|
|
101
|
+
| `generated` | `.jskelet` | Build ara çıktıları: `manifest.json`, `metafile.json`, `images.json`, `templates/` |
|
|
102
|
+
|
|
103
|
+
Bunlara ek olarak framework iki yolu her zaman türetir ve ayrı ayar kabul
|
|
104
|
+
etmez: `public/assets` (hash'li build çıktısı) ve `public/fonts` (self-host
|
|
105
|
+
fontlar).
|
|
106
|
+
|
|
107
|
+
Tipik bir proje (`jskelet init` çıktısına yakın):
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
benim-sitem/
|
|
111
|
+
├── jskelet.config.mjs
|
|
112
|
+
├── jsconfig.json
|
|
113
|
+
├── features/
|
|
114
|
+
│ └── home/
|
|
115
|
+
│ ├── index.js
|
|
116
|
+
│ ├── server/
|
|
117
|
+
│ ├── views/
|
|
118
|
+
│ │ ├── pages/home.jsk
|
|
119
|
+
│ │ └── components/button.js
|
|
120
|
+
│ └── client/counter.js
|
|
121
|
+
├── views/
|
|
122
|
+
│ └── pages/not-found.jsk
|
|
123
|
+
├── client/
|
|
124
|
+
│ └── entries/main.js
|
|
125
|
+
├── styles/
|
|
126
|
+
│ └── globals.css
|
|
127
|
+
├── public/
|
|
128
|
+
│ └── (statik dosyalar; build → public/assets)
|
|
129
|
+
└── .jskelet/
|
|
130
|
+
├── manifest.json
|
|
131
|
+
└── templates/
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## İlk route
|
|
135
|
+
|
|
136
|
+
Route modülleri **dosya sistemine dayalı otomatik URL türetmez**; her modül
|
|
137
|
+
kendi yollarını `app.get(...)` ile açıkça yazar. Modül sözleşmesi: default
|
|
138
|
+
export ya da `register` adlı named export, `(app, api)` imzasıyla.
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
// features/home/index.js
|
|
142
|
+
export default function register(app, { route }) {
|
|
143
|
+
app.get(
|
|
144
|
+
"/",
|
|
145
|
+
route(
|
|
146
|
+
async () => ({
|
|
147
|
+
view: "pages/home",
|
|
148
|
+
metadata: { title: "Ana sayfa" },
|
|
149
|
+
data: { message: "JSkelet çalışıyor" },
|
|
150
|
+
}),
|
|
151
|
+
{ revalidate: 60 },
|
|
152
|
+
),
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`api` nesnesi içinde `route`, `renderView`, `renderPage`, `notFound`, `redirect`
|
|
158
|
+
ve `permanentRedirect` hazır gelir; route dosyaları framework'ten tek tek import
|
|
159
|
+
yapmak zorunda kalmaz. `route()` controller'ı sarar: HTML cache'i,
|
|
160
|
+
notFound/redirect kontrol akışı, sıkıştırma ve `X-JSkelet-Cache` başlığı ondan
|
|
161
|
+
gelir. Controller'ın tek işi bir sayfa tanımı döndürmektir.
|
|
162
|
+
|
|
163
|
+
`routes/` kullanıyorsanız dosya adındaki `10-` öneki yükleme sırasını belirler;
|
|
164
|
+
`/:slug` gibi yakalayıcı route'ları daha yüksek numaralı bir dosyaya koyun.
|
|
165
|
+
Feature `index.js` dosyaları `routes/` tarandıktan sonra alfabetik eklenir.
|
|
166
|
+
Ayrıntı: [03-routing.md](./03-routing.md).
|
|
167
|
+
|
|
168
|
+
Şablon tarafı `.jsk` (build-time derlenir):
|
|
169
|
+
|
|
170
|
+
```html
|
|
171
|
+
{# features/home/views/pages/home.jsk #}
|
|
172
|
+
<section class="wrapper">
|
|
173
|
+
<h1>{{ metadata.title }}</h1>
|
|
174
|
+
<p>{{ message }}</p>
|
|
175
|
+
<Button text="Örnek bileşen" />
|
|
176
|
+
<div data-island="counter" data-island-props='{"start":0}'></div>
|
|
177
|
+
</section>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`Button`, `features/home/views/components/button.js` içindeki `button` named
|
|
181
|
+
export'undan gelir — PascalCase etiket; import gerekmez
|
|
182
|
+
([04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md)).
|
|
183
|
+
|
|
184
|
+
## İlk island
|
|
185
|
+
|
|
186
|
+
Island, sunucunun ürettiği HTML'e davranış ekleyen küçük bir modüldür. Sözleşme
|
|
187
|
+
iki parçadan oluşur.
|
|
188
|
+
|
|
189
|
+
**1. Şablonda işaret:** bir elemente `data-island="ad"` verin. Props JSON olarak
|
|
190
|
+
`data-island-props` içinde taşınır.
|
|
191
|
+
|
|
192
|
+
```ejs
|
|
193
|
+
<div data-island="counter" data-island-props='{"start":5}'></div>
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**2. Modülde `mount`:** island `mount(element, props)` adlı bir named export
|
|
197
|
+
verir.
|
|
198
|
+
|
|
199
|
+
```js
|
|
200
|
+
// features/home/client/counter.js
|
|
201
|
+
/**
|
|
202
|
+
* @param {HTMLElement} element
|
|
203
|
+
* @param {{ start?: number }} props
|
|
204
|
+
*/
|
|
205
|
+
export function mount(element, props) {
|
|
206
|
+
let value = props.start ?? 0;
|
|
207
|
+
|
|
208
|
+
const button = document.createElement("button");
|
|
209
|
+
button.type = "button";
|
|
210
|
+
|
|
211
|
+
const paint = () => {
|
|
212
|
+
button.textContent = `Tıklama: ${value}`;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
button.addEventListener("click", () => {
|
|
216
|
+
value += 1;
|
|
217
|
+
paint();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
paint();
|
|
221
|
+
element.append(button);
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**3. Kayıt:** `client/entries/main.js` island adını dinamik import'a bağlar ve
|
|
226
|
+
runtime'ı başlatır.
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
import { registerAll, start } from "jskelet/client";
|
|
230
|
+
|
|
231
|
+
registerAll({
|
|
232
|
+
counter: () => import("../../features/home/client/counter.js"),
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
start();
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Değerlerin dinamik import olması kritik: modül yalnızca sayfada o island
|
|
239
|
+
gerçekten varsa **ve** element görünür hâle geldiğinde indirilir. Yani bu
|
|
240
|
+
haritayı büyütmek ilk yükü büyütmez. Hidrasyon stratejileri
|
|
241
|
+
(`data-island-eager`, `data-island-idle`) ve runtime API'sinin tamamı
|
|
242
|
+
[05-islands.md](./05-islands.md)'de.
|
|
243
|
+
|
|
244
|
+
## CLI komutları
|
|
245
|
+
|
|
246
|
+
`bin/jskelet.mjs` şu alt komutları sunar. Her biri ayrı bir Node sürecinde
|
|
247
|
+
çalışır; sebebi `dev`in iki uzun ömürlü süreci yönetmesi ve sunucunun ESM
|
|
248
|
+
resolve hook'larına (`--import`) süreç başlangıcında ihtiyaç duyması.
|
|
249
|
+
|
|
250
|
+
| Komut | Ne yapar |
|
|
251
|
+
| --- | --- |
|
|
252
|
+
| `jskelet dev` | Build watch + sunucu, tek terminalde. Canlı yenileme, CSS hot-swap, dev overlay. `NODE_ENV=development`. Port doluysa başlamaz; `--murder` dinleyiciyi öldürüp bağlar. |
|
|
253
|
+
| `jskelet build` | Tek seferlik prod build: fontlar → ikon sprite → CSS → client JS → görseller → manifest → precompress. `NODE_ENV` verilmemişse `production`. |
|
|
254
|
+
| `jskelet start` | Prod sunucu. Build çıktısı yoksa önce üretir. `NODE_ENV` verilmemişse `production`. Port davranışı `dev` ile aynı (`--murder`). |
|
|
255
|
+
| `jskelet init` | Bulunduğun dizine feature-first `.jsk` iskeleti kurar; var olan dosyalara dokunmaz. |
|
|
256
|
+
| `jskelet generate` | `feature` / `page` / `island` iskeleti üretir. |
|
|
257
|
+
| `jskelet migrate` | Next.js App Router → JSkelet codemod (`scan` / `apply` / `config`). [11-tasima.md](./11-tasima.md). |
|
|
258
|
+
|
|
259
|
+
Bilinmeyen bir komut ya da argümansız çağrı kullanım metnini basar.
|
|
260
|
+
|
|
261
|
+
Her komut iki Node bayrağıyla çalışır:
|
|
262
|
+
|
|
263
|
+
- `--env-file=.env` — yalnızca dosya gerçekten varsa geçilir; yoksa hiçbir
|
|
264
|
+
bayrak eklenmez ve uyarı basılmaz.
|
|
265
|
+
- `--import <register.mjs>` — `jsconfig.json` / `tsconfig.json` içindeki
|
|
266
|
+
`compilerOptions.paths` alias'larını (`@/lib/x`) ve uzantısız göreli
|
|
267
|
+
import'ları (`./cache` → `./cache.js`) çözen ESM hook'larını kurar.
|
|
268
|
+
(`jskelet dev` bu hook'ları kendi alt süreçlerinde kurar, dış süreçte kurmaz.)
|
|
269
|
+
|
|
270
|
+
## İthal yolları
|
|
271
|
+
|
|
272
|
+
`package.json` → `exports` haritası kararlı yüzeyi tanımlar. Örneklerde
|
|
273
|
+
yalnızca bu belirteçleri kullanın:
|
|
274
|
+
|
|
275
|
+
| Belirteç | İçeriği |
|
|
276
|
+
| --- | --- |
|
|
277
|
+
| `jskelet` | Sunucu API'si: `route`, `renderPage`, `renderView`, `renderNotFound`, `createApp`, `startServer`, `notFound`, `redirect`, `permanentRedirect`, `cache`, `withRequestCache`, `reportUpstreamFailure`, `asset`, `hasAsset`, `optimizedImage`, `getSpriteIds`, `headHints`, `renderHeadMeta`, HTML cache fonksiyonları, `prewarm`, `createProxy`, `getConfig`, `loadConfig` ve html/tag yardımcıları |
|
|
278
|
+
| `jskelet/server` | `jskelet` ile aynı modül (okunurluk için takma ad) |
|
|
279
|
+
| `jskelet/client` | Tarayıcı runtime'ı: `register`, `registerAll`, `hydrate`, `observeDocument`, `start`, `createStore`, DOM yardımcıları, `startSafeImages` |
|
|
280
|
+
| `jskelet/html` | `esc`, `attrs`, `cx`, `cn`, `jsonScript` |
|
|
281
|
+
| `jskelet/tags` | `link`, `image`, `icon`, `preloadImage`, `toKebab` |
|
|
282
|
+
| `jskelet/log` | Konsol çıktısı yardımcıları (`banner`, `event`, `task`, `size`, `ms`, …) |
|
|
283
|
+
| `jskelet/register` | `node --import jskelet/register` ile alias + uzantı hook'ları |
|
|
284
|
+
| `jskelet/layout` | Framework'ün varsayılan `layout.jsk` dosyasının yolu |
|
|
285
|
+
|
|
286
|
+
## Sırada ne var
|
|
287
|
+
|
|
288
|
+
- Neden bu şekilde çalışıyor: [02-mimari.md](./02-mimari.md)
|
|
289
|
+
- Daha fazla route ve yakalayıcı desenler: [03-routing.md](./03-routing.md)
|
|
290
|
+
- Layout'u devralmak ve metadata: [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md)
|
|
291
|
+
- Önbelleği ayarlamak: [06-cache.md](./06-cache.md)
|