jskelet 0.5.5 → 0.6.0
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 +18 -13
- package/CHANGELOG.md +95 -0
- package/README.md +9 -7
- package/bin/jskelet.mjs +24 -10
- package/docs/01-baslangic.md +4 -3
- package/docs/02-mimari.md +4 -3
- package/docs/03-routing.md +11 -6
- package/docs/04-render-ve-sablonlar.md +35 -43
- package/docs/05-islands.md +12 -8
- package/docs/07-yapilandirma.md +40 -18
- package/docs/08-build.md +15 -9
- package/docs/09-dev-araclari.md +5 -1
- package/docs/10-dagitim.md +6 -1
- package/docs/11-tasima.md +51 -17
- package/docs/12-panel-ve-oturum.md +10 -4
- package/docs/README.md +7 -5
- package/docs/en/01-getting-started.md +4 -3
- package/docs/en/02-architecture.md +5 -5
- package/docs/en/03-routing.md +12 -7
- package/docs/en/04-rendering.md +47 -59
- package/docs/en/05-islands.md +13 -8
- package/docs/en/07-configuration.md +40 -20
- package/docs/en/08-build.md +16 -10
- package/docs/en/09-dev-tools.md +6 -1
- package/docs/en/10-deployment.md +6 -1
- package/docs/en/11-migration.md +51 -16
- package/docs/en/12-dashboards-and-sessions.md +9 -4
- package/docs/en/README.md +7 -5
- package/package.json +49 -14
- package/src/build/tasks/client.mjs +91 -10
- package/src/build/tasks/icons.mjs +11 -1
- package/src/client/index.js +2 -2
- package/src/compile/codegen.js +4 -0
- package/src/compile/compile-all.js +12 -21
- package/src/compile/expr.js +5 -0
- package/src/compile/parse.js +64 -8
- package/src/compile/resolve.js +3 -0
- package/src/config/defaults.js +12 -2
- package/src/config/index.js +1 -1
- package/src/dev-server.mjs +26 -3
- package/src/http/cookies-entry.js +1 -0
- package/src/http/cookies.js +18 -0
- package/src/logo.png +0 -0
- package/src/migrate/apply.mjs +262 -0
- package/src/migrate/babel.mjs +79 -0
- package/src/migrate/classify.mjs +155 -0
- package/src/migrate/config.mjs +126 -0
- package/src/migrate/fs-walk.mjs +191 -0
- package/src/migrate/parse.mjs +26 -0
- package/src/migrate/scan.mjs +177 -0
- package/src/migrate/transform/expr-source.mjs +168 -0
- package/src/migrate/transform/island.mjs +67 -0
- package/src/migrate/transform/jsx-to-component.mjs +302 -0
- package/src/migrate/transform/jsx-to-jsk.mjs +330 -0
- package/src/migrate/transform/page-split.mjs +435 -0
- package/src/migrate/write.mjs +81 -0
- package/src/migrate.mjs +171 -0
- package/src/server/auth/handoff.js +94 -11
- package/src/server/create-app.js +28 -10
- package/src/server/ejs-adapter.js +59 -0
- package/src/server/image-optimizer.js +94 -26
- package/src/server/port-guard.js +255 -0
- package/src/server/render.js +27 -9
- package/src/server/status-page.js +105 -4
- package/src/start.mjs +18 -3
- package/src/templates/layout.ejs +8 -28
- package/src/templates/layout.jsk +30 -0
- package/src/templates/layout.render.js +41 -0
- package/src/views/helpers/tags.js +86 -3
- package/types/build/resolve-peer.d.mts +13 -0
- package/types/client/dom.d.ts +55 -0
- package/types/client/form.d.ts +19 -0
- package/types/client/index.d.ts +20 -0
- package/types/client/registry.d.ts +53 -0
- package/types/client/safe-image.d.ts +19 -0
- package/types/client/shared-cookie.d.ts +82 -0
- package/types/client/store.d.ts +18 -0
- package/types/client/swap.d.ts +46 -0
- package/types/compile/codegen.d.ts +32 -0
- package/types/compile/compile-all.d.ts +42 -0
- package/types/compile/errors.d.ts +30 -0
- package/types/compile/expr.d.ts +67 -0
- package/types/compile/index.d.ts +10 -0
- package/types/compile/parse.d.ts +82 -0
- package/types/compile/resolve.d.ts +46 -0
- package/types/compile/scan-exports.d.ts +9 -0
- package/types/config/defaults.d.ts +449 -0
- package/types/config/index.d.ts +299 -0
- package/types/config/pattern.d.ts +38 -0
- package/types/http/control-flow.d.ts +45 -0
- package/types/http/cookies-entry.d.ts +5 -0
- package/types/http/cookies.d.ts +113 -0
- package/types/http/request-cache.d.ts +13 -0
- package/types/http/request-context.d.ts +67 -0
- package/types/http/shared-cookie.d.ts +73 -0
- package/types/index.d.ts +30 -0
- package/types/log.d.mts +153 -0
- package/types/server/admin/actions.d.ts +16 -0
- package/types/server/admin/auth.d.ts +52 -0
- package/types/server/admin/event-log.d.ts +38 -0
- package/types/server/admin/gate.d.ts +43 -0
- package/types/server/admin/inventory.d.ts +40 -0
- package/types/server/admin/mount.d.ts +6 -0
- package/types/server/admin/router.d.ts +6 -0
- package/types/server/admin/snapshot.d.ts +6 -0
- package/types/server/assets.d.ts +47 -0
- package/types/server/auth/handoff.d.ts +12 -0
- package/types/server/cache-deps.d.ts +16 -0
- package/types/server/cache-vary.d.ts +30 -0
- package/types/server/cloudflare.d.ts +163 -0
- package/types/server/create-app.d.ts +25 -0
- package/types/server/data-cache.d.ts +116 -0
- package/types/server/dev/devtools.d.ts +44 -0
- package/types/server/dev/report.d.ts +229 -0
- package/types/server/dev/socket.d.ts +17 -0
- package/types/server/dev/version-check.d.mts +15 -0
- package/types/server/ejs-adapter.d.ts +11 -0
- package/types/server/head-hints.d.ts +40 -0
- package/types/server/html-cache.d.ts +173 -0
- package/types/server/image-optimizer.d.ts +68 -0
- package/types/server/logs/access-middleware.d.ts +7 -0
- package/types/server/logs/file-sink.d.ts +17 -0
- package/types/server/logs/pipeline.d.ts +37 -0
- package/types/server/logs/s3-put.d.ts +85 -0
- package/types/server/logs/s3-sink.d.ts +26 -0
- package/types/server/metadata.d.ts +38 -0
- package/types/server/middleware/compression.d.ts +17 -0
- package/types/server/middleware/csrf.d.ts +4 -0
- package/types/server/middleware/dev-gate.d.ts +2 -0
- package/types/server/middleware/headers.d.ts +2 -0
- package/types/server/middleware/redirects.d.ts +2 -0
- package/types/server/middleware/static-precompressed.d.ts +5 -0
- package/types/server/middleware/trailing-slash.d.ts +11 -0
- package/types/server/middleware/upstream-proxy.d.ts +21 -0
- package/types/server/og-image.d.ts +149 -0
- package/types/server/port-guard.d.ts +50 -0
- package/types/server/prewarm.d.ts +128 -0
- package/types/server/redis.d.ts +163 -0
- package/types/server/render.d.ts +101 -0
- package/types/server/router.d.ts +5 -0
- package/types/server/status-page.d.ts +24 -0
- package/types/server/upstream-limiter.d.ts +123 -0
- package/types/server/upstream-tracking.d.ts +42 -0
- package/types/shared/cookie-domain.d.ts +29 -0
- package/types/templates/layout.render.d.ts +7 -0
- package/types/version.d.mts +10 -0
- package/types/views/components/loader.d.ts +5 -0
- package/types/views/helpers/html.d.ts +39 -0
- package/types/views/helpers/tags.d.ts +127 -0
package/docs/08-build.md
CHANGED
|
@@ -167,8 +167,9 @@ etmezdi. Değişiklikler 120 ms birleştirilir.
|
|
|
167
167
|
|
|
168
168
|
## Client JS — esbuild
|
|
169
169
|
|
|
170
|
-
`client/entries/*.js` içindeki her
|
|
171
|
-
|
|
170
|
+
`client/entries/*.{js,ts,mts}` içindeki her kaynak dosya bir entry'dir (`.tsx`
|
|
171
|
+
yok). Manifest anahtarı her zaman `*.js` olur (`main.ts` → `main.js`). Aynı stem
|
|
172
|
+
için birden fazla uzantı build hatasıdır. Dizin yoksa ya da boşsa adım atlanır.
|
|
172
173
|
|
|
173
174
|
esbuild ayarları:
|
|
174
175
|
|
|
@@ -178,7 +179,7 @@ esbuild ayarları:
|
|
|
178
179
|
| `format` | `esm` | `type="module"` script'ler |
|
|
179
180
|
| `target` | `chrome111`, `edge111`, `firefox111`, `safari16.4` | ESM + dinamik import + `IntersectionObserver` island modelinin alt sınırı; daha eskisine transpile etmek çıktıyı büyütüp hiçbir ziyaretçi kazandırmıyor |
|
|
180
181
|
| `minify` | `true` | — |
|
|
181
|
-
| `sourcemap` | `
|
|
182
|
+
| `sourcemap` | yalnızca `NODE_ENV=development` | Prod'da `.map` dosyaları `public/assets` altında yayınlanmaz |
|
|
182
183
|
| `entryNames` | `[name].[hash]` | `immutable` cache |
|
|
183
184
|
| `chunkNames` | `chunks/[name].[hash]` | — |
|
|
184
185
|
| `legalComments` | `none` | — |
|
|
@@ -189,16 +190,19 @@ esbuild ayarları:
|
|
|
189
190
|
### `@/` alias'ı
|
|
190
191
|
|
|
191
192
|
esbuild tarafında `@/` proje köküne çözülür ve uzantı tamamlama yapılır
|
|
192
|
-
(`.js`, `.mjs`, `.json`, `/index.js`). Node
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
(`.js`, `.mjs`, `.ts`, `.mts`, `.json`, `/index.js`, `/index.ts`). Node
|
|
194
|
+
`alias-hooks.mjs` sunucuda yalnızca `.js` / `.mjs` / `.json` çözer; paylaşılan
|
|
195
|
+
`@/lib` dosyaları bu yüzden `.js` kalmalıdır. Client-only `.ts` import'ları
|
|
196
|
+
esbuild hattında çalışır.
|
|
195
197
|
|
|
196
198
|
### `clientEnv` gömülmesi
|
|
197
199
|
|
|
198
200
|
Tarayıcıda `process` yoktur; sunucuyla paylaşılan modüller yine de `process.env`
|
|
199
201
|
okur. `config.clientEnv` ile bildirilen anahtarlar ve `NODE_ENV` build zamanında
|
|
200
202
|
tek nesne olarak define edilir, yani listede olmayan bir anahtar okunduğunda
|
|
201
|
-
çökme yerine `undefined` döner.
|
|
203
|
+
çökme yerine `undefined` döner. İsimleri secret benzeri olan anahtarlar
|
|
204
|
+
(`SECRET`, `API_KEY`, …) build'i düşürür; `PUBLIC` / `PUBLISHABLE` içerenler
|
|
205
|
+
muaf. Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
|
|
202
206
|
|
|
203
207
|
### Manifest anahtarları
|
|
204
208
|
|
|
@@ -274,7 +278,7 @@ Yerel dosya adları:
|
|
|
274
278
|
(Phosphor ve `icon()` ile uyum için önerilen kutu).
|
|
275
279
|
- Taranan dizinler varsayılan olarak `views`, `client`, `routes`, `lib`,
|
|
276
280
|
`features`, `shared`; `icons.scan` ile değiştirilebilir. Taranan uzantılar:
|
|
277
|
-
`.ejs`, `.jsk`, `.js`, `.mjs`.
|
|
281
|
+
`.ejs`, `.jsk`, `.js`, `.mjs`, `.ts`, `.mts`.
|
|
278
282
|
- Ağırlıklar: `thin`, `light`, `regular`, `bold`, `fill`, `duotone`. Tanınmayan
|
|
279
283
|
bir ağırlık `regular` sayılır.
|
|
280
284
|
|
|
@@ -339,7 +343,9 @@ orijinal dosyaya döner. Watch turunda hiç çalışmaz.
|
|
|
339
343
|
`images.remote.allowHosts` verilirse `createApp` `/_jskelet/image` ucunu
|
|
340
344
|
mount eder. CMS / CDN kapakları build'e girmediği için `image()` bu host'lardaki
|
|
341
345
|
URL'leri `?url=&w=` biçiminde yeniden yazar; uç sharp ile webp üretir ve
|
|
342
|
-
`.jskelet/image-cache/` altına yazar.
|
|
346
|
+
`.jskelet/image-cache/` altına yazar. Upstream fetch redirect'leri elle takip
|
|
347
|
+
edilir: her hop allowlist + private IP / DNS kontrolünden geçer (açık redirect
|
|
348
|
+
SSRF kapalı). Ayrıntı: [07-yapilandirma.md](./07-yapilandirma.md).
|
|
343
349
|
|
|
344
350
|
## Precompress
|
|
345
351
|
|
package/docs/09-dev-araclari.md
CHANGED
|
@@ -21,6 +21,10 @@ jskelet dev
|
|
|
21
21
|
bastırır) ve TTY varsa `JSKELET_COLOR=1` (borulanmış çıktıda renk zorlar)
|
|
22
22
|
geçirilir.
|
|
23
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
|
+
|
|
24
28
|
Açılış sırası: banner → build adımları → sunucu hazır → `Ready` özeti. Özet hem
|
|
25
29
|
build hem sunucu hazır olduğunda basılır; aksi hâlde arkadan gelen build
|
|
26
30
|
satırlarının arasında kalıyordu.
|
|
@@ -70,7 +74,7 @@ WATCH_DIRS = [
|
|
|
70
74
|
Ayrıca `jskelet.config.mjs` dosyasının kendisi izlenir: config değişince hem
|
|
71
75
|
sunucu hem build yeni ayarlarla açılmalı.
|
|
72
76
|
|
|
73
|
-
İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.ejs`.
|
|
77
|
+
İzlenen uzantılar: `.js`, `.mjs`, `.json`, `.jsk`, `.ejs`.
|
|
74
78
|
|
|
75
79
|
`views` de izlenir çünkü bileşenlerin çoğu `views/components/**.js` içinde ve bu
|
|
76
80
|
modüller sunucuya bir kez import edildiği için, restart olmadan yapılan
|
package/docs/10-dagitim.md
CHANGED
|
@@ -23,6 +23,10 @@ kendisi çalıştırır. Docker imajında build zaten yapıldığı için bu bir
|
|
|
23
23
|
amaç `npm start`ı doğrudan çalıştıran birinin stilsiz bir sayfayla
|
|
24
24
|
karşılaşmaması.
|
|
25
25
|
|
|
26
|
+
Port doluysa süreç **başlamaz** (PID + ipucu). `jskelet start --murder` o
|
|
27
|
+
porttaki dinleyiciyi öldürüp bağlar — geliştirmede unutulmuş bir süreç için;
|
|
28
|
+
üretim orkestratöründe genelde gerekmez.
|
|
29
|
+
|
|
26
30
|
Sunucu hazır olduğunda tek satır basar:
|
|
27
31
|
|
|
28
32
|
```
|
|
@@ -63,7 +67,8 @@ değerin geçerli olduğunu belirsizleştirir; prod imajında `.env` bulundurmam
|
|
|
63
67
|
temizidir.
|
|
64
68
|
|
|
65
69
|
**Gizli anahtarlar `clientEnv` listesine konmamalıdır:** oradaki değerler client
|
|
66
|
-
bundle'a düz metin olarak gömülür ([08-build.md](./08-build.md)).
|
|
70
|
+
bundle'a düz metin olarak gömülür ([08-build.md](./08-build.md)). Secret benzeri
|
|
71
|
+
isimler (`SECRET`, `API_KEY`, …) artık build'i düşürür.
|
|
67
72
|
|
|
68
73
|
## Docker
|
|
69
74
|
|
package/docs/11-tasima.md
CHANGED
|
@@ -7,6 +7,29 @@ alt kümesine benzetildi — `next.config` sözdizimi, Metadata API, `notFound()
|
|
|
7
7
|
`revalidate`, `cache()` gibi kavramlar tanıdık gelecek. Farkların *nedenleri*
|
|
8
8
|
[02-mimari.md](./02-mimari.md)'de.
|
|
9
9
|
|
|
10
|
+
## `jskelet migrate` (codemod)
|
|
11
|
+
|
|
12
|
+
App Router ağacına karşı codemod'u çalıştırın. Babel (`@babel/parser`,
|
|
13
|
+
`@babel/types`) JSkelet ile birlikte gelir — ek kurulum yok.
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx jskelet migrate scan ../my-next-app
|
|
17
|
+
npx jskelet migrate apply ../my-next-app --out . --write
|
|
18
|
+
npx jskelet migrate config ../my-next-app --write
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
| Komut | Ne yapar |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `migrate` / `migrate scan` | Sayfa, layout, `"use client"` modülleri ve engelleri (iç içe layout, Server Actions, Suspense) listeler. |
|
|
24
|
+
| `migrate apply` | **Otomatik çeviri:** `page.*` → feature controller + `.jsk`; presentational bileşenler → `views/components/*.js`; client → island `mount()` iskeleti. Varsayılan dry-run; yazmak için `--write`. Üzerine yazmaz (çakışmada `.migrate` soneki). |
|
|
25
|
+
| `migrate config` | `next.config`'ten `jskelet.config.mjs` taslağı (`headers` / `redirects` / `rewrites`, `images.widths`, `NEXT_PUBLIC_*` → `clientEnv`). |
|
|
26
|
+
|
|
27
|
+
Bayraklar: `--out <dir>`, `--only pages,components,islands`, `--json`, `--strict` (partial/skipped → exit 1).
|
|
28
|
+
|
|
29
|
+
**Otomatik çevrilenler:** `className`, `{{ }}` / `{{{ }}}`, `{#if}` / `{#each}`, `next/image` → `<Image />`, `next/link` → `<Link />`, `dangerouslySetInnerHTML`, `revalidate`, basit controller prelude.
|
|
30
|
+
|
|
31
|
+
**Çevrilmeyenler (raporlanır):** React hooks, Server Actions, iç içe layout düzleştirme, Streaming/Suspense, client routing. Dosya başına `ok` / `partial` / `skipped`.
|
|
32
|
+
|
|
10
33
|
## Karşılık tablosu
|
|
11
34
|
|
|
12
35
|
### Yapılandırma
|
|
@@ -30,8 +53,8 @@ alt kümesine benzetildi — `next.config` sözdizimi, Metadata API, `notFound()
|
|
|
30
53
|
| `app/page.js` (dosya bazlı routing) | `routes/*.mjs` içinde `app.get(...)` | Sıra açık yazılır ([03](./03-routing.md)) |
|
|
31
54
|
| `app/[slug]/page.js` | `app.get("/:slug", route(...))` | Express desen sözdizimi |
|
|
32
55
|
| `params`, `searchParams` | `ctx.params`, `ctx.query` | Controller'ın tek argümanı |
|
|
33
|
-
| `layout.js` | `views/layout.
|
|
34
|
-
| Sunucu bileşeni (RSC) | Controller +
|
|
56
|
+
| `layout.js` | `views/layout.jsk` + `hooks.layoutContext()` | Tek layout; iç içe layout yok |
|
|
57
|
+
| Sunucu bileşeni (RSC) | Controller + `.jsk` şablonu + `views/components/**` | Fonksiyon HTML string döndürür |
|
|
35
58
|
| İstemci bileşeni (`"use client"`) | Island (`data-island` + `mount`) | Sayfanın tamamı hidre edilmez ([05](./05-islands.md)) |
|
|
36
59
|
| `notFound()` | `notFound()` | Aynı ad, aynı kontrol akışı |
|
|
37
60
|
| `redirect()` | `redirect()` (307) | Kalıcı için `permanentRedirect()` (308) |
|
|
@@ -87,10 +110,13 @@ Bunları taşıma planında baştan hesaba katın:
|
|
|
87
110
|
|
|
88
111
|
- **React'in kendisi.** Bileşenler HTML string döndüren fonksiyonlara dönüşür.
|
|
89
112
|
JSX yok, hook yok, sanal DOM yok.
|
|
90
|
-
- **TypeScript.**
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
113
|
+
- **TypeScript.** Framework kaynağı düz JS + JSDoc'tur ve tüketiciler için
|
|
114
|
+
`.d.ts` yayınlar. Client entry/island'lar `.ts` / `.mts` olabilir (esbuild tip
|
|
115
|
+
siler; manifest anahtarı `*.js` kalır). Sunucu route, hook ve
|
|
116
|
+
`jskelet.config.mjs` Node ESM JavaScript kalır — orada editör denetimi için
|
|
117
|
+
`jsconfig.json` içinde `checkJs: true` kullanın.
|
|
118
|
+
- **İç içe layout'lar.** Tek bir layout var; ortak bölümleri `{#include}` ya da
|
|
119
|
+
bileşen fonksiyonlarıyla paylaşırsınız (legacy EJS’te `include`).
|
|
94
120
|
- **Streaming / Suspense / kısmi prerender.** Yanıt tek parça üretilir.
|
|
95
121
|
- **İstemci tarafı yönlendirme.** Gezinme gerçek sayfa yüklemesidir. Sunucu HTML'i
|
|
96
122
|
önbellekten geldiği için pratikte çok hızlıdır, ama SPA geçişleri yoktur.
|
|
@@ -169,12 +195,12 @@ export default function register(app, { route, notFound }) {
|
|
|
169
195
|
}
|
|
170
196
|
```
|
|
171
197
|
|
|
172
|
-
```
|
|
173
|
-
|
|
198
|
+
```jsk
|
|
199
|
+
{# views/pages/article.jsk #}
|
|
174
200
|
<article class="wrapper">
|
|
175
|
-
<h1 class="text-3xl font-bold"
|
|
176
|
-
|
|
177
|
-
<div
|
|
201
|
+
<h1 class="text-3xl font-bold">{{ article.title }}</h1>
|
|
202
|
+
<Image :src="article.cover" :alt="article.title" priority :width="1200" :height="630" />
|
|
203
|
+
<div>{{{ article.body }}}</div>
|
|
178
204
|
</article>
|
|
179
205
|
```
|
|
180
206
|
|
|
@@ -188,12 +214,16 @@ de aynı yazıyı isterse tek upstream isteği yapılmasını sağlar
|
|
|
188
214
|
|
|
189
215
|
Yeni bir dizinde `npx jskelet init` çalıştırın ve `jskelet dev`in açıldığını
|
|
190
216
|
görün. Mevcut Next projesini olduğu gibi bırakın; taşıma paralel yürüsün.
|
|
217
|
+
İsterseniz önce `jskelet migrate scan <next-root>` ile sayfa ve engel listesine bakın.
|
|
191
218
|
|
|
192
219
|
`jsconfig.json` içindeki `paths` alias'larınızı taşıyın — `@/` gibi önekler hem
|
|
193
220
|
sunucuda hem bundle'da aynı şekilde çalışır ([02-mimari.md](./02-mimari.md)).
|
|
194
221
|
|
|
195
222
|
### 2. `next.config.mjs`'i çevir (1-2 saat)
|
|
196
223
|
|
|
224
|
+
`jskelet migrate config <next-root> --write` çoğunu taslaklar; ardından gözden
|
|
225
|
+
geçirin:
|
|
226
|
+
|
|
197
227
|
`headers()`, `redirects()` ve `rewrites()` bölümleri neredeyse birebir kopyalanır.
|
|
198
228
|
Desen sözdizimini kontrol edin: JSkelet `:slug`, `:path*`, `/a-:b` ve
|
|
199
229
|
`/:path*.svg` biçimlerini destekler; daha karmaşık `path-to-regexp` ifadeleri
|
|
@@ -214,9 +244,9 @@ değildir; olduğu gibi kopyalanır. İki değişiklik yapın:
|
|
|
214
244
|
|
|
215
245
|
### 4. Layout'u kur (yarım gün)
|
|
216
246
|
|
|
217
|
-
`app/layout.jsx`'i `views/layout.
|
|
218
|
-
layout'unu (`
|
|
219
|
-
üzerine yazmak en hızlı yol.
|
|
247
|
+
`app/layout.jsx`'i `views/layout.jsk`'e çevirin (veya `migrate apply` taslağını
|
|
248
|
+
kullanın). Framework'ün varsayılan layout'unu (`jskelet/layout` → `.jsk`)
|
|
249
|
+
kopyalayıp üzerine yazmak en hızlı yol.
|
|
220
250
|
|
|
221
251
|
`layout.jsx` içinde veri çekiyorsanız (navigasyon, site ayarları) bunu
|
|
222
252
|
`hooks.layoutContext()` içine taşıyın: gövde render'ıyla paralel çalışır ve
|
|
@@ -227,6 +257,9 @@ Global metadata varsayılanlarını (`titleTemplate`, `siteUrl`, `description`)
|
|
|
227
257
|
|
|
228
258
|
### 5. Bileşenleri çevir (en uzun adım)
|
|
229
259
|
|
|
260
|
+
`jskelet migrate apply --only components --write` hooks'suz presentational
|
|
261
|
+
bileşenleri çevirir. Gerisini elle bitirin:
|
|
262
|
+
|
|
230
263
|
Her React bileşeni bir fonksiyona dönüşür:
|
|
231
264
|
|
|
232
265
|
```jsx
|
|
@@ -260,8 +293,9 @@ Bileşenleri küçük ve saf tutun; veri çekmeyi controller'da bırakın.
|
|
|
260
293
|
|
|
261
294
|
### 6. Sayfaları taşı (sayfa başına saatler)
|
|
262
295
|
|
|
263
|
-
|
|
264
|
-
|
|
296
|
+
`jskelet migrate apply --only pages --write` her `page.*` dosyasını feature
|
|
297
|
+
controller + `.jsk` şablonuna böler. `partial` / `skipped` satırlarını gözden
|
|
298
|
+
geçirip TODO'ları bitirin. Sırayı düşünerek dosyalayın:
|
|
265
299
|
|
|
266
300
|
```
|
|
267
301
|
routes/
|
|
@@ -337,7 +371,7 @@ redirect kurallarının doğruluğunu ölçmek için işe yarar.
|
|
|
337
371
|
## Taşıma sırasında sık yapılan hatalar
|
|
338
372
|
|
|
339
373
|
- **`esc()` unutmak.** JSX'ten gelen alışkanlıkla `${value}` yazmak XSS demektir.
|
|
340
|
-
|
|
374
|
+
`.jsk`'de `{{ }}` (kaçışlı) / `{{{ }}}` (ham); bileşenlerde `esc()` kendiniz.
|
|
341
375
|
- **`@source` eklemeden yeni bir dizin açmak.** Sınıflar sessizce düşer.
|
|
342
376
|
- **Yakalayıcı route'u yanlış sıraya koymak.** `/:slug` her zaman en sonda.
|
|
343
377
|
- **Sayfanın tamamını island yapmak.** Kazanç sunucu HTML'inin tam olmasından
|
|
@@ -143,7 +143,9 @@ export default {
|
|
|
143
143
|
sharedCookieRoots: [".investvio.com", ".localhost"],
|
|
144
144
|
},
|
|
145
145
|
auth: {
|
|
146
|
-
crossSubdomainHandoff:
|
|
146
|
+
crossSubdomainHandoff: {
|
|
147
|
+
allowedCookieNames: ["sid"], // zorunlu allowlist
|
|
148
|
+
},
|
|
147
149
|
},
|
|
148
150
|
};
|
|
149
151
|
```
|
|
@@ -207,15 +209,19 @@ okunur. Yazımdan sonra **read-back** yapılır; tarayıcı Domain'i reddettiyse
|
|
|
207
209
|
|
|
208
210
|
`auth.crossSubdomainHandoff` açıkken:
|
|
209
211
|
|
|
210
|
-
1. `POST /_jskelet/auth/handoff` `{ name, value, next }` → `{ url }` (`?handoff=` ekli)
|
|
212
|
+
1. `POST /_jskelet/auth/handoff` `{ name, value, next }` → `{ url }` (`?handoff=` ekli).
|
|
213
|
+
Mint, CSRF middleware'inden **sonra** mount edilir; `name`
|
|
214
|
+
`allowedCookieNames` içinde ve RFC 6265 token olmalı.
|
|
211
215
|
2. Hedef host'ta GET middleware bileti tek kullanımlık tüketir, cookie yazar
|
|
212
216
|
(önce shared Domain, olmazsa host-only), `handoff` query'siz 303
|
|
213
217
|
|
|
214
218
|
`next` yalnızca aynı `sharedCookieRoots` altındaki host'lara izinli. Bilet
|
|
215
|
-
~60 sn, süreç belleğinde
|
|
219
|
+
~60 sn, süreç belleğinde; bekleyen bilet ve IP başına mint sınırı vardır.
|
|
220
|
+
JWT URL'ye konmaz.
|
|
216
221
|
|
|
217
222
|
`window.name` köprüsü cookie'siz yedek: kaynakta `handoffViaWindowName`,
|
|
218
|
-
hedeefte `consumeWindowNameHandoff`.
|
|
223
|
+
hedeefte `consumeWindowNameHandoff`. Cross-origin tab'da `window.name`
|
|
224
|
+
okunabilir kalır — mümkünse sunucu handoff tercih edin.
|
|
219
225
|
|
|
220
226
|
## CSRF
|
|
221
227
|
|
package/docs/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# JSkelet belgeleri
|
|
2
2
|
|
|
3
3
|
JSkelet, SEO ve hız odaklı siteler için "framework'süz hissettiren" bir
|
|
4
|
-
framework: Express 5 +
|
|
5
|
-
island'larla ekler, CSS'i
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
framework: Express 5 + build-time `.jsk` ile sunucuda tam HTML üretir (EJS
|
|
5
|
+
opsiyonel legacy peer), etkileşimi vanilla JS island'larla ekler, CSS'i
|
|
6
|
+
Tailwind v4 ile tek bir stylesheet'e derler ve ISR yerine süreç belleğinde
|
|
7
|
+
yaşayan, stale-while-revalidate'li bir HTML TTL cache kullanır. React yok;
|
|
8
|
+
framework kaynağı düz JavaScript + JSDoc'tur. Uygulama tarafında client
|
|
9
|
+
island/entry'ler TypeScript yazılabilir ve paket `.d.ts` yayınlar.
|
|
8
10
|
|
|
9
11
|
Bu dizin framework'ün tam referansıdır. Sıralı okumak için baştan başlayın;
|
|
10
12
|
belirli bir konuyu arıyorsanız doğrudan ilgili başlığa gidin.
|
|
@@ -19,7 +21,7 @@ eşlenik tutuluyor; birini değiştiriyorsan diğerini de değiştir.
|
|
|
19
21
|
| [01-baslangic.md](./01-baslangic.md) | Kurulum, `jskelet init`, ilk route, ilk island, dizin yapısı, CLI komutları |
|
|
20
22
|
| [02-mimari.md](./02-mimari.md) | Mimari kararlar ve gerekçeleri: island modeli, tam sunucu HTML'i, cache stratejisi, middleware sırası |
|
|
21
23
|
| [03-routing.md](./03-routing.md) | Route modülü sözleşmesi, yükleme sırası, controller sözleşmesi, `ctx`, `notFound`/`redirect`, config redirects/rewrites |
|
|
22
|
-
| [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md) |
|
|
24
|
+
| [04-render-ve-sablonlar.md](./04-render-ve-sablonlar.md) | `.jsk` layout/sayfalar, otomatik bileşen kaydı, `html`/`tags`, metadata → `<head>`, hook'lar; EJS legacy |
|
|
23
25
|
| [05-islands.md](./05-islands.md) | `data-island` sözleşmesi, hidrasyon stratejileri, `client/entries/*`, `createStore`, DOM yardımcıları, `startSafeImages` |
|
|
24
26
|
| [06-cache.md](./06-cache.md) | `withHtmlCache`, `revalidate`, stale-while-revalidate, cache anahtarı, `X-JSkelet-Cache`, istek içi cache, degraded render, prewarm |
|
|
25
27
|
| [07-yapilandirma.md](./07-yapilandirma.md) | `jskelet.config.mjs` tam referansı, `source` desen sözdizimi, ortam değişkenleri tablosu |
|
|
@@ -255,11 +255,12 @@ ESM resolve hooks (`--import`) at process start.
|
|
|
255
255
|
|
|
256
256
|
| Command | What it does |
|
|
257
257
|
| --- | --- |
|
|
258
|
-
| `jskelet dev` | Build watch + server, in a single terminal. Live reload, CSS hot-swap, dev overlay. `NODE_ENV=development`. |
|
|
258
|
+
| `jskelet dev` | Build watch + server, in a single terminal. Live reload, CSS hot-swap, dev overlay. `NODE_ENV=development`. Refuses to start if the port is busy; `--murder` kills the listener and binds. |
|
|
259
259
|
| `jskelet build` | One-shot prod build: fonts → icon sprite → CSS → client JS → images → manifest → precompress. `production` if `NODE_ENV` is not given. |
|
|
260
|
-
| `jskelet start` | Prod server. If there is no build output it produces it first. `production` if `NODE_ENV` is not given. |
|
|
260
|
+
| `jskelet start` | Prod server. If there is no build output it produces it first. `production` if `NODE_ENV` is not given. Same port behaviour as `dev` (`--murder`). |
|
|
261
261
|
| `jskelet init` | Installs a feature-first `.jsk` skeleton into the current directory; leaves existing files alone. |
|
|
262
262
|
| `jskelet generate` | Scaffolds a `feature` / `page` / `island`. |
|
|
263
|
+
| `jskelet migrate` | Next.js App Router → JSkelet codemod (`scan` / `apply` / `config`). See [11-migration.md](./11-migration.md). |
|
|
263
264
|
|
|
264
265
|
An unknown command, or a call with no arguments, prints the usage text.
|
|
265
266
|
|
|
@@ -287,7 +288,7 @@ only these specifiers:
|
|
|
287
288
|
| `jskelet/tags` | `link`, `image`, `icon`, `preloadImage`, `toKebab` |
|
|
288
289
|
| `jskelet/log` | Console output helpers (`banner`, `event`, `task`, `size`, `ms`, …) |
|
|
289
290
|
| `jskelet/register` | Alias + extension hooks via `node --import jskelet/register` |
|
|
290
|
-
| `jskelet/layout` | The path to the framework's default `layout.
|
|
291
|
+
| `jskelet/layout` | The path to the framework's default `layout.jsk` file |
|
|
291
292
|
|
|
292
293
|
## What's next
|
|
293
294
|
|
|
@@ -51,7 +51,7 @@ Request
|
|
|
51
51
|
│ └─ withHtmlCache TTL + stale-while-revalidate
|
|
52
52
|
│ └─ withUpstreamTracking
|
|
53
53
|
│ └─ withRequestCache
|
|
54
|
-
│ └─ controller → renderPage → EJS
|
|
54
|
+
│ └─ controller → renderPage → .jsk (or legacy EJS)
|
|
55
55
|
├─ 404 → hooks.notFound()
|
|
56
56
|
└─ error handling redirect/notFound + 500 fallback
|
|
57
57
|
```
|
|
@@ -270,10 +270,10 @@ hard-to-diagnose problems like "why is there no stylesheet".
|
|
|
270
270
|
|
|
271
271
|
## Why this dependency list
|
|
272
272
|
|
|
273
|
-
There are
|
|
274
|
-
`
|
|
275
|
-
Phosphor icons) is an **optional
|
|
276
|
-
corresponding build step is skipped.
|
|
273
|
+
There are three runtime dependencies: `express`, `esbuild`, `tailwind-merge`.
|
|
274
|
+
`ejs` is an optional peer only for legacy `.ejs` templates. Everything else
|
|
275
|
+
(Tailwind, PostCSS, lightningcss, sharp, the Phosphor icons) is an **optional
|
|
276
|
+
peer dependency**, and if it is absent the corresponding build step is skipped.
|
|
277
277
|
|
|
278
278
|
Two decisions deserve a separate explanation:
|
|
279
279
|
|
package/docs/en/03-routing.md
CHANGED
|
@@ -213,7 +213,7 @@ fields:
|
|
|
213
213
|
|
|
214
214
|
| Field | Type | Default | Meaning |
|
|
215
215
|
| --- | --- | --- | --- |
|
|
216
|
-
| `view` | `string` | — | The template path under `views/`, without the extension: `"pages/home"` → `views/pages/home.ejs
|
|
216
|
+
| `view` | `string` | — | The template path under `views/`, without the extension: `"pages/home"` → `views/pages/home.jsk` (else legacy `.ejs`). |
|
|
217
217
|
| `data` | `object` | `{}` | Data passed to the template as locals. |
|
|
218
218
|
| `metadata` | `object` | `{}` | Turned into `<head>` tags; it overrides the output of `hooks.metadata()`. Schema: [04-rendering.md](./04-rendering.md). |
|
|
219
219
|
| `status` | `number` | `200` | The HTTP status code. Only 200 is written to the cache. |
|
|
@@ -332,13 +332,18 @@ handler kicks in, logs the error and returns the framework's own error page with
|
|
|
332
332
|
`Cache-Control: no-store`. The status code is read from the error's `statusCode`
|
|
333
333
|
(or `status`) field; if it is not in the 400–599 range, 500 is used.
|
|
334
334
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
to `en`).
|
|
335
|
+
**Development** (`NODE_ENV=development`, i.e. `jskelet dev`): for 5xx responses
|
|
336
|
+
the built-in 500 page and `hooks.error()` are skipped; a diagnostic page with
|
|
337
|
+
the message, stack trace, and any `cause` chain is returned instead. 4xx (404
|
|
338
|
+
and friends) still use the usual status page in development.
|
|
340
339
|
|
|
341
|
-
|
|
340
|
+
**Production**: the framework's page is deliberately plain — status code, a
|
|
341
|
+
one-line heading and a one-line description. It carries no brand name, no
|
|
342
|
+
navigation and no error detail; the innards of the server are not opened up to
|
|
343
|
+
the visitor. The language comes from `brand.lang` (`tr` and `en` are built in,
|
|
344
|
+
others fall back to `en`).
|
|
345
|
+
|
|
346
|
+
To provide your own page, `hooks.error()` (production / 4xx only):
|
|
342
347
|
|
|
343
348
|
```js
|
|
344
349
|
// jskelet.config.mjs
|
package/docs/en/04-rendering.md
CHANGED
|
@@ -52,7 +52,7 @@ controller data → imported render(data, helpers) → HTML
|
|
|
52
52
|
{/if}
|
|
53
53
|
|
|
54
54
|
{#each items as item, i}
|
|
55
|
-
<li data-i="
|
|
55
|
+
<li :data-i="i">{{ item }}</li>
|
|
56
56
|
{/each}
|
|
57
57
|
|
|
58
58
|
<Link href="/" text="Home" />
|
|
@@ -68,7 +68,7 @@ controller data → imported render(data, helpers) → HTML
|
|
|
68
68
|
| Loop | `{#each list as item}` or `as item, i` |
|
|
69
69
|
| Include | `{#include "partials/header"}` (compiled `.jsk`) |
|
|
70
70
|
| Component | PascalCase tag; `:prop="expr"`, `prop="literal"`, boolean `disabled` |
|
|
71
|
-
| Built-ins | `Link`, `Image`, `Icon`, `CsrfField`, `PreloadImage` |
|
|
71
|
+
| Built-ins | `Link`, `Image`, `Icon`, `CsrfField`, `PreloadImage`, `Stylesheets`, `BodyScripts`, `JsonLd` |
|
|
72
72
|
|
|
73
73
|
The expression language is intentionally small (access, compare, ternary,
|
|
74
74
|
`.length`). No assignments, object literals, or arbitrary calls — keep logic in
|
|
@@ -104,12 +104,15 @@ See the extension README for details.
|
|
|
104
104
|
|
|
105
105
|
If a compiled `.jsk` exists for a view id it wins; otherwise `.ejs` is rendered
|
|
106
106
|
with EJS. Existing apps keep working unchanged. `jskelet init` scaffolds `.jsk`.
|
|
107
|
+
Legacy `.ejs` needs the optional `ejs` peer installed in the application
|
|
108
|
+
(`npm install ejs`); without it only `.jsk` templates run.
|
|
107
109
|
|
|
108
110
|
## The EJS engine (legacy)
|
|
109
111
|
|
|
110
|
-
EJS remains supported
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
EJS remains supported as an **optional peer dependency** for legacy templates.
|
|
113
|
+
The engine is set up once on the first render; the component scan touches the
|
|
114
|
+
file system, so it cannot be done on every request and cannot be computed
|
|
115
|
+
before the config is loaded.
|
|
113
116
|
|
|
114
117
|
Settings:
|
|
115
118
|
|
|
@@ -130,66 +133,54 @@ normal flow because the dev server restarts the process.
|
|
|
130
133
|
|
|
131
134
|
1. `jskelet.config.mjs` → if `layout` is given, it is used. The path is
|
|
132
135
|
resolved relative to the **parent directory of the views directory**: if
|
|
133
|
-
`views` is the default, `layout: "views/custom.
|
|
136
|
+
`views` is the default, `layout: "views/custom.jsk"` → `<root>/views/custom.jsk`.
|
|
134
137
|
2. If it is not given and `views/layout.jsk` exists (compiled), that is used.
|
|
135
|
-
3. Else if `views/layout.ejs` exists, that is used.
|
|
138
|
+
3. Else if `views/layout.ejs` exists (legacy), that is used.
|
|
136
139
|
4. If that does not exist either, the framework's own minimal layout is used
|
|
137
|
-
(`node_modules/jskelet/src/templates/layout.
|
|
140
|
+
(`node_modules/jskelet/src/templates/layout.jsk`, also reachable through the
|
|
138
141
|
`jskelet/layout` specifier).
|
|
139
142
|
|
|
140
143
|
These fallbacks exist so that a new project can work with a single route. The
|
|
141
144
|
most practical way to move to your own layout is to copy that file to
|
|
142
|
-
`views/layout.
|
|
145
|
+
`views/layout.jsk`.
|
|
143
146
|
|
|
144
147
|
### The framework's default layout
|
|
145
148
|
|
|
146
|
-
```
|
|
149
|
+
```html
|
|
147
150
|
<!DOCTYPE html>
|
|
148
|
-
<html lang="
|
|
151
|
+
<html :lang="lang">
|
|
149
152
|
<head>
|
|
150
153
|
<meta charset="utf-8">
|
|
151
154
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
<% styles.forEach(function (sheet) { %>
|
|
157
|
-
<% if (hasAsset(sheet)) { %>
|
|
158
|
-
<link rel="stylesheet" href="<%= asset(sheet) %>" data-jskelet-css="<%= sheet %>">
|
|
159
|
-
<% } %>
|
|
160
|
-
<% }); %>
|
|
161
|
-
<%- headMeta %>
|
|
162
|
-
<% structuredData.forEach(function (item) { %>
|
|
163
|
-
<script type="application/ld+json"><%- jsonScript(item) %></script>
|
|
164
|
-
<% }); %>
|
|
155
|
+
{{{ extraHead }}}
|
|
156
|
+
<Stylesheets :styles="styles" />
|
|
157
|
+
{{{ headMeta }}}
|
|
158
|
+
<JsonLd :items="structuredData" />
|
|
165
159
|
</head>
|
|
166
|
-
<body class="
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
<script type="module" src="<%= asset('main.js') %>"></script>
|
|
170
|
-
<% } %>
|
|
171
|
-
<% entries.forEach(function (entry) { %>
|
|
172
|
-
<script type="module" src="<%= asset(entry) %>"></script>
|
|
173
|
-
<% }); %>
|
|
174
|
-
<% if (devtools) { %>
|
|
175
|
-
<script type="module" src="<%= devBasePath %>/overlay.js"></script>
|
|
176
|
-
<% } %>
|
|
160
|
+
<body :class="bodyClass">
|
|
161
|
+
{{{ body }}}
|
|
162
|
+
<BodyScripts :entries="entries" :devtools="devtools" :devBasePath="devBasePath" />
|
|
177
163
|
</body>
|
|
178
164
|
</html>
|
|
179
165
|
```
|
|
180
166
|
|
|
167
|
+
The `.jsk` expression language has no function calls, so asset loops live in the
|
|
168
|
+
built-in `<Stylesheets />`, `<BodyScripts />` and `<JsonLd />` tags instead of
|
|
169
|
+
inline `hasAsset` / `asset` / `forEach` in the layout.
|
|
170
|
+
|
|
181
171
|
Points to watch:
|
|
182
172
|
|
|
183
173
|
- **`extraHead` comes first.** Delaying resource hints (`preconnect`, LCP
|
|
184
174
|
`preload`) writes straight into LCP.
|
|
185
|
-
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
the tag is
|
|
189
|
-
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
175
|
+
- **`<Stylesheets />` emits global `app.css` (render-blocking)** plus controller
|
|
176
|
+
`styles: [...]`, with the reasoning in
|
|
177
|
+
[02-architecture.md](./02-architecture.md). If the build has not run,
|
|
178
|
+
`hasAsset` is false inside the tag and nothing is emitted.
|
|
179
|
+
- **`<BodyScripts />` emits `main.js`, page `entries`, and the
|
|
180
|
+
development-only overlay.** The overlay script exists only when
|
|
181
|
+
`NODE_ENV=development`; it is absent from production output.
|
|
182
|
+
- **`<JsonLd />` turns `structuredData` into safe
|
|
183
|
+
`application/ld+json` scripts.**
|
|
193
184
|
|
|
194
185
|
### Layout locals
|
|
195
186
|
|
|
@@ -219,30 +210,27 @@ of bug where every page thinks it is the home page and renders the logo as an
|
|
|
219
210
|
## Page templates
|
|
220
211
|
|
|
221
212
|
The `view` field gives the path under `views/` without an extension:
|
|
222
|
-
`"pages/home"` → `views/pages/home.ejs
|
|
223
|
-
the contents of the `data` field plus `metadata` —
|
|
224
|
-
The page template still has access to all helpers
|
|
213
|
+
`"pages/home"` → `views/pages/home.jsk` (else legacy `home.ejs`). The locals
|
|
214
|
+
passed to the template are the contents of the `data` field plus `metadata` —
|
|
215
|
+
**not** the layout locals. The page template still has access to all helpers
|
|
216
|
+
and components.
|
|
225
217
|
|
|
226
|
-
```
|
|
227
|
-
|
|
218
|
+
```html
|
|
219
|
+
{# views/pages/home.jsk #}
|
|
228
220
|
<section class="wrapper">
|
|
229
|
-
<h1 class="text-3xl font-bold"
|
|
221
|
+
<h1 class="text-3xl font-bold">{{ heading }}</h1>
|
|
230
222
|
|
|
231
|
-
|
|
232
|
-
|
|
223
|
+
{# `list` is defined in views/components/list.js; no import needed. #}
|
|
224
|
+
<List :items="items" />
|
|
233
225
|
|
|
234
226
|
<div class="mt-8" data-island="counter" data-island-props='{"start":5}'></div>
|
|
235
227
|
</section>
|
|
236
228
|
```
|
|
237
229
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
be safe (component calls, `headMeta`, `body`).
|
|
243
|
-
|
|
244
|
-
Because `async: true` is on, `await` can also be used inside a template, but
|
|
245
|
-
keeping data fetching in the controller makes diagnosis easier.
|
|
230
|
+
In `.jsk`, `{{ }}` escapes and `{{{ }}}` emits raw HTML (trusted strings only).
|
|
231
|
+
Legacy EJS keeps `<%= %>` / `<%- %>` with the same meaning; because `async: true`
|
|
232
|
+
is on there, `await` can also be used inside an `.ejs` template, but keeping
|
|
233
|
+
data fetching in the controller makes diagnosis easier.
|
|
246
234
|
|
|
247
235
|
## Components: `views/components/**`
|
|
248
236
|
|
package/docs/en/05-islands.md
CHANGED
|
@@ -123,25 +123,30 @@ will still mount.
|
|
|
123
123
|
```
|
|
124
124
|
client/
|
|
125
125
|
├── entries/
|
|
126
|
-
│ ├── main.js
|
|
126
|
+
│ ├── main.js shared bootstrap on every page (or main.ts)
|
|
127
127
|
│ └── chart.js only on the pages that ask for it
|
|
128
128
|
└── islands/
|
|
129
|
-
├── counter.js
|
|
129
|
+
├── counter.ts .js or .ts
|
|
130
130
|
└── chart.js
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
-
**Every file** under `client/entries/*.js` **is an esbuild entry**.
|
|
134
|
-
is loaded by the layout on every page (if it is in the
|
|
135
|
-
are loaded only on the pages that ask for them
|
|
133
|
+
**Every file** under `client/entries/*.{js,ts,mts}` **is an esbuild entry**.
|
|
134
|
+
`main.js` (or `main.ts`) is loaded by the layout on every page (if it is in the
|
|
135
|
+
manifest). Extra entries are loaded only on the pages that ask for them. Two
|
|
136
|
+
extensions for the same stem (`main.js` + `main.ts`) fail the build.
|
|
136
137
|
|
|
137
138
|
```js
|
|
138
|
-
// controller
|
|
139
|
+
// controller — the manifest key is always *.js
|
|
139
140
|
return { view: "pages/markets", entries: ["chart.js"] };
|
|
140
141
|
```
|
|
141
142
|
|
|
142
143
|
The layout resolves every name in the `entries` array with `asset(entry)` and
|
|
143
|
-
emits a `<script type="module">`. The name is the manifest key
|
|
144
|
-
|
|
144
|
+
emits a `<script type="module">`. The name is the manifest key (`chart.js`);
|
|
145
|
+
even when the source is `chart.ts`, the unhashed key stays `.js`.
|
|
146
|
+
|
|
147
|
+
Shared `@/lib` modules imported on the server must stay **`.js`** — the Node
|
|
148
|
+
runtime does not resolve `.ts`; TypeScript is compiled only on the esbuild
|
|
149
|
+
client path.
|
|
145
150
|
|
|
146
151
|
Code splitting (`splitting: true`) is on: modules shared by two entries end up
|
|
147
152
|
in a common chunk and are not downloaded twice.
|