@rsc-kit/core 0.13.0 → 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 +151 -7
- 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
|
|
|
@@ -3722,7 +3848,16 @@ export function rscKit(options = {}) {
|
|
|
3722
3848
|
// routing bug rather than as this line. In dev the pages are the root;
|
|
3723
3849
|
// the assets come from the same origin either way.
|
|
3724
3850
|
base: '/',
|
|
3725
|
-
|
|
3851
|
+
// Where the generated entries live, so Vite resolves them as its own
|
|
3852
|
+
// source. A build concern only.
|
|
3853
|
+
//
|
|
3854
|
+
// Not during preview. `vite preview` serves what was built, and Nitro's
|
|
3855
|
+
// preview reads its build info from `<vite root>/node_modules/.nitro` —
|
|
3856
|
+
// so pointing the root at this directory sent it looking somewhere no
|
|
3857
|
+
// build ever writes, and every preview failed with "Cannot load nitro
|
|
3858
|
+
// build info. Make sure to build first." after a build that had just
|
|
3859
|
+
// succeeded.
|
|
3860
|
+
...(env.isPreview ? {} : { root: outDir }),
|
|
3726
3861
|
// Force single instances of React/RSC runtime — critical when the
|
|
3727
3862
|
// package is symlinked (local dev / monorepo), else "use client"
|
|
3728
3863
|
// components SSR against a second React copy and hooks throw.
|
|
@@ -3922,6 +4057,15 @@ export function rscKit(options = {}) {
|
|
|
3922
4057
|
},
|
|
3923
4058
|
configResolved(config) {
|
|
3924
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
|
+
}
|
|
3925
4069
|
// rsc() splits the module graph into client and server; a JSX transform
|
|
3926
4070
|
// placed ahead of it sees the wrong graph and fails in ways that are hard
|
|
3927
4071
|
// to trace back here. Cheaper to refuse than to let it through.
|