@rsc-kit/core 0.30.14 → 0.30.16
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/README.md +3 -1
- package/dist/appAssets.d.ts +25 -4
- package/dist/appAssets.js +86 -30
- package/dist/appAssets.js.map +1 -1
- package/dist/commandFiles.d.ts +60 -0
- package/dist/commandFiles.js +136 -0
- package/dist/commandFiles.js.map +1 -0
- package/dist/commands.d.ts +74 -0
- package/dist/commands.js +172 -0
- package/dist/commands.js.map +1 -0
- package/dist/files.d.ts +3 -1
- package/dist/files.js +47 -1
- package/dist/files.js.map +1 -1
- package/dist/metadata.d.ts +4 -0
- package/dist/metadata.js.map +1 -1
- package/dist/shareImages.d.ts +30 -0
- package/dist/shareImages.js +50 -0
- package/dist/shareImages.js.map +1 -0
- package/dist/vite.js +157 -22
- package/dist/vite.js.map +1 -1
- package/package.json +1 -1
package/dist/vite.js
CHANGED
|
@@ -24,7 +24,7 @@ import { loadEnv, parseAst } from "vite";
|
|
|
24
24
|
import { stampDisplayNames } from "./stableNames.js";
|
|
25
25
|
import { REPORT_FILE, buildReport } from "./buildReport.js";
|
|
26
26
|
import { MANIFEST_PATH, manifestWarning, webManifest } from "./webManifest.js";
|
|
27
|
-
import { ASSET_BASE, allAppAssets, appAssets, headTags, typeOf, } from "./appAssets.js";
|
|
27
|
+
import { ASSET_BASE, allAppAssets, assetFile, appAssets, headTags, shareImageUrls, typeOf, } from "./appAssets.js";
|
|
28
28
|
import { reactCacheImports } from "./reactCache.js";
|
|
29
29
|
import { clientEntries, clientScanPlugin, engineClientEntries, } from "./clientEntries.js";
|
|
30
30
|
import { serverImportsOfClientPackages } from "./clientImports.js";
|
|
@@ -33,6 +33,7 @@ import { ownHosts } from "./hostRouting.js";
|
|
|
33
33
|
import { unrollBarrelImports } from "./barrelImports.js";
|
|
34
34
|
import { hasUseSsr, serverRendererMessage, SERVER_RENDERER, ssrProxyModule, UseSsrError, withoutSsrDirective } from "./useSsr.js";
|
|
35
35
|
import { httpHostCalls } from "./hostCalls.js";
|
|
36
|
+
import { COMMANDS_MODULE_ID, commandFiles, commandsEntry, commandsEntrySource, commandsModule } from "./commandFiles.js";
|
|
36
37
|
import { clientPackages, importsServerRenderer, packageDir as installedPackageDir, packageEntryInGraph, polyfillsToTrace, traceableByName } from "./clientPackages.js";
|
|
37
38
|
// Resolved once per rscKit() call. One build runs in one process, so these are
|
|
38
39
|
// module state rather than threaded through every helper.
|
|
@@ -47,6 +48,46 @@ let clientLibraryImports = [];
|
|
|
47
48
|
* decisions buildApp makes about where stored pages can live.
|
|
48
49
|
*/
|
|
49
50
|
let nitroPreset = null;
|
|
51
|
+
/** `src/commands`, read once per build; null until asked. See buildCommands(). */
|
|
52
|
+
let commandsFound = null;
|
|
53
|
+
/**
|
|
54
|
+
* The presets whose output is a process that Node or Bun starts: where a
|
|
55
|
+
* command runs. Every other preset is a platform that starts the app itself -
|
|
56
|
+
* a function, a Worker - and a release step there is not the app's to run.
|
|
57
|
+
*/
|
|
58
|
+
const COMMAND_PRESETS = /^(?:bun|node|node[-_]server|node[-_]cluster)$/;
|
|
59
|
+
/**
|
|
60
|
+
* The app's commands, for a build that has a process to run them in.
|
|
61
|
+
*
|
|
62
|
+
* Decided once, the first time the bundle asks, and every later step reads the
|
|
63
|
+
* same answer: the table in the bundle, `commands.mjs`, the compile entry and
|
|
64
|
+
* `.output/rsc-kit.json` cannot disagree about what is there.
|
|
65
|
+
*
|
|
66
|
+
* Not the dev server, which has no output to run one from - a command there is
|
|
67
|
+
* `bun src/commands/<name>.ts`. Not a Worker: its bundle targets workerd, where
|
|
68
|
+
* the packages a release step wants (a database driver, `node:child_process`)
|
|
69
|
+
* either resolve to a different build or not at all, so a command that ran there
|
|
70
|
+
* would run something other than what was written. And not a preset this has not
|
|
71
|
+
* been run on: it says so, rather than writing an entry for a layout it has not
|
|
72
|
+
* seen.
|
|
73
|
+
*/
|
|
74
|
+
function buildCommands() {
|
|
75
|
+
if (resolvedConfig?.command !== "build")
|
|
76
|
+
return [];
|
|
77
|
+
if (commandsFound)
|
|
78
|
+
return commandsFound;
|
|
79
|
+
const { commands, ignored } = commandFiles(sourceDir);
|
|
80
|
+
for (const { path, reason } of ignored)
|
|
81
|
+
log(`${relative(projectRoot, path)} is not a command: ${reason}.`);
|
|
82
|
+
if (commands.length && !(nitroPreset && COMMAND_PRESETS.test(nitroPreset))) {
|
|
83
|
+
const names = commands.map((c) => c.name).join(", ");
|
|
84
|
+
log(nitroPreset?.startsWith("cloudflare")
|
|
85
|
+
? `src/commands is not built for a Worker (${names}): the bundle runs on workerd, which is not where a release step runs. Run the file itself, or wrangler.`
|
|
86
|
+
: `src/commands is built for the bun and node presets, and this build is ${nitroPreset ? `for ${nitroPreset}` : "not using a Nitro preset"} (${names}). Run the file itself from CI.`);
|
|
87
|
+
return (commandsFound = []);
|
|
88
|
+
}
|
|
89
|
+
return (commandsFound = commands);
|
|
90
|
+
}
|
|
50
91
|
/**
|
|
51
92
|
* Modules a runtime provides and no bundle should try to carry.
|
|
52
93
|
*
|
|
@@ -195,8 +236,7 @@ let foundAssets = {
|
|
|
195
236
|
appleIcon: null,
|
|
196
237
|
appleSplash: [],
|
|
197
238
|
screenshots: [],
|
|
198
|
-
|
|
199
|
-
twitter: null,
|
|
239
|
+
shareImages: {},
|
|
200
240
|
};
|
|
201
241
|
/** Host functions to generate stubs for — see RscKitOptions.hostActions. */
|
|
202
242
|
let hostActions;
|
|
@@ -1393,7 +1433,7 @@ function copyAppAssets(clientDir) {
|
|
|
1393
1433
|
if (all.length === 0)
|
|
1394
1434
|
return;
|
|
1395
1435
|
for (const asset of all) {
|
|
1396
|
-
const to = join(clientDir, asset.href.slice(1));
|
|
1436
|
+
const to = join(clientDir, assetFile(asset.href.slice(1)));
|
|
1397
1437
|
mkdirSync(dirname(to), { recursive: true });
|
|
1398
1438
|
copyFileSync(join(sourceDir, "app", asset.file), to);
|
|
1399
1439
|
}
|
|
@@ -2424,6 +2464,8 @@ const API_METHODS = [
|
|
|
2424
2464
|
];
|
|
2425
2465
|
/** `orders.section.tsx` — a region of a page that can be refreshed by name. */
|
|
2426
2466
|
const SECTION_FILE = /\.section\.(tsx|jsx|ts|js)$/;
|
|
2467
|
+
/** A share image file: the pages beneath its folder change what they say about themselves. */
|
|
2468
|
+
const SHARE_IMAGE_FILE = /^(?:opengraph|twitter)-image[-\w]*\.(?:png|svg|jpe?g|webp|gif|avif)$/i;
|
|
2427
2469
|
/**
|
|
2428
2470
|
* Whether a page or a section declares refreshOn. Read from the source, as
|
|
2429
2471
|
* section names are, because the manifest is written before any bundle exists.
|
|
@@ -2489,6 +2531,20 @@ function registerOpenApiRoutes() {
|
|
|
2489
2531
|
}
|
|
2490
2532
|
apiRoutes.set(name, { name, absPath: OPENAPI_ROUTE_ID, methods: ["GET"], generated: { kind: "openapi", file: "" } });
|
|
2491
2533
|
}
|
|
2534
|
+
/** The table behind `runCommand` in the server's entry: src/commands, or nothing where they are not built. */
|
|
2535
|
+
function commandsPlugin() {
|
|
2536
|
+
return {
|
|
2537
|
+
name: "rsc-kit:commands",
|
|
2538
|
+
resolveId(id) {
|
|
2539
|
+
if (id === COMMANDS_MODULE_ID)
|
|
2540
|
+
return "\0" + id;
|
|
2541
|
+
},
|
|
2542
|
+
load(id) {
|
|
2543
|
+
if (id === "\0" + COMMANDS_MODULE_ID)
|
|
2544
|
+
return commandsModule(buildCommands());
|
|
2545
|
+
},
|
|
2546
|
+
};
|
|
2547
|
+
}
|
|
2492
2548
|
/** The module behind the synthesised /openapi.json route. */
|
|
2493
2549
|
function openApiPlugin() {
|
|
2494
2550
|
return {
|
|
@@ -3069,7 +3125,7 @@ export function instrumentationImport(instrumentation) {
|
|
|
3069
3125
|
return (`import { ${hooks.map((hook) => `${hook} as __instrumentation_${hook}`).join(", ")} } from ${from}\n` +
|
|
3070
3126
|
`const __instrumentation: ${type} = { ${hooks.map((hook) => `${hook}: __instrumentation_${hook}`).join(", ")} }`);
|
|
3071
3127
|
}
|
|
3072
|
-
function generateEntryRsc(fallbackOrigin = "") {
|
|
3128
|
+
function generateEntryRsc(fallbackOrigin = "", withCommands = false) {
|
|
3073
3129
|
const instrumentation = instrumentationFile();
|
|
3074
3130
|
// Every 404 page the app has, and the layouts each renders inside. Computed
|
|
3075
3131
|
// here rather than looked up at runtime: not-found is not a route, so the
|
|
@@ -3146,6 +3202,7 @@ ${
|
|
|
3146
3202
|
import { SegmentBoundary } from ${JSON.stringify(join(packageDir, "js/SegmentBoundary"))}
|
|
3147
3203
|
import { LoadingBoundary } from ${JSON.stringify(join(packageDir, "js/LoadingBoundary"))}
|
|
3148
3204
|
import { DocumentTitle } from ${JSON.stringify(join(packageDir, "js/DocumentTitle"))}
|
|
3205
|
+
import { depthOf, fileWins, folderOf, nearestShareImage } from ${JSON.stringify(join(packageDir, "shareImages"))}
|
|
3149
3206
|
import { SlotBoundary } from ${JSON.stringify(join(packageDir, "js/SlotBoundary"))}
|
|
3150
3207
|
import { RouteErrorBoundary } from ${JSON.stringify(join(packageDir, "js/RouteErrorBoundary"))}
|
|
3151
3208
|
import __rsc_assets from 'virtual:vite-rsc/assets-manifest'
|
|
@@ -3199,6 +3256,9 @@ ${mapEntries.join("\n")}
|
|
|
3199
3256
|
/** Head tags for the icons and share images found in app/. */
|
|
3200
3257
|
const APP_HEAD: { tag: any; props: Record<string, string> }[] = ${JSON.stringify(headTags(foundAssets))}
|
|
3201
3258
|
|
|
3259
|
+
/** The share images found under app/, by the folder each is in - see shareImages.ts. */
|
|
3260
|
+
const SHARE_IMAGES: Record<string, { openGraph?: string; twitter?: string }> = ${JSON.stringify(shareImageUrls(foundAssets))}
|
|
3261
|
+
|
|
3202
3262
|
const WEB_MANIFEST: { href: string; themeColor?: string } | null = ${JSON.stringify(webManifestOptions
|
|
3203
3263
|
? {
|
|
3204
3264
|
href: MANIFEST_PATH,
|
|
@@ -3598,7 +3658,9 @@ if (!isolateRuntime) {
|
|
|
3598
3658
|
;(globalThis as { __rscKitShutdown?: () => unknown }).__rscKitShutdown = () => __instrumentation.shutdown?.()
|
|
3599
3659
|
}
|
|
3600
3660
|
|
|
3601
|
-
|
|
3661
|
+
// Started to run a command (src/commands), not to serve: register() waits for
|
|
3662
|
+
// the command that asks for it, rather than running at import.
|
|
3663
|
+
if (__instrumentation.register && !isolateRuntime && !(globalThis as Record<symbol, unknown>)[Symbol.for('rsc-kit.command')]) {
|
|
3602
3664
|
instrumented().catch((error) => {
|
|
3603
3665
|
console.error('[rsc-kit] instrumentation.ts register() failed:', error)
|
|
3604
3666
|
|
|
@@ -4199,13 +4261,35 @@ async function renderTree(
|
|
|
4199
4261
|
}
|
|
4200
4262
|
|
|
4201
4263
|
for (const [i, found] of APP_HEAD.entries()) {
|
|
4202
|
-
|
|
4264
|
+
head.push(createElement(found.tag, { key: '__a' + i, ...found.props }))
|
|
4265
|
+
}
|
|
4203
4266
|
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4267
|
+
// The share image files found in app/. The nearest to this page is its
|
|
4268
|
+
// card - unless its metadata exports images from a segment nearer still,
|
|
4269
|
+
// in which case the file is left out and the exported ones render, so a
|
|
4270
|
+
// page that names its own image replaces the site's instead of following
|
|
4271
|
+
// it. Scrapers read the first og:image they meet; a second after the
|
|
4272
|
+
// site's would be a card that never changes.
|
|
4273
|
+
const folder = folderOf(component)
|
|
4274
|
+
const sources = md ? imageSources.get(md) : undefined
|
|
4275
|
+
const shared = (kind: 'openGraph' | 'twitter') => {
|
|
4276
|
+
const file = nearestShareImage(SHARE_IMAGES, folder, kind)
|
|
4277
|
+
const source = sources?.[kind]
|
|
4278
|
+
|
|
4279
|
+
return fileWins(file, source?.exports ? source : null) ? file : null
|
|
4280
|
+
}
|
|
4281
|
+
const ogFile = shared('openGraph')
|
|
4282
|
+
const twitterFile = shared('twitter')
|
|
4283
|
+
|
|
4284
|
+
if (ogFile) head.push(createElement('meta', { key: '__og', property: 'og:image', content: absolute(ogFile.href) }))
|
|
4207
4285
|
|
|
4208
|
-
|
|
4286
|
+
if (twitterFile) {
|
|
4287
|
+
head.push(createElement('meta', { key: '__tw', name: 'twitter:image', content: absolute(twitterFile.href) }))
|
|
4288
|
+
|
|
4289
|
+
// The card a twitter image implies, unless the page named its own.
|
|
4290
|
+
if ((md?.twitter as { card?: unknown } | undefined)?.card == null) {
|
|
4291
|
+
head.push(createElement('meta', { key: '__twc', name: 'twitter:card', content: 'summary_large_image' }))
|
|
4292
|
+
}
|
|
4209
4293
|
}
|
|
4210
4294
|
|
|
4211
4295
|
if (md) {
|
|
@@ -4305,7 +4389,7 @@ async function renderTree(
|
|
|
4305
4389
|
if (og.siteName != null) head.push(tag('og:site_name', og.siteName))
|
|
4306
4390
|
if (og.type != null) head.push(tag('og:type', og.type))
|
|
4307
4391
|
if (og.locale != null) head.push(tag('og:locale', og.locale))
|
|
4308
|
-
if (og.images != null) images('og:image', og.images)
|
|
4392
|
+
if (og.images != null && !ogFile) images('og:image', og.images)
|
|
4309
4393
|
}
|
|
4310
4394
|
|
|
4311
4395
|
if (md.twitter) {
|
|
@@ -4316,7 +4400,7 @@ async function renderTree(
|
|
|
4316
4400
|
if (tw.description != null) head.push(tag('twitter:description', tw.description))
|
|
4317
4401
|
if (tw.site != null) head.push(tag('twitter:site', tw.site))
|
|
4318
4402
|
if (tw.creator != null) head.push(tag('twitter:creator', tw.creator))
|
|
4319
|
-
if (tw.images != null) images('twitter:image', tw.images)
|
|
4403
|
+
if (tw.images != null && !twitterFile) images('twitter:image', tw.images)
|
|
4320
4404
|
}
|
|
4321
4405
|
|
|
4322
4406
|
// icons is links, not meta. A string is one icon; an object names which
|
|
@@ -5209,6 +5293,17 @@ const METADATA_PROBE_GRACE_MS = 20
|
|
|
5209
5293
|
|
|
5210
5294
|
const METADATA_POSTPONED = Symbol('metadata postponed')
|
|
5211
5295
|
|
|
5296
|
+
/**
|
|
5297
|
+
* For each of openGraph and twitter, how deep the segment that supplied the
|
|
5298
|
+
* merged object is, and whether it exports images - the other half of the
|
|
5299
|
+
* comparison a share image file is held to. Beside the metadata rather than
|
|
5300
|
+
* inside it, so the object a page's tags are rendered from stays only what
|
|
5301
|
+
* the app wrote.
|
|
5302
|
+
*/
|
|
5303
|
+
type ImageSources = { openGraph?: { depth: number; exports: boolean }; twitter?: { depth: number; exports: boolean } }
|
|
5304
|
+
|
|
5305
|
+
const imageSources = new WeakMap<object, ImageSources>()
|
|
5306
|
+
|
|
5212
5307
|
export async function resolveMetadata(
|
|
5213
5308
|
component: string,
|
|
5214
5309
|
props: Record<string, unknown> = {},
|
|
@@ -5273,18 +5368,27 @@ export async function resolveMetadata(
|
|
|
5273
5368
|
// happened to declare one of its own.
|
|
5274
5369
|
const merged: Record<string, unknown> = {}
|
|
5275
5370
|
const other: Record<string, unknown> = {}
|
|
5371
|
+
const sources: ImageSources = {}
|
|
5276
5372
|
|
|
5277
|
-
const take = (from: Record<string, unknown
|
|
5373
|
+
const take = (from: Record<string, unknown>, depth: number) => {
|
|
5278
5374
|
for (const [k, v] of Object.entries(from)) {
|
|
5279
5375
|
if (k === 'title') continue
|
|
5280
5376
|
if (k === 'other') Object.assign(other, v as Record<string, unknown>)
|
|
5281
5377
|
else merged[k] = v
|
|
5378
|
+
|
|
5379
|
+
// openGraph and twitter are replaced whole by a nearer segment's, so
|
|
5380
|
+
// whichever segment took them last is the one whose images - or lack of
|
|
5381
|
+
// them - the merged object carries. That segment's depth is what a file
|
|
5382
|
+
// in app/ is weighed against; see shareImages.ts.
|
|
5383
|
+
if (k === 'openGraph' || k === 'twitter') {
|
|
5384
|
+
sources[k] = { depth, exports: typeof v === 'object' && v !== null && (v as { images?: unknown }).images != null }
|
|
5385
|
+
}
|
|
5282
5386
|
}
|
|
5283
5387
|
}
|
|
5284
5388
|
|
|
5285
|
-
|
|
5389
|
+
layoutMeta.forEach((m, i) => take(m, depthOf(folderOf(layouts[i].component))))
|
|
5286
5390
|
|
|
5287
|
-
take(page)
|
|
5391
|
+
take(page, depthOf(folderOf(component)))
|
|
5288
5392
|
|
|
5289
5393
|
if (Object.keys(other).length > 0) merged.other = other
|
|
5290
5394
|
|
|
@@ -5309,7 +5413,11 @@ export async function resolveMetadata(
|
|
|
5309
5413
|
}
|
|
5310
5414
|
if (title != null) merged.title = title
|
|
5311
5415
|
|
|
5312
|
-
|
|
5416
|
+
if (Object.keys(merged).length === 0) return null
|
|
5417
|
+
|
|
5418
|
+
imageSources.set(merged, sources)
|
|
5419
|
+
|
|
5420
|
+
return merged
|
|
5313
5421
|
}
|
|
5314
5422
|
|
|
5315
5423
|
// Buffered render (worker: rsc / rscWithoutCallbacks — used at prerender time).
|
|
@@ -5939,7 +6047,11 @@ async function renderNotFound(request: Request): Promise<Response> {
|
|
|
5939
6047
|
: ""}
|
|
5940
6048
|
return new Response('Not found', { status: 404 })
|
|
5941
6049
|
}
|
|
5942
|
-
|
|
6050
|
+
${
|
|
6051
|
+
// After everything the entry is for: running a command reads its
|
|
6052
|
+
// register() and shutdown(). Only a build for an app that has commands; what
|
|
6053
|
+
// is in the table is decided later, when the bundle is built.
|
|
6054
|
+
withCommands ? commandsEntry(join(packageDir, "commands")) : ""}`;
|
|
5943
6055
|
}
|
|
5944
6056
|
function generateEntrySsr() {
|
|
5945
6057
|
const devUrls = join(packageDir, "devUrls");
|
|
@@ -7168,6 +7280,20 @@ export function rscKit(options = {}) {
|
|
|
7168
7280
|
if (nitro.options.dev)
|
|
7169
7281
|
return;
|
|
7170
7282
|
nitroPreset = nitro.options.preset ?? null;
|
|
7283
|
+
// The entry a command runs from, beside the server it does not start.
|
|
7284
|
+
// Written once Nitro has assembled the output, because it names a
|
|
7285
|
+
// file Nitro places: if that moves, the build says so rather than a
|
|
7286
|
+
// release step finding out.
|
|
7287
|
+
nitro.hooks.hook("compiled", async () => {
|
|
7288
|
+
if (buildCommands().length === 0)
|
|
7289
|
+
return;
|
|
7290
|
+
const serverDir = nitro.options.output.serverDir;
|
|
7291
|
+
if (!existsSync(join(serverDir, "_ssr", "rsc.mjs"))) {
|
|
7292
|
+
throw new Error(`[rsc-kit] src/commands runs from ${join(serverDir, "_ssr", "rsc.mjs")}, and Nitro did not write it there. ` +
|
|
7293
|
+
"Nitro's output layout changed; the commands entry needs to follow it.");
|
|
7294
|
+
}
|
|
7295
|
+
writeFileSync(join(serverDir, "commands.mjs"), commandsEntrySource());
|
|
7296
|
+
});
|
|
7171
7297
|
// On Workers the stored pages ride the static assets, not the bundle.
|
|
7172
7298
|
// Copied once Nitro has listed its public files, so the copies are
|
|
7173
7299
|
// not in that list: a path in it is served as an asset before the
|
|
@@ -7280,6 +7406,7 @@ export function rscKit(options = {}) {
|
|
|
7280
7406
|
// Both maps, not one: the config hook runs again when the config
|
|
7281
7407
|
// changes under a dev server, and a route.ts or a synthesised
|
|
7282
7408
|
// robots.txt left over from the previous run read as a duplicate.
|
|
7409
|
+
commandsFound = null;
|
|
7283
7410
|
components.clear();
|
|
7284
7411
|
apiRoutes.clear();
|
|
7285
7412
|
discover(appDir);
|
|
@@ -7362,7 +7489,7 @@ export function rscKit(options = {}) {
|
|
|
7362
7489
|
: env.command === "build"
|
|
7363
7490
|
? (declaresBackend ? "" : false)
|
|
7364
7491
|
: (detected || (declaresBackend ? "" : false));
|
|
7365
|
-
writeGenerated(join(genDir, "entry.rsc.tsx"), generateEntryRsc(fallbackOrigin));
|
|
7492
|
+
writeGenerated(join(genDir, "entry.rsc.tsx"), generateEntryRsc(fallbackOrigin, env.command === "build" && existsSync(join(sourceDir, "commands"))));
|
|
7366
7493
|
writeGenerated(join(genDir, "entry.ssr.tsx"), generateEntrySsr());
|
|
7367
7494
|
writeGenerated(join(genDir, "entry.browser.tsx"), generateEntryBrowser());
|
|
7368
7495
|
// Written beside the entries, for a host to read instead of walking the
|
|
@@ -7637,7 +7764,8 @@ export function rscKit(options = {}) {
|
|
|
7637
7764
|
res.end(webManifest(webManifestOptions));
|
|
7638
7765
|
return;
|
|
7639
7766
|
}
|
|
7640
|
-
|
|
7767
|
+
// Either spelling of a bracket: the tag says %5B, a hand-typed url says [.
|
|
7768
|
+
const asset = allAppAssets(foundAssets).find((a) => assetFile(a.href) === assetFile(url));
|
|
7641
7769
|
const file = asset ? join(sourceDir, "app", asset.file) : null;
|
|
7642
7770
|
if (!asset || !file || !existsSync(file))
|
|
7643
7771
|
return next();
|
|
@@ -7724,6 +7852,7 @@ export function rscKit(options = {}) {
|
|
|
7724
7852
|
// published without any — generic-host.test.ts fails if it reappears.
|
|
7725
7853
|
return ((base !== stem && shapes.has(stem)) ||
|
|
7726
7854
|
SECTION_FILE.test(base) ||
|
|
7855
|
+
SHARE_IMAGE_FILE.test(base) ||
|
|
7727
7856
|
(routeConfig !== null && base === routeConfig.file));
|
|
7728
7857
|
};
|
|
7729
7858
|
const restart = (file) => {
|
|
@@ -7840,7 +7969,7 @@ export function rscKit(options = {}) {
|
|
|
7840
7969
|
// And the entry a binary is compiled from, so the pages above end up
|
|
7841
7970
|
// inside it rather than rendered live: bun build --compile
|
|
7842
7971
|
// .output/server/compile.mjs. The scaffold's script names it.
|
|
7843
|
-
writeFileSync(join(dirname(staticDir), "compile.mjs"), compileEntrySource(NITRO_STATIC_DIR));
|
|
7972
|
+
writeFileSync(join(dirname(staticDir), "compile.mjs"), compileEntrySource(NITRO_STATIC_DIR, { commands: buildCommands().length > 0 }));
|
|
7844
7973
|
}
|
|
7845
7974
|
// Manifest first. The service worker precaches whatever it finds in this
|
|
7846
7975
|
// directory, so writing it afterwards leaves it out of the list — and an
|
|
@@ -7864,7 +7993,12 @@ export function rscKit(options = {}) {
|
|
|
7864
7993
|
if (clientOut) {
|
|
7865
7994
|
writeFileSync(join(dirname(clientOut), "rsc-kit.json"), JSON.stringify(output === "export"
|
|
7866
7995
|
? { version: PACKAGE_VERSION, output: "export", dir: relative(projectRoot, exportPath) }
|
|
7867
|
-
: {
|
|
7996
|
+
: {
|
|
7997
|
+
version: PACKAGE_VERSION,
|
|
7998
|
+
output: "server",
|
|
7999
|
+
...compileStep(projectRoot),
|
|
8000
|
+
...(buildCommands().length ? { commands: buildCommands().map((c) => c.name) } : {}),
|
|
8001
|
+
}, null, 2) + "\n");
|
|
7868
8002
|
}
|
|
7869
8003
|
},
|
|
7870
8004
|
configResolved(config) {
|
|
@@ -7947,6 +8081,7 @@ export function rscKit(options = {}) {
|
|
|
7947
8081
|
serverRendererInRsc(),
|
|
7948
8082
|
metadataRoutesPlugin(),
|
|
7949
8083
|
openApiPlugin(),
|
|
8084
|
+
commandsPlugin(),
|
|
7950
8085
|
extendableClientReferences(),
|
|
7951
8086
|
stableComponentNames(),
|
|
7952
8087
|
typecheckPlugin(),
|