jskelet 0.1.1
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 +127 -0
- package/CHANGELOG.md +40 -0
- package/LICENSE +21 -0
- package/README.md +342 -0
- package/bin/jskelet.mjs +104 -0
- package/docs/01-baslangic.md +285 -0
- package/docs/02-mimari.md +287 -0
- package/docs/03-routing.md +437 -0
- package/docs/04-render-ve-sablonlar.md +490 -0
- package/docs/05-islands.md +429 -0
- package/docs/06-cache.md +409 -0
- package/docs/07-yapilandirma.md +673 -0
- package/docs/08-build.md +366 -0
- package/docs/09-dev-araclari.md +302 -0
- package/docs/10-dagitim.md +329 -0
- package/docs/11-tasima.md +352 -0
- package/docs/README.md +82 -0
- package/package.json +97 -0
- package/src/build/build.mjs +138 -0
- package/src/build/ensure-build.mjs +15 -0
- package/src/build/paths.mjs +118 -0
- package/src/build/resolve-peer.mjs +36 -0
- package/src/build/tasks/client.mjs +268 -0
- package/src/build/tasks/css.mjs +124 -0
- package/src/build/tasks/fonts.mjs +146 -0
- package/src/build/tasks/icons.mjs +224 -0
- package/src/build/tasks/images.mjs +244 -0
- package/src/build/tasks/precompress.mjs +78 -0
- package/src/client/devtools/overlay.js +1763 -0
- package/src/client/devtools/report.html +185 -0
- package/src/client/devtools/report.js +712 -0
- package/src/client/dom.js +95 -0
- package/src/client/index.js +26 -0
- package/src/client/registry.js +223 -0
- package/src/client/safe-image.js +91 -0
- package/src/client/store.js +36 -0
- package/src/config/defaults.js +102 -0
- package/src/config/index.js +433 -0
- package/src/config/pattern.js +107 -0
- package/src/dev-server.mjs +383 -0
- package/src/http/control-flow.js +56 -0
- package/src/http/request-cache.js +46 -0
- package/src/index.js +35 -0
- package/src/init.mjs +220 -0
- package/src/log.mjs +332 -0
- package/src/logo.png +0 -0
- package/src/runtime/alias-hooks.mjs +119 -0
- package/src/runtime/register.mjs +4 -0
- package/src/server/assets.js +119 -0
- package/src/server/create-app.js +167 -0
- package/src/server/dev/devtools.js +383 -0
- package/src/server/dev/report.js +351 -0
- package/src/server/head-hints.js +132 -0
- package/src/server/html-cache.js +166 -0
- package/src/server/metadata.js +102 -0
- package/src/server/middleware/compression.js +205 -0
- package/src/server/middleware/dev-gate.js +62 -0
- package/src/server/middleware/headers.js +37 -0
- package/src/server/middleware/redirects.js +32 -0
- package/src/server/middleware/static-precompressed.js +100 -0
- package/src/server/middleware/upstream-proxy.js +141 -0
- package/src/server/prewarm.js +283 -0
- package/src/server/render.js +356 -0
- package/src/server/router.js +121 -0
- package/src/server/status-page.js +164 -0
- package/src/server/upstream-tracking.js +51 -0
- package/src/start.mjs +7 -0
- package/src/templates/layout.ejs +44 -0
- package/src/version.mjs +17 -0
- package/src/views/components/loader.js +85 -0
- package/src/views/helpers/html.js +102 -0
- package/src/views/helpers/tags.js +193 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `next/link`, `next/image` ve `@phosphor-icons/react` karşılıkları.
|
|
3
|
+
* Hepsi HTML string döndürür; EJS içinden `<%- %>` ile basılır.
|
|
4
|
+
*/
|
|
5
|
+
import { attrs, esc, cn } from "./html.js";
|
|
6
|
+
import { asset, getSpriteIds, optimizedImage } from "../../server/assets.js";
|
|
7
|
+
|
|
8
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
9
|
+
|
|
10
|
+
/** Aynı eksik ikon için tek uyarı. */
|
|
11
|
+
const warnedIcons = new Set();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* `SeoLink` karşılığı: title otomatik doldurulur.
|
|
15
|
+
* @param {{ href: string, text?: string, html?: string, class?: string,
|
|
16
|
+
* title?: string, ariaLabel?: string, target?: string, rel?: string,
|
|
17
|
+
* attrs?: Record<string, unknown> }} props
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function link(props) {
|
|
21
|
+
const {
|
|
22
|
+
href,
|
|
23
|
+
text,
|
|
24
|
+
html,
|
|
25
|
+
class: className,
|
|
26
|
+
title,
|
|
27
|
+
ariaLabel,
|
|
28
|
+
target,
|
|
29
|
+
rel,
|
|
30
|
+
attrs: extra = {},
|
|
31
|
+
} = props;
|
|
32
|
+
|
|
33
|
+
const resolvedTitle = title ?? ariaLabel ?? text ?? href;
|
|
34
|
+
const isExternal = /^https?:\/\//.test(String(href ?? ""));
|
|
35
|
+
|
|
36
|
+
const attributes = attrs({
|
|
37
|
+
href,
|
|
38
|
+
class: className,
|
|
39
|
+
title: resolvedTitle,
|
|
40
|
+
"aria-label": ariaLabel,
|
|
41
|
+
target: target ?? (isExternal ? "_blank" : undefined),
|
|
42
|
+
rel: rel ?? (isExternal ? "noopener noreferrer" : undefined),
|
|
43
|
+
...extra,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return `<a${attributes}>${html ?? esc(text ?? "")}</a>`;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `next/image` karşılığı. `public/` altındaki yerel görseller için build'de
|
|
51
|
+
* üretilen webp varyantları (`build/tasks/images.mjs`) otomatik olarak
|
|
52
|
+
* `srcset` + intrinsic `width`/`height` olarak eklenir; manifest'te olmayan
|
|
53
|
+
* ya da uzak görseller olduğu gibi basılır.
|
|
54
|
+
*
|
|
55
|
+
* `priority` LCP görselleri için `fetchpriority=high` + eager yükleme yapar.
|
|
56
|
+
* @param {{ src: string, alt: string, width?: number, height?: number,
|
|
57
|
+
* class?: string, sizes?: string, srcset?: string, priority?: boolean,
|
|
58
|
+
* fill?: boolean, loading?: 'lazy' | 'eager', unoptimized?: boolean,
|
|
59
|
+
* attrs?: Record<string, unknown> }} props
|
|
60
|
+
* @returns {string}
|
|
61
|
+
*/
|
|
62
|
+
export function image(props) {
|
|
63
|
+
const {
|
|
64
|
+
src,
|
|
65
|
+
alt,
|
|
66
|
+
width,
|
|
67
|
+
height,
|
|
68
|
+
class: className,
|
|
69
|
+
sizes,
|
|
70
|
+
srcset,
|
|
71
|
+
priority = false,
|
|
72
|
+
fill = false,
|
|
73
|
+
loading,
|
|
74
|
+
unoptimized = false,
|
|
75
|
+
attrs: extra = {},
|
|
76
|
+
} = props;
|
|
77
|
+
|
|
78
|
+
const optimized = unoptimized || srcset ? undefined : optimizedImage(src);
|
|
79
|
+
const largest = optimized?.variants.at(-1);
|
|
80
|
+
// Tek varyant üretilmişse (kaynak zaten küçükse) srcset/sizes gürültüden ibaret.
|
|
81
|
+
const responsive = optimized && optimized.variants.length > 1;
|
|
82
|
+
|
|
83
|
+
const attributes = attrs({
|
|
84
|
+
src: largest?.url ?? src,
|
|
85
|
+
alt: alt ?? "",
|
|
86
|
+
width: fill ? undefined : (width ?? optimized?.width),
|
|
87
|
+
height: fill ? undefined : (height ?? optimized?.height),
|
|
88
|
+
class: fill
|
|
89
|
+
? cn("absolute inset-0 h-full w-full object-cover", className)
|
|
90
|
+
: className,
|
|
91
|
+
sizes: responsive ? (sizes ?? defaultSizes(optimized)) : sizes,
|
|
92
|
+
srcset: responsive ? toSrcSet(optimized) : srcset,
|
|
93
|
+
loading: loading ?? (priority ? "eager" : "lazy"),
|
|
94
|
+
decoding: priority ? "sync" : "async",
|
|
95
|
+
fetchpriority: priority ? "high" : undefined,
|
|
96
|
+
...extra,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
return `<img${attributes}>`;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {import("../../server/assets.js").OptimizedImage} optimized
|
|
104
|
+
* @returns {string}
|
|
105
|
+
*/
|
|
106
|
+
function toSrcSet(optimized) {
|
|
107
|
+
return optimized.variants
|
|
108
|
+
.map((variant) => `${variant.url} ${variant.width}w`)
|
|
109
|
+
.join(", ");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Çağıran `sizes` vermediyse makul bir varsayılan: görsel kendi intrinsic
|
|
114
|
+
* genişliğinden büyütülmez, dar ekranlarda viewport'u kaplar.
|
|
115
|
+
* @param {import("../../server/assets.js").OptimizedImage} optimized
|
|
116
|
+
* @returns {string}
|
|
117
|
+
*/
|
|
118
|
+
function defaultSizes(optimized) {
|
|
119
|
+
const max = optimized.variants.at(-1)?.width ?? optimized.width;
|
|
120
|
+
return `(max-width: ${max}px) 100vw, ${max}px`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* LCP görselleri için `<head>` preload etiketi.
|
|
125
|
+
* @param {{ href: string, imagesrcset?: string, imagesizes?: string }} props
|
|
126
|
+
* @returns {string}
|
|
127
|
+
*/
|
|
128
|
+
export function preloadImage({ href, imagesrcset, imagesizes }) {
|
|
129
|
+
return `<link${attrs({
|
|
130
|
+
rel: "preload",
|
|
131
|
+
as: "image",
|
|
132
|
+
href,
|
|
133
|
+
imagesrcset,
|
|
134
|
+
imagesizes,
|
|
135
|
+
fetchpriority: "high",
|
|
136
|
+
})}>`;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Phosphor ikonları — build zamanı üretilen SVG sprite'tan `<use>`.
|
|
141
|
+
* `weight` sprite id'sine dahildir (regular/bold/fill).
|
|
142
|
+
* @param {{ name: string, size?: number | string, weight?: string,
|
|
143
|
+
* class?: string, attrs?: Record<string, unknown> }} props
|
|
144
|
+
* @returns {string}
|
|
145
|
+
*/
|
|
146
|
+
export function icon(props) {
|
|
147
|
+
const {
|
|
148
|
+
name,
|
|
149
|
+
size = 24,
|
|
150
|
+
weight = "regular",
|
|
151
|
+
class: className,
|
|
152
|
+
attrs: extra = {},
|
|
153
|
+
} = props;
|
|
154
|
+
|
|
155
|
+
const spritePath = asset("sprite.svg");
|
|
156
|
+
const id = `${toKebab(name)}-${weight}`;
|
|
157
|
+
|
|
158
|
+
if (isDev && !warnedIcons.has(id)) {
|
|
159
|
+
const ids = getSpriteIds();
|
|
160
|
+
if (ids.size && !ids.has(id)) {
|
|
161
|
+
warnedIcons.add(id);
|
|
162
|
+
console.warn(
|
|
163
|
+
`[icon] sprite'ta yok: ${id} — adı sabit yazın ya da build/tasks/icons.mjs taramasına ekleyin.`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const attributes = attrs({
|
|
169
|
+
width: size,
|
|
170
|
+
height: size,
|
|
171
|
+
class: className,
|
|
172
|
+
"aria-hidden": "true",
|
|
173
|
+
focusable: "false",
|
|
174
|
+
fill: "currentColor",
|
|
175
|
+
viewBox: "0 0 256 256",
|
|
176
|
+
...extra,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
return `<svg${attributes}><use href="${esc(spritePath)}#${esc(id)}"></use></svg>`;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* `ArrowRightIcon` / `ArrowRight` → `arrow-right`
|
|
184
|
+
* @param {string} name
|
|
185
|
+
* @returns {string}
|
|
186
|
+
*/
|
|
187
|
+
export function toKebab(name) {
|
|
188
|
+
return String(name)
|
|
189
|
+
.replace(/Icon$/, "")
|
|
190
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
191
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, "$1-$2")
|
|
192
|
+
.toLowerCase();
|
|
193
|
+
}
|