@rsc-kit/core 0.13.1 → 0.14.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/dist/action.d.ts +26 -4
- package/dist/action.js +12 -2
- package/dist/action.js.map +1 -1
- package/dist/js/nuqs.d.ts +4 -0
- package/dist/js/nuqs.js +64 -0
- package/dist/js/nuqs.js.map +1 -0
- package/dist/js/useSearchParams.js +11 -4
- package/dist/js/useSearchParams.js.map +1 -1
- package/dist/metadata.d.ts +58 -0
- package/dist/metadata.js.map +1 -1
- package/dist/testing.d.ts +29 -0
- package/dist/testing.js +102 -0
- package/dist/testing.js.map +1 -0
- package/dist/vite.js +141 -6
- package/dist/vite.js.map +1 -1
- package/package.json +16 -3
package/dist/vite.js
CHANGED
|
@@ -2245,8 +2245,27 @@ async function renderTree(
|
|
|
2245
2245
|
// Icons and share images the build found in app/. Rendered here so React
|
|
2246
2246
|
// hoists them into <head>, the same way the manifest link is — an app never
|
|
2247
2247
|
// edits its layout to get a favicon.
|
|
2248
|
-
|
|
2249
|
-
|
|
2248
|
+
// Where the site lives, for making a relative image or url absolute. Read
|
|
2249
|
+
// here, above the found images, because those are the ones most likely to
|
|
2250
|
+
// be relative: an opengraph-image.png in app/ is emitted as /_app/..., and a
|
|
2251
|
+
// share-card scraper needs the origin in front of it.
|
|
2252
|
+
const base = md?.metadataBase ? String(md.metadataBase) : null
|
|
2253
|
+
const absolute = (value: unknown): string => {
|
|
2254
|
+
const text = String(value instanceof URL ? value.href : value)
|
|
2255
|
+
|
|
2256
|
+
if (!base || /^[a-z][a-z0-9+.-]*:/i.test(text)) return text
|
|
2257
|
+
|
|
2258
|
+
return new URL(text, base).href
|
|
2259
|
+
}
|
|
2260
|
+
|
|
2261
|
+
for (const [i, found] of APP_HEAD.entries()) {
|
|
2262
|
+
const props = { ...found.props }
|
|
2263
|
+
|
|
2264
|
+
if (props.content && /^(og:image|twitter:image)$/.test(props.property ?? props.name ?? '')) {
|
|
2265
|
+
props.content = absolute(props.content)
|
|
2266
|
+
}
|
|
2267
|
+
|
|
2268
|
+
head.push(createElement(found.tag, { key: '__a' + i, ...props }))
|
|
2250
2269
|
}
|
|
2251
2270
|
|
|
2252
2271
|
if (WEB_MANIFEST) {
|
|
@@ -2271,16 +2290,123 @@ async function renderTree(
|
|
|
2271
2290
|
if (bootstrap) head.push(createElement(DocumentTitle, { key: '__ts', title: String(md.title) }))
|
|
2272
2291
|
}
|
|
2273
2292
|
if (md.description != null) head.push(createElement('meta', { key: '__d', name: 'description', content: String(md.description) }))
|
|
2293
|
+
|
|
2294
|
+
// og: and its relatives are PROPERTY, not name. Facebook's scraper - and
|
|
2295
|
+
// Slack's, and LinkedIn's - reads only property=, so every og tag this
|
|
2296
|
+
// used to emit with name= was invisible to the thing it existed for.
|
|
2297
|
+
// Twitter reads name=, which is why the two are not one rule.
|
|
2298
|
+
const isProperty = (k: string) => /^(og|article|profile|book|music|video|fb):/.test(k)
|
|
2299
|
+
// The keys whose CONTENT is a url. Exact, plus the :url and :secure_url
|
|
2300
|
+
// spellings - not og:image:width, which a looser match turned into
|
|
2301
|
+
// https://site/1200 and no scraper would ever read.
|
|
2302
|
+
const isUrlKey = (k: string) => /^(og:image|og:url|twitter:image)(:(secure_)?url)?$/.test(k)
|
|
2303
|
+
const tag = (k: string, v: unknown) =>
|
|
2304
|
+
createElement('meta', {
|
|
2305
|
+
key: '__m_' + k + '_' + String(v).slice(0, 40),
|
|
2306
|
+
[isProperty(k) ? 'property' : 'name']: k,
|
|
2307
|
+
content: isUrlKey(k) ? absolute(v) : String(v),
|
|
2308
|
+
})
|
|
2309
|
+
|
|
2310
|
+
// One image, or several. Each becomes its own og:image plus the size and
|
|
2311
|
+
// alt tags beside it, which is how a scraper is told which is which.
|
|
2312
|
+
const images = (prefix: string, value: unknown): void => {
|
|
2313
|
+
const list = Array.isArray(value) ? value : [value]
|
|
2314
|
+
|
|
2315
|
+
for (const item of list) {
|
|
2316
|
+
if (item == null) continue
|
|
2317
|
+
|
|
2318
|
+
if (typeof item === 'object' && !(item instanceof URL)) {
|
|
2319
|
+
const image = item as { url: unknown; width?: number; height?: number; alt?: string; type?: string }
|
|
2320
|
+
|
|
2321
|
+
head.push(tag(prefix, image.url))
|
|
2322
|
+
if (image.width) head.push(tag(prefix + ':width', image.width))
|
|
2323
|
+
if (image.height) head.push(tag(prefix + ':height', image.height))
|
|
2324
|
+
if (image.alt) head.push(tag(prefix + ':alt', image.alt))
|
|
2325
|
+
if (image.type) head.push(tag(prefix + ':type', image.type))
|
|
2326
|
+
} else {
|
|
2327
|
+
head.push(tag(prefix, item))
|
|
2328
|
+
}
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
if (md.openGraph) {
|
|
2333
|
+
const og = md.openGraph as Record<string, unknown>
|
|
2334
|
+
|
|
2335
|
+
if (og.title != null) head.push(tag('og:title', og.title))
|
|
2336
|
+
if (og.description != null) head.push(tag('og:description', og.description))
|
|
2337
|
+
if (og.url != null) head.push(tag('og:url', og.url))
|
|
2338
|
+
if (og.siteName != null) head.push(tag('og:site_name', og.siteName))
|
|
2339
|
+
if (og.type != null) head.push(tag('og:type', og.type))
|
|
2340
|
+
if (og.locale != null) head.push(tag('og:locale', og.locale))
|
|
2341
|
+
if (og.images != null) images('og:image', og.images)
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
if (md.twitter) {
|
|
2345
|
+
const tw = md.twitter as Record<string, unknown>
|
|
2346
|
+
|
|
2347
|
+
if (tw.card != null) head.push(tag('twitter:card', tw.card))
|
|
2348
|
+
if (tw.title != null) head.push(tag('twitter:title', tw.title))
|
|
2349
|
+
if (tw.description != null) head.push(tag('twitter:description', tw.description))
|
|
2350
|
+
if (tw.site != null) head.push(tag('twitter:site', tw.site))
|
|
2351
|
+
if (tw.creator != null) head.push(tag('twitter:creator', tw.creator))
|
|
2352
|
+
if (tw.images != null) images('twitter:image', tw.images)
|
|
2353
|
+
}
|
|
2354
|
+
|
|
2355
|
+
// icons is links, not meta. A string is one icon; an object names which
|
|
2356
|
+
// rel each is for. The ones found in app/ are already in APP_HEAD above,
|
|
2357
|
+
// so this is for an app that wants to say it explicitly.
|
|
2358
|
+
const links = (rel: string, value: unknown): void => {
|
|
2359
|
+
const list = Array.isArray(value) ? value : [value]
|
|
2360
|
+
|
|
2361
|
+
for (const item of list) {
|
|
2362
|
+
if (item == null) continue
|
|
2363
|
+
|
|
2364
|
+
const icon = typeof item === 'object' && !(item instanceof URL)
|
|
2365
|
+
? (item as Record<string, unknown>)
|
|
2366
|
+
: { url: item }
|
|
2367
|
+
|
|
2368
|
+
head.push(
|
|
2369
|
+
createElement('link', {
|
|
2370
|
+
key: '__i_' + rel + '_' + String(icon.url).slice(0, 40),
|
|
2371
|
+
rel: (icon.rel as string) ?? rel,
|
|
2372
|
+
href: absolute(icon.url),
|
|
2373
|
+
...(icon.type ? { type: icon.type } : {}),
|
|
2374
|
+
...(icon.sizes ? { sizes: icon.sizes } : {}),
|
|
2375
|
+
...(icon.media ? { media: icon.media } : {}),
|
|
2376
|
+
}),
|
|
2377
|
+
)
|
|
2378
|
+
}
|
|
2379
|
+
}
|
|
2380
|
+
|
|
2381
|
+
if (md.icons != null) {
|
|
2382
|
+
const icons = md.icons as Record<string, unknown> | string | unknown[]
|
|
2383
|
+
|
|
2384
|
+
if (typeof icons === 'string' || Array.isArray(icons) || icons instanceof URL) {
|
|
2385
|
+
links('icon', icons)
|
|
2386
|
+
} else {
|
|
2387
|
+
if (icons.icon != null) links('icon', icons.icon)
|
|
2388
|
+
if (icons.apple != null) links('apple-touch-icon', icons.apple)
|
|
2389
|
+
if (icons.shortcut != null) links('shortcut icon', icons.shortcut)
|
|
2390
|
+
if (icons.other != null) links('icon', icons.other)
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2274
2394
|
// other is flattened in beside the named keys, because it is a place to put
|
|
2275
2395
|
// meta tags rather than a meta tag by that name. A key at the top level
|
|
2276
|
-
// still renders
|
|
2396
|
+
// still renders - the type no longer invites one, but an app written
|
|
2277
2397
|
// against the old shape must not silently lose its tags.
|
|
2278
|
-
const
|
|
2398
|
+
const structured = new Set(['title', 'description', 'metadataBase', 'openGraph', 'twitter', 'icons', 'other'])
|
|
2399
|
+
const named = Object.entries(md).filter(([k]) => !structured.has(k))
|
|
2279
2400
|
const extra = Object.entries((md.other ?? {}) as Record<string, unknown>)
|
|
2280
2401
|
|
|
2281
2402
|
for (const [k, v] of [...named, ...extra]) {
|
|
2282
|
-
if (
|
|
2283
|
-
|
|
2403
|
+
if (v == null) continue
|
|
2404
|
+
|
|
2405
|
+
if (Array.isArray(v)) {
|
|
2406
|
+
for (const item of v) head.push(tag(k, item))
|
|
2407
|
+
} else {
|
|
2408
|
+
head.push(tag(k, v))
|
|
2409
|
+
}
|
|
2284
2410
|
}
|
|
2285
2411
|
}
|
|
2286
2412
|
|
|
@@ -3931,6 +4057,15 @@ export function rscKit(options = {}) {
|
|
|
3931
4057
|
},
|
|
3932
4058
|
configResolved(config) {
|
|
3933
4059
|
isWatch = config.build?.watch != null;
|
|
4060
|
+
const nitroMain = config.plugins.find((p) => p.name === 'nitro:main');
|
|
4061
|
+
if (nitroMain?.hotUpdate) {
|
|
4062
|
+
const original = nitroMain.hotUpdate;
|
|
4063
|
+
nitroMain.hotUpdate = function (ctx) {
|
|
4064
|
+
if (this.environment?.name === 'rsc')
|
|
4065
|
+
return;
|
|
4066
|
+
return original.call(this, ctx);
|
|
4067
|
+
};
|
|
4068
|
+
}
|
|
3934
4069
|
// rsc() splits the module graph into client and server; a JSX transform
|
|
3935
4070
|
// placed ahead of it sees the wrong graph and fails in ways that are hard
|
|
3936
4071
|
// to trace back here. Cheaper to refuse than to let it through.
|