@rshono/core 1.0.0-rc.11 → 1.0.0-rc.12
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 +2 -1
- package/dist/builder/rspack-config.d.ts +16 -0
- package/dist/builder/rspack-config.d.ts.map +1 -1
- package/dist/builder/rspack-config.js +24 -4
- package/dist/builder/rspack-config.js.map +1 -1
- package/dist/cli/build.js +2 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +29 -6
- package/dist/cli/dev.js.map +1 -1
- package/dist/deploy/filesystem.d.ts.map +1 -1
- package/dist/deploy/filesystem.js +7 -6
- package/dist/deploy/filesystem.js.map +1 -1
- package/dist/runtime/entry.client.d.ts.map +1 -1
- package/dist/runtime/entry.client.js +33 -25
- package/dist/runtime/entry.client.js.map +1 -1
- package/dist/runtime/hot-update.d.ts +52 -0
- package/dist/runtime/hot-update.d.ts.map +1 -0
- package/dist/runtime/hot-update.js +50 -0
- package/dist/runtime/hot-update.js.map +1 -0
- package/dist/server/server-config.d.ts +13 -5
- package/dist/server/server-config.d.ts.map +1 -1
- package/dist/server/server-config.js +2 -1
- package/dist/server/server-config.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -126,7 +126,8 @@ Call them directly from client code (typed args and result), or wire them to `<f
|
|
|
126
126
|
`useActionState` — forms keep working before hydration and with JavaScript disabled. Every action response
|
|
127
127
|
carries a fresh page payload, so server-rendered UI updates after a mutation.
|
|
128
128
|
**Every `'use server'` export is a public HTTP endpoint**, so authenticate, authorize and validate inside the
|
|
129
|
-
action. [Server actions docs](https://www.rshono.com/docs/server-actions)
|
|
129
|
+
action. [Server actions docs](https://www.rshono.com/docs/pages#server-actions), and
|
|
130
|
+
[how to use them](https://www.rshono.com/docs/usage).
|
|
130
131
|
|
|
131
132
|
## Full Hono underneath
|
|
132
133
|
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { type RspackOptions } from '@rspack/core';
|
|
2
2
|
import type { RshonoConfig } from '../config.js';
|
|
3
3
|
import type { DeployPreset } from '../deploy/presets.js';
|
|
4
|
+
/**
|
|
5
|
+
* The directory a command writes its bundles to, relative to the project root — one per command,
|
|
6
|
+
* never shared.
|
|
7
|
+
*
|
|
8
|
+
* `rshono build` run while `rshono dev` is up would otherwise write over the dev server's own
|
|
9
|
+
* output: the build's `clean` empties `<out>/server`, and the route chunks it deletes are exactly
|
|
10
|
+
* the ones the running server worker imports *lazily, at request time*. Every route the worker had
|
|
11
|
+
* not already loaded then fails with `ERR_MODULE_NOT_FOUND`, and no later edit repairs it, because
|
|
12
|
+
* Rspack's watch-mode emit compares against what it believes it already wrote rather than against
|
|
13
|
+
* the disk — so it never re-emits the deleted files. The dev server 500s until it is restarted.
|
|
14
|
+
*
|
|
15
|
+
* Both names are a single level under the root, which {@link ../deploy/filesystem.ts} relies on: it
|
|
16
|
+
* derives the project root from where the bundle ended up, `<out>/server/main.mjs` → `../..`.
|
|
17
|
+
*/
|
|
18
|
+
export declare const BUILD_OUT_DIR = "dist";
|
|
19
|
+
export declare const DEV_OUT_DIR = ".rshono";
|
|
4
20
|
export interface RspackConfigOptions {
|
|
5
21
|
rootDir: string;
|
|
6
22
|
isDev: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rspack-config.d.ts","sourceRoot":"","sources":["../../src/builder/rspack-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,aAAa,EAAoB,MAAM,cAAc,CAAC;AAK3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"rspack-config.d.ts","sourceRoot":"","sources":["../../src/builder/rspack-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,aAAa,EAAoB,MAAM,cAAc,CAAC;AAK3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAYzD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,aAAa,SAAS,CAAC;AACpC,eAAO,MAAM,WAAW,YAAY,CAAC;AAgFrC,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,2IAA2I;IAC3I,MAAM,EAAE,YAAY,CAAC;IACrB,4GAA4G;IAC5G,MAAM,EAAE,YAAY,CAAC;IACrB,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,mBAAmB,GAAG,CAAC,aAAa,EAAE,aAAa,CAAC,CAgN1F"}
|
|
@@ -11,6 +11,22 @@ import { publicEnv } from './public-env.js';
|
|
|
11
11
|
const FRAMEWORK_DIST = join(import.meta.dirname, '..');
|
|
12
12
|
const FRAMEWORK_ROOT = join(FRAMEWORK_DIST, '..');
|
|
13
13
|
const BUNDLED_PACKAGES = /^(@rshono\/core|react|react-dom|react-server-dom-rspack|hono|@hono\/node-server)(\/|$)/;
|
|
14
|
+
/**
|
|
15
|
+
* The directory a command writes its bundles to, relative to the project root — one per command,
|
|
16
|
+
* never shared.
|
|
17
|
+
*
|
|
18
|
+
* `rshono build` run while `rshono dev` is up would otherwise write over the dev server's own
|
|
19
|
+
* output: the build's `clean` empties `<out>/server`, and the route chunks it deletes are exactly
|
|
20
|
+
* the ones the running server worker imports *lazily, at request time*. Every route the worker had
|
|
21
|
+
* not already loaded then fails with `ERR_MODULE_NOT_FOUND`, and no later edit repairs it, because
|
|
22
|
+
* Rspack's watch-mode emit compares against what it believes it already wrote rather than against
|
|
23
|
+
* the disk — so it never re-emits the deleted files. The dev server 500s until it is restarted.
|
|
24
|
+
*
|
|
25
|
+
* Both names are a single level under the root, which {@link ../deploy/filesystem.ts} relies on: it
|
|
26
|
+
* derives the project root from where the bundle ended up, `<out>/server/main.mjs` → `../..`.
|
|
27
|
+
*/
|
|
28
|
+
export const BUILD_OUT_DIR = 'dist';
|
|
29
|
+
export const DEV_OUT_DIR = '.rshono';
|
|
14
30
|
/**
|
|
15
31
|
* Packages that end up imported *by app source* without the app ever mentioning them: the RSC
|
|
16
32
|
* transform rewrites a `'use client'` module, a page or a server action into imports of the RSC
|
|
@@ -90,6 +106,7 @@ export function createConfigs(options) {
|
|
|
90
106
|
const { rootDir, isDev, config, preset, onServerComponentChanges } = options;
|
|
91
107
|
const srcDir = join(rootDir, 'src');
|
|
92
108
|
const mode = isDev ? 'development' : 'production';
|
|
109
|
+
const outDir = isDev ? DEV_OUT_DIR : BUILD_OUT_DIR;
|
|
93
110
|
const routesFile = ['routes.ts', 'routes.tsx'].map((f) => join(srcDir, f)).find(existsSync);
|
|
94
111
|
if (!routesFile) {
|
|
95
112
|
throw new Error(`[rshono] src/routes.ts not found in ${rootDir} — it is the one required file.`);
|
|
@@ -146,7 +163,7 @@ export function createConfigs(options) {
|
|
|
146
163
|
devtool: isDev ? 'source-map' : false,
|
|
147
164
|
entry: { main: clientEntry },
|
|
148
165
|
output: {
|
|
149
|
-
path: join(rootDir,
|
|
166
|
+
path: join(rootDir, outDir, 'static'),
|
|
150
167
|
publicPath: '/_static/',
|
|
151
168
|
clean: !isDev,
|
|
152
169
|
filename: isDev ? 'chunks/main.js' : 'chunks/main.[contenthash].js',
|
|
@@ -180,8 +197,11 @@ export function createConfigs(options) {
|
|
|
180
197
|
devtool: isDev ? 'source-map' : false,
|
|
181
198
|
entry: { main: rscEntry },
|
|
182
199
|
output: {
|
|
183
|
-
path: join(rootDir,
|
|
184
|
-
|
|
200
|
+
path: join(rootDir, outDir, 'server'),
|
|
201
|
+
// Off in dev, matching the client compiler above: route chunks are imported lazily, at request
|
|
202
|
+
// time, so leaving a superseded one on disk is harmless where deleting one mid-request is not.
|
|
203
|
+
// `rshono dev` empties the directory on startup, so nothing accumulates across sessions.
|
|
204
|
+
clean: !isDev,
|
|
185
205
|
module: true,
|
|
186
206
|
chunkFormat: 'module',
|
|
187
207
|
chunkLoading: 'import',
|
|
@@ -262,7 +282,7 @@ export function createConfigs(options) {
|
|
|
262
282
|
pageScanPlugin,
|
|
263
283
|
new ServerPlugin({ onServerComponentChanges }),
|
|
264
284
|
// Bakes rshono.config.ts into the bundle, read back as `__RSHONO_CONFIG__` at request time.
|
|
265
|
-
new rspack.DefinePlugin({ __RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev })) }),
|
|
285
|
+
new rspack.DefinePlugin({ __RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev, outDir })) }),
|
|
266
286
|
],
|
|
267
287
|
performance: false,
|
|
268
288
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rspack-config.js","sourceRoot":"","sources":["../../src/builder/rspack-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { rspack, type Compiler, type RspackOptions, type RuleSetRule } from '@rspack/core';\nimport { ReactRefreshRspackPlugin } from '@rspack/plugin-react-refresh';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join, win32 } from 'node:path';\nimport type { RshonoConfig } from '../config.js';\nimport type { DeployPreset } from '../deploy/presets.js';\nimport { resolveServerConfig } from '../server/server-config.js';\nimport { scanPageFiles } from './page-files.js';\nimport { publicEnv } from './public-env.js';\n\n// The framework's own compiled output (this file lives in `dist/builder/`), which is what the two\n// compilers consume: the entries and loaders below are the *built* framework, not its TypeScript.\nconst FRAMEWORK_DIST = join(import.meta.dirname, '..');\nconst FRAMEWORK_ROOT = join(FRAMEWORK_DIST, '..');\n\nconst BUNDLED_PACKAGES = /^(@rshono\\/core|react|react-dom|react-server-dom-rspack|hono|@hono\\/node-server)(\\/|$)/;\n\n/**\n * Packages that end up imported *by app source* without the app ever mentioning them: the RSC\n * transform rewrites a `'use client'` module, a page or a server action into imports of the RSC\n * runtime, and those requests resolve from the app's own `src/`.\n */\nconst INJECTED_PACKAGES = ['react-server-dom-rspack'];\n\n/** The `node_modules` directory a resolved file sits in — `…/node_modules/pkg/index.js` → `…/node_modules`. */\nfunction enclosingNodeModules(file: string): string | undefined {\n let dir = dirname(file);\n while (basename(dir) !== 'node_modules') {\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n return dir;\n}\n\n/**\n * Where packages are resolved from: the app's own `node_modules`, then the framework's.\n *\n * The second part is what makes {@link INJECTED_PACKAGES} resolvable from app source. npm, yarn and\n * bun hoist the framework's dependencies into the app's own `node_modules`; pnpm installs them as\n * *siblings* of `@rshono/core` where nothing under the app's tree can see them, and the build then\n * fails with `Can't resolve 'react-server-dom-rspack/client'` in a file the user never wrote that\n * import into.\n *\n * Asking Node where the framework itself resolves the package finds the directory in any layout, and\n * a search path rather than an alias keeps the package's own `exports` conditions in play — the RSC\n * layer, the SSR layer and each deploy target need a different build of it.\n */\nfunction resolveModules(): string[] {\n const require = createRequire(import.meta.url);\n const dirs = new Set<string>();\n for (const name of INJECTED_PACKAGES) {\n try {\n const dir = enclosingNodeModules(require.resolve(name));\n if (dir) dirs.add(dir);\n } catch {\n // Left to the resolver to report against the request that actually needed it.\n }\n }\n // A checkout or a vendored copy, where the framework has real dependencies of its own and the lookup\n // above found nothing to add.\n dirs.add(join(FRAMEWORK_ROOT, 'node_modules'));\n return ['node_modules', ...dirs];\n}\n\n/**\n * Whether a request names a file rather than a package, and so belongs in the bundle.\n *\n * Rspack's RSC plugins ask for their client and server-entry proxies by *absolute path*, which on\n * Windows means a drive letter (`D:\\app\\src\\home.tsx`) instead of a leading slash. Externalizing one\n * of those emits `import(\"D:\\\\app\\\\src\\\\home.tsx\")`, which Node rejects with\n * `ERR_UNSUPPORTED_ESM_URL_SCHEME`. `win32.isAbsolute` also accepts the POSIX form, so it is used on\n * every platform — one code path, and the Windows shapes stay testable off Windows.\n */\nfunction isPathRequest(request: string): boolean {\n return request.startsWith('.') || win32.isAbsolute(request);\n}\n\nconst BROWSER_TARGETS = ['last 2 versions', '> 0.2%', 'not dead', 'Firefox ESR'];\nconst NODE_TARGETS = ['node >= 22'];\n\n/**\n * Rspack's native CSS pipeline, which both compilers get.\n *\n * It parses *finished* CSS, so a stylesheet needing a PostCSS plugin — Tailwind, most obviously —\n * adds the loader through the {@link RshonoConfig.rspack} hook, along with the packages a PostCSS\n * pass takes. `postcss` is then a dependency of the apps that want one rather than of every app.\n *\n * A fresh object per compiler, so an app that reaches in to change this rule does not find it has\n * changed the other bundle's too.\n */\nfunction cssRule(): RuleSetRule {\n return { test: /\\.css$/i, type: 'css/auto' };\n}\n\nexport interface RspackConfigOptions {\n rootDir: string;\n isDev: boolean;\n /** The project's resolved config — supplies the {@link RshonoConfig.rspack} hook and the runtime settings baked into the server bundle. */\n config: RshonoConfig;\n /** The platform being built for: decides the `@rshono/deploy` runtime and any server-compiler overrides. */\n preset: DeployPreset;\n onServerComponentChanges?: () => void;\n}\n\nexport function createConfigs(options: RspackConfigOptions): [RspackOptions, RspackOptions] {\n const { rootDir, isDev, config, preset, onServerComponentChanges } = options;\n const srcDir = join(rootDir, 'src');\n const mode = isDev ? 'development' : 'production';\n\n const routesFile = ['routes.ts', 'routes.tsx'].map((f) => join(srcDir, f)).find(existsSync);\n if (!routesFile) {\n throw new Error(`[rshono] src/routes.ts not found in ${rootDir} — it is the one required file.`);\n }\n const serverAppFile = ['server.ts', 'server.tsx'].map((f) => join(srcDir, f)).find(existsSync);\n const serverAppAlias = serverAppFile ?? join(FRAMEWORK_DIST, 'runtime', 'empty-server-app.js');\n\n const rscEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.rsc.js');\n const ssrEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.ssr.js');\n const clientEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.client.js');\n\n const swcRule = (targets: string[]): RuleSetRule => ({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /[\\\\/]core-js[\\\\/]/,\n use: {\n loader: 'builtin:swc-loader',\n options: {\n detectSyntax: 'auto',\n jsc: {\n transform: { react: { runtime: 'automatic', development: isDev } },\n experimental: { keepImportAttributes: true },\n },\n env: { targets },\n rspackExperiments: { reactServerComponents: true },\n },\n },\n type: 'javascript/auto',\n });\n\n const resolveBase = {\n extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],\n extensionAlias: { '.js': ['.ts', '.tsx', '.js'] },\n modules: resolveModules(),\n };\n\n // The platform's own resolve conditions, ahead of whatever the Rspack target implies ('...'). This\n // is what hands the server bundle the right build of React and the RSC runtime, both of which ship\n // one per runtime. Left unset for Node, where the target already implies the `node` condition.\n const runtimeConditions = preset.resolveConditions ?? [];\n const serverResolveBase = runtimeConditions.length > 0 ? { ...resolveBase, conditionNames: [...runtimeConditions, '...'] } : resolveBase;\n const rscConditionNames = ['react-server', ...runtimeConditions, '...'];\n\n const { ServerPlugin, ClientPlugin } = rspack.experiments.rsc.createPlugins();\n const { Layers } = rspack.experiments.rsc;\n\n const pageFiles = new Set<string>();\n scanPageFiles(routesFile, srcDir, pageFiles);\n const pageScanPlugin = {\n apply(compiler: Compiler) {\n const refresh = () => scanPageFiles(routesFile, srcDir, pageFiles);\n compiler.hooks.beforeRun.tap('rshono/page-scan', refresh);\n compiler.hooks.watchRun.tap('rshono/page-scan', refresh);\n },\n };\n\n const clientConfig: RspackOptions = {\n name: 'client',\n mode,\n target: 'web',\n context: rootDir,\n devtool: isDev ? 'source-map' : false,\n entry: { main: clientEntry },\n output: {\n path: join(rootDir, 'dist', 'static'),\n publicPath: '/_static/',\n clean: !isDev,\n filename: isDev ? 'chunks/main.js' : 'chunks/main.[contenthash].js',\n chunkFilename: isDev ? 'chunks/[name].js' : 'chunks/[name].[contenthash].js',\n cssFilename: isDev ? 'chunks/[name].css' : 'chunks/[name].[contenthash].css',\n cssChunkFilename: isDev ? 'chunks/[name].css' : 'chunks/[name].[contenthash].css',\n assetModuleFilename: 'assets/[name].[hash][ext]',\n },\n optimization: {\n moduleIds: isDev ? 'named' : 'hashed',\n },\n resolve: {\n ...resolveBase,\n alias: { '@': srcDir },\n },\n module: {\n rules: [swcRule(BROWSER_TARGETS), cssRule(), { test: /\\.(png|jpe?g|gif|webp|avif|ico|svg|woff2?|ttf|otf)$/i, type: 'asset' }],\n },\n plugins: [\n new ClientPlugin(),\n new rspack.DefinePlugin({ 'process.env': JSON.stringify(publicEnv(isDev)) }),\n ...(isDev ? [new rspack.HotModuleReplacementPlugin(), new ReactRefreshRspackPlugin()] : []),\n ],\n performance: false,\n };\n\n const serverConfig: RspackOptions = {\n name: 'server',\n mode,\n target: 'node',\n context: rootDir,\n devtool: isDev ? 'source-map' : false,\n entry: { main: rscEntry },\n output: {\n path: join(rootDir, 'dist', 'server'),\n clean: true,\n module: true,\n chunkFormat: 'module',\n chunkLoading: 'import',\n library: { type: 'module' },\n filename: 'main.mjs',\n chunkFilename: 'chunks/[name].mjs',\n publicPath: '/_static/',\n assetModuleFilename: 'assets/[name].[hash][ext]',\n },\n optimization: {\n minimize: isDev ? false : true,\n },\n externalsType: 'module-import',\n externals: [\n ({ request }, callback) => {\n if (\n !request ||\n isPathRequest(request) ||\n request.startsWith('@/') ||\n request.startsWith('@rshono/') ||\n request.startsWith('builtin:') ||\n request.includes('!') ||\n BUNDLED_PACKAGES.test(request)\n ) {\n return callback();\n }\n callback(undefined, `module-import ${request}`);\n },\n ],\n resolve: {\n ...serverResolveBase,\n alias: {\n '@rshono/routes$': routesFile,\n '@rshono/server-app$': serverAppAlias,\n // The one import that decides which platform the server bundle is for. Split on '/' so the\n // preset can declare a POSIX-looking path and still resolve on Windows.\n '@rshono/deploy$': join(FRAMEWORK_DIST, ...preset.runtimeModule.split('/')),\n '@': srcDir,\n },\n },\n module: {\n rules: [\n {\n test: (resource: string) => pageFiles.has(resource),\n enforce: 'pre',\n use: [{ loader: join(FRAMEWORK_DIST, 'builder', 'page-entry-loader.cjs') }],\n },\n {\n test: /\\.[cm]?[tj]sx?$/,\n include: srcDir,\n enforce: 'pre',\n use: [\n {\n loader: join(FRAMEWORK_DIST, 'builder', 'env-shadow-loader.cjs'),\n options: { prelude: `const process = { env: ${JSON.stringify(publicEnv(isDev))} }; `, layer: Layers.ssr },\n },\n ],\n },\n swcRule([...(preset.syntaxTargets ?? NODE_TARGETS)]),\n cssRule(),\n {\n test: /\\.(png|jpe?g|gif|webp|avif|ico|svg|woff2?|ttf|otf)$/i,\n type: 'asset',\n generator: { emit: false },\n },\n { resource: ssrEntry, layer: Layers.ssr },\n {\n resource: rscEntry,\n layer: Layers.rsc,\n resolve: { conditionNames: rscConditionNames },\n },\n {\n issuerLayer: Layers.rsc,\n exclude: ssrEntry,\n resolve: { conditionNames: rscConditionNames },\n },\n ],\n },\n plugins: [\n pageScanPlugin,\n new ServerPlugin({ onServerComponentChanges }),\n // Bakes rshono.config.ts into the bundle, read back as `__RSHONO_CONFIG__` at request time.\n new rspack.DefinePlugin({ __RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev })) }),\n ],\n performance: false,\n };\n\n // The platform's own overrides, then the user's hook — so an app can still adjust whatever a\n // preset decided.\n preset.configureServer?.(serverConfig);\n\n const rspackHook = config.rspack;\n if (rspackHook) {\n return [\n rspackHook(clientConfig, { isServer: false, isDev }) ?? clientConfig,\n rspackHook(serverConfig, { isServer: true, isDev }) ?? serverConfig,\n ];\n }\n return [clientConfig, serverConfig];\n}\n"]}
|
|
1
|
+
{"version":3,"file":"rspack-config.js","sourceRoot":"","sources":["../../src/builder/rspack-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { rspack, type Compiler, type RspackOptions, type RuleSetRule } from '@rspack/core';\nimport { ReactRefreshRspackPlugin } from '@rspack/plugin-react-refresh';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join, win32 } from 'node:path';\nimport type { RshonoConfig } from '../config.js';\nimport type { DeployPreset } from '../deploy/presets.js';\nimport { resolveServerConfig } from '../server/server-config.js';\nimport { scanPageFiles } from './page-files.js';\nimport { publicEnv } from './public-env.js';\n\n// The framework's own compiled output (this file lives in `dist/builder/`), which is what the two\n// compilers consume: the entries and loaders below are the *built* framework, not its TypeScript.\nconst FRAMEWORK_DIST = join(import.meta.dirname, '..');\nconst FRAMEWORK_ROOT = join(FRAMEWORK_DIST, '..');\n\nconst BUNDLED_PACKAGES = /^(@rshono\\/core|react|react-dom|react-server-dom-rspack|hono|@hono\\/node-server)(\\/|$)/;\n\n/**\n * The directory a command writes its bundles to, relative to the project root — one per command,\n * never shared.\n *\n * `rshono build` run while `rshono dev` is up would otherwise write over the dev server's own\n * output: the build's `clean` empties `<out>/server`, and the route chunks it deletes are exactly\n * the ones the running server worker imports *lazily, at request time*. Every route the worker had\n * not already loaded then fails with `ERR_MODULE_NOT_FOUND`, and no later edit repairs it, because\n * Rspack's watch-mode emit compares against what it believes it already wrote rather than against\n * the disk — so it never re-emits the deleted files. The dev server 500s until it is restarted.\n *\n * Both names are a single level under the root, which {@link ../deploy/filesystem.ts} relies on: it\n * derives the project root from where the bundle ended up, `<out>/server/main.mjs` → `../..`.\n */\nexport const BUILD_OUT_DIR = 'dist';\nexport const DEV_OUT_DIR = '.rshono';\n\n/**\n * Packages that end up imported *by app source* without the app ever mentioning them: the RSC\n * transform rewrites a `'use client'` module, a page or a server action into imports of the RSC\n * runtime, and those requests resolve from the app's own `src/`.\n */\nconst INJECTED_PACKAGES = ['react-server-dom-rspack'];\n\n/** The `node_modules` directory a resolved file sits in — `…/node_modules/pkg/index.js` → `…/node_modules`. */\nfunction enclosingNodeModules(file: string): string | undefined {\n let dir = dirname(file);\n while (basename(dir) !== 'node_modules') {\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n return dir;\n}\n\n/**\n * Where packages are resolved from: the app's own `node_modules`, then the framework's.\n *\n * The second part is what makes {@link INJECTED_PACKAGES} resolvable from app source. npm, yarn and\n * bun hoist the framework's dependencies into the app's own `node_modules`; pnpm installs them as\n * *siblings* of `@rshono/core` where nothing under the app's tree can see them, and the build then\n * fails with `Can't resolve 'react-server-dom-rspack/client'` in a file the user never wrote that\n * import into.\n *\n * Asking Node where the framework itself resolves the package finds the directory in any layout, and\n * a search path rather than an alias keeps the package's own `exports` conditions in play — the RSC\n * layer, the SSR layer and each deploy target need a different build of it.\n */\nfunction resolveModules(): string[] {\n const require = createRequire(import.meta.url);\n const dirs = new Set<string>();\n for (const name of INJECTED_PACKAGES) {\n try {\n const dir = enclosingNodeModules(require.resolve(name));\n if (dir) dirs.add(dir);\n } catch {\n // Left to the resolver to report against the request that actually needed it.\n }\n }\n // A checkout or a vendored copy, where the framework has real dependencies of its own and the lookup\n // above found nothing to add.\n dirs.add(join(FRAMEWORK_ROOT, 'node_modules'));\n return ['node_modules', ...dirs];\n}\n\n/**\n * Whether a request names a file rather than a package, and so belongs in the bundle.\n *\n * Rspack's RSC plugins ask for their client and server-entry proxies by *absolute path*, which on\n * Windows means a drive letter (`D:\\app\\src\\home.tsx`) instead of a leading slash. Externalizing one\n * of those emits `import(\"D:\\\\app\\\\src\\\\home.tsx\")`, which Node rejects with\n * `ERR_UNSUPPORTED_ESM_URL_SCHEME`. `win32.isAbsolute` also accepts the POSIX form, so it is used on\n * every platform — one code path, and the Windows shapes stay testable off Windows.\n */\nfunction isPathRequest(request: string): boolean {\n return request.startsWith('.') || win32.isAbsolute(request);\n}\n\nconst BROWSER_TARGETS = ['last 2 versions', '> 0.2%', 'not dead', 'Firefox ESR'];\nconst NODE_TARGETS = ['node >= 22'];\n\n/**\n * Rspack's native CSS pipeline, which both compilers get.\n *\n * It parses *finished* CSS, so a stylesheet needing a PostCSS plugin — Tailwind, most obviously —\n * adds the loader through the {@link RshonoConfig.rspack} hook, along with the packages a PostCSS\n * pass takes. `postcss` is then a dependency of the apps that want one rather than of every app.\n *\n * A fresh object per compiler, so an app that reaches in to change this rule does not find it has\n * changed the other bundle's too.\n */\nfunction cssRule(): RuleSetRule {\n return { test: /\\.css$/i, type: 'css/auto' };\n}\n\nexport interface RspackConfigOptions {\n rootDir: string;\n isDev: boolean;\n /** The project's resolved config — supplies the {@link RshonoConfig.rspack} hook and the runtime settings baked into the server bundle. */\n config: RshonoConfig;\n /** The platform being built for: decides the `@rshono/deploy` runtime and any server-compiler overrides. */\n preset: DeployPreset;\n onServerComponentChanges?: () => void;\n}\n\nexport function createConfigs(options: RspackConfigOptions): [RspackOptions, RspackOptions] {\n const { rootDir, isDev, config, preset, onServerComponentChanges } = options;\n const srcDir = join(rootDir, 'src');\n const mode = isDev ? 'development' : 'production';\n const outDir = isDev ? DEV_OUT_DIR : BUILD_OUT_DIR;\n\n const routesFile = ['routes.ts', 'routes.tsx'].map((f) => join(srcDir, f)).find(existsSync);\n if (!routesFile) {\n throw new Error(`[rshono] src/routes.ts not found in ${rootDir} — it is the one required file.`);\n }\n const serverAppFile = ['server.ts', 'server.tsx'].map((f) => join(srcDir, f)).find(existsSync);\n const serverAppAlias = serverAppFile ?? join(FRAMEWORK_DIST, 'runtime', 'empty-server-app.js');\n\n const rscEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.rsc.js');\n const ssrEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.ssr.js');\n const clientEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.client.js');\n\n const swcRule = (targets: string[]): RuleSetRule => ({\n test: /\\.[cm]?[jt]sx?$/,\n exclude: /[\\\\/]core-js[\\\\/]/,\n use: {\n loader: 'builtin:swc-loader',\n options: {\n detectSyntax: 'auto',\n jsc: {\n transform: { react: { runtime: 'automatic', development: isDev } },\n experimental: { keepImportAttributes: true },\n },\n env: { targets },\n rspackExperiments: { reactServerComponents: true },\n },\n },\n type: 'javascript/auto',\n });\n\n const resolveBase = {\n extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],\n extensionAlias: { '.js': ['.ts', '.tsx', '.js'] },\n modules: resolveModules(),\n };\n\n // The platform's own resolve conditions, ahead of whatever the Rspack target implies ('...'). This\n // is what hands the server bundle the right build of React and the RSC runtime, both of which ship\n // one per runtime. Left unset for Node, where the target already implies the `node` condition.\n const runtimeConditions = preset.resolveConditions ?? [];\n const serverResolveBase = runtimeConditions.length > 0 ? { ...resolveBase, conditionNames: [...runtimeConditions, '...'] } : resolveBase;\n const rscConditionNames = ['react-server', ...runtimeConditions, '...'];\n\n const { ServerPlugin, ClientPlugin } = rspack.experiments.rsc.createPlugins();\n const { Layers } = rspack.experiments.rsc;\n\n const pageFiles = new Set<string>();\n scanPageFiles(routesFile, srcDir, pageFiles);\n const pageScanPlugin = {\n apply(compiler: Compiler) {\n const refresh = () => scanPageFiles(routesFile, srcDir, pageFiles);\n compiler.hooks.beforeRun.tap('rshono/page-scan', refresh);\n compiler.hooks.watchRun.tap('rshono/page-scan', refresh);\n },\n };\n\n const clientConfig: RspackOptions = {\n name: 'client',\n mode,\n target: 'web',\n context: rootDir,\n devtool: isDev ? 'source-map' : false,\n entry: { main: clientEntry },\n output: {\n path: join(rootDir, outDir, 'static'),\n publicPath: '/_static/',\n clean: !isDev,\n filename: isDev ? 'chunks/main.js' : 'chunks/main.[contenthash].js',\n chunkFilename: isDev ? 'chunks/[name].js' : 'chunks/[name].[contenthash].js',\n cssFilename: isDev ? 'chunks/[name].css' : 'chunks/[name].[contenthash].css',\n cssChunkFilename: isDev ? 'chunks/[name].css' : 'chunks/[name].[contenthash].css',\n assetModuleFilename: 'assets/[name].[hash][ext]',\n },\n optimization: {\n moduleIds: isDev ? 'named' : 'hashed',\n },\n resolve: {\n ...resolveBase,\n alias: { '@': srcDir },\n },\n module: {\n rules: [swcRule(BROWSER_TARGETS), cssRule(), { test: /\\.(png|jpe?g|gif|webp|avif|ico|svg|woff2?|ttf|otf)$/i, type: 'asset' }],\n },\n plugins: [\n new ClientPlugin(),\n new rspack.DefinePlugin({ 'process.env': JSON.stringify(publicEnv(isDev)) }),\n ...(isDev ? [new rspack.HotModuleReplacementPlugin(), new ReactRefreshRspackPlugin()] : []),\n ],\n performance: false,\n };\n\n const serverConfig: RspackOptions = {\n name: 'server',\n mode,\n target: 'node',\n context: rootDir,\n devtool: isDev ? 'source-map' : false,\n entry: { main: rscEntry },\n output: {\n path: join(rootDir, outDir, 'server'),\n // Off in dev, matching the client compiler above: route chunks are imported lazily, at request\n // time, so leaving a superseded one on disk is harmless where deleting one mid-request is not.\n // `rshono dev` empties the directory on startup, so nothing accumulates across sessions.\n clean: !isDev,\n module: true,\n chunkFormat: 'module',\n chunkLoading: 'import',\n library: { type: 'module' },\n filename: 'main.mjs',\n chunkFilename: 'chunks/[name].mjs',\n publicPath: '/_static/',\n assetModuleFilename: 'assets/[name].[hash][ext]',\n },\n optimization: {\n minimize: isDev ? false : true,\n },\n externalsType: 'module-import',\n externals: [\n ({ request }, callback) => {\n if (\n !request ||\n isPathRequest(request) ||\n request.startsWith('@/') ||\n request.startsWith('@rshono/') ||\n request.startsWith('builtin:') ||\n request.includes('!') ||\n BUNDLED_PACKAGES.test(request)\n ) {\n return callback();\n }\n callback(undefined, `module-import ${request}`);\n },\n ],\n resolve: {\n ...serverResolveBase,\n alias: {\n '@rshono/routes$': routesFile,\n '@rshono/server-app$': serverAppAlias,\n // The one import that decides which platform the server bundle is for. Split on '/' so the\n // preset can declare a POSIX-looking path and still resolve on Windows.\n '@rshono/deploy$': join(FRAMEWORK_DIST, ...preset.runtimeModule.split('/')),\n '@': srcDir,\n },\n },\n module: {\n rules: [\n {\n test: (resource: string) => pageFiles.has(resource),\n enforce: 'pre',\n use: [{ loader: join(FRAMEWORK_DIST, 'builder', 'page-entry-loader.cjs') }],\n },\n {\n test: /\\.[cm]?[tj]sx?$/,\n include: srcDir,\n enforce: 'pre',\n use: [\n {\n loader: join(FRAMEWORK_DIST, 'builder', 'env-shadow-loader.cjs'),\n options: { prelude: `const process = { env: ${JSON.stringify(publicEnv(isDev))} }; `, layer: Layers.ssr },\n },\n ],\n },\n swcRule([...(preset.syntaxTargets ?? NODE_TARGETS)]),\n cssRule(),\n {\n test: /\\.(png|jpe?g|gif|webp|avif|ico|svg|woff2?|ttf|otf)$/i,\n type: 'asset',\n generator: { emit: false },\n },\n { resource: ssrEntry, layer: Layers.ssr },\n {\n resource: rscEntry,\n layer: Layers.rsc,\n resolve: { conditionNames: rscConditionNames },\n },\n {\n issuerLayer: Layers.rsc,\n exclude: ssrEntry,\n resolve: { conditionNames: rscConditionNames },\n },\n ],\n },\n plugins: [\n pageScanPlugin,\n new ServerPlugin({ onServerComponentChanges }),\n // Bakes rshono.config.ts into the bundle, read back as `__RSHONO_CONFIG__` at request time.\n new rspack.DefinePlugin({ __RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev, outDir })) }),\n ],\n performance: false,\n };\n\n // The platform's own overrides, then the user's hook — so an app can still adjust whatever a\n // preset decided.\n preset.configureServer?.(serverConfig);\n\n const rspackHook = config.rspack;\n if (rspackHook) {\n return [\n rspackHook(clientConfig, { isServer: false, isDev }) ?? clientConfig,\n rspackHook(serverConfig, { isServer: true, isDev }) ?? serverConfig,\n ];\n }\n return [clientConfig, serverConfig];\n}\n"]}
|
package/dist/cli/build.js
CHANGED
|
@@ -3,12 +3,12 @@ import { cpSync, existsSync } from 'node:fs';
|
|
|
3
3
|
import { rm } from 'node:fs/promises';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
5
|
import { pathToFileURL } from 'node:url';
|
|
6
|
-
import { createConfigs } from '../builder/rspack-config.js';
|
|
6
|
+
import { BUILD_OUT_DIR, createConfigs } from '../builder/rspack-config.js';
|
|
7
7
|
import { writeBuildMarker } from '../deploy/build-marker.js';
|
|
8
8
|
import { prerenderStaticRoutes } from '../server/ssg.js';
|
|
9
9
|
export async function buildCommand(options) {
|
|
10
10
|
const { rootDir, config, preset } = options;
|
|
11
|
-
const distDir = join(rootDir,
|
|
11
|
+
const distDir = join(rootDir, BUILD_OUT_DIR);
|
|
12
12
|
console.log(' • building client + server bundles…');
|
|
13
13
|
const configs = createConfigs({ rootDir, isDev: false, config, preset });
|
|
14
14
|
const compiler = rspack(configs);
|
package/dist/cli/build.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAmB,MAAM,cAAc,CAAC;AAEvD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { rspack, type MultiStats } from '@rspack/core';\nimport type { Hono } from 'hono';\nimport { cpSync, existsSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport { BUILD_OUT_DIR, createConfigs } from '../builder/rspack-config.js';\nimport type { RshonoConfig } from '../config.js';\nimport { writeBuildMarker } from '../deploy/build-marker.js';\nimport type { DeployPreset } from '../deploy/presets.js';\nimport type { Route } from '../router.js';\nimport { prerenderStaticRoutes } from '../server/ssg.js';\n\ninterface BuildOptions {\n rootDir: string;\n config: RshonoConfig;\n /** The platform to build for, already resolved from the flag, the environment and the config. */\n preset: DeployPreset;\n}\n\nexport async function buildCommand(options: BuildOptions): Promise<void> {\n const { rootDir, config, preset } = options;\n const distDir = join(rootDir, BUILD_OUT_DIR);\n\n console.log(' • building client + server bundles…');\n const configs = createConfigs({ rootDir, isDev: false, config, preset });\n const compiler = rspack(configs);\n\n const stats = await new Promise<MultiStats>((resolve, reject) => {\n compiler.run((err, result) => {\n compiler.close(() => {\n if (err) reject(err);\n else resolve(result!);\n });\n });\n });\n\n if (stats.hasErrors()) {\n console.error(stats.toString({ preset: 'errors-warnings', colors: true }));\n process.exit(1);\n }\n console.log(stats.toString({ preset: 'summary', colors: true }));\n\n const publicDir = join(rootDir, 'public');\n let distPublicDir: string | null = null;\n if (existsSync(publicDir)) {\n distPublicDir = join(distDir, 'public');\n cpSync(publicDir, distPublicDir, { recursive: true });\n console.log(' • copied public/ into dist/public (served at /)');\n }\n\n const ssgDir = join(distDir, 'ssg');\n await rm(ssgDir, { recursive: true, force: true });\n process.env.RSHONO_PRERENDER = '1';\n const bundle = (await import(pathToFileURL(join(distDir, 'server', 'main.mjs')).href)) as {\n app: Hono;\n routes: readonly Route[];\n };\n const { written, skipped } = await prerenderStaticRoutes({\n routes: bundle.routes,\n fetch: (request) => bundle.app.fetch(request),\n ssgDir,\n siteUrl: config.siteUrl,\n });\n if (written.length > 0) console.log(` • prerendered ${written.length} static page(s): ${written.join(', ')}`);\n if (skipped.length > 0) console.log(` • skipped ${skipped.length} (will SSR per request)`);\n\n // Written before `finalize`, so a preset that copies `dist/` into a platform layout takes it along.\n writeBuildMarker(distDir, preset.name);\n\n // Last, so a preset arranging its output finds every piece of the build already written.\n await preset.finalize?.({\n rootDir,\n distDir,\n staticDir: join(distDir, 'static'),\n publicDir: distPublicDir,\n ssgDir,\n });\n\n console.log(` ✓ build complete — ${preset.deployHint}`);\n process.exit(0);\n}\n"]}
|
package/dist/cli/dev.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AA6BjD,UAAU,UAAU;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAwPnE"}
|
package/dist/cli/dev.js
CHANGED
|
@@ -3,9 +3,10 @@ import { rspack } from '@rspack/core';
|
|
|
3
3
|
import { Hono } from 'hono';
|
|
4
4
|
import { proxy } from 'hono/proxy';
|
|
5
5
|
import { mkdir, rm } from 'node:fs/promises';
|
|
6
|
+
import { createServer } from 'node:net';
|
|
6
7
|
import { join } from 'node:path';
|
|
7
8
|
import { Worker } from 'node:worker_threads';
|
|
8
|
-
import { createConfigs } from '../builder/rspack-config.js';
|
|
9
|
+
import { DEV_OUT_DIR, createConfigs } from '../builder/rspack-config.js';
|
|
9
10
|
import { NODE_PRESET } from '../deploy/presets.js';
|
|
10
11
|
import { SERVER_DEFAULTS } from '../server/server-config.js';
|
|
11
12
|
import { createStaticAssetsApp } from '../server/static.js';
|
|
@@ -14,12 +15,34 @@ const WORKER_READY_TIMEOUT_MS = 15_000;
|
|
|
14
15
|
function describe(error) {
|
|
15
16
|
return error instanceof Error ? (error.stack ?? error.message) : String(error);
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether nothing is listening on the port yet — checked before the output directory is emptied.
|
|
20
|
+
*
|
|
21
|
+
* `rshono dev` clears its own output on startup, so a second one started against a running server
|
|
22
|
+
* wipes the directory that server is still importing route chunks from, and only then exits on
|
|
23
|
+
* EADDRINUSE. The first server keeps serving from files that no longer exist, and its watcher never
|
|
24
|
+
* re-emits them — it believes it already wrote them — so it 500s until it is restarted.
|
|
25
|
+
*/
|
|
26
|
+
function portAvailable(port, hostname) {
|
|
27
|
+
const { promise, resolve } = Promise.withResolvers();
|
|
28
|
+
const probe = createServer();
|
|
29
|
+
probe.once('error', () => resolve(false));
|
|
30
|
+
probe.listen(port, hostname, () => probe.close(() => resolve(true)));
|
|
31
|
+
return promise;
|
|
32
|
+
}
|
|
17
33
|
export async function devCommand(options) {
|
|
18
34
|
const { rootDir, config } = options;
|
|
19
35
|
const port = options.port ?? SERVER_DEFAULTS.port;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
36
|
+
// Its own directory, never `dist/`: a `rshono build` in another terminal must not be able to
|
|
37
|
+
// delete the chunks this server is still importing. See DEV_OUT_DIR.
|
|
38
|
+
const outDir = join(rootDir, DEV_OUT_DIR);
|
|
39
|
+
// Before the `rm` below, not at `serve` where the bind actually happens: see {@link portAvailable}.
|
|
40
|
+
if (!(await portAvailable(port, '127.0.0.1'))) {
|
|
41
|
+
console.error(` ✗ port ${port} is already in use`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
await rm(outDir, { recursive: true, force: true });
|
|
45
|
+
await mkdir(join(outDir, 'static'), { recursive: true });
|
|
23
46
|
const encoder = new TextEncoder();
|
|
24
47
|
const sseClients = new Set();
|
|
25
48
|
let clientHash;
|
|
@@ -66,7 +89,7 @@ export async function devCommand(options) {
|
|
|
66
89
|
}
|
|
67
90
|
function spawnWorker() {
|
|
68
91
|
return new Promise((resolve, reject) => {
|
|
69
|
-
const worker = new Worker(join(
|
|
92
|
+
const worker = new Worker(join(outDir, 'server', 'main.mjs'), {
|
|
70
93
|
workerData: { port: 0, hostname: '127.0.0.1' },
|
|
71
94
|
execArgv: ['--enable-source-maps'],
|
|
72
95
|
env: process.env,
|
|
@@ -170,7 +193,7 @@ export async function devCommand(options) {
|
|
|
170
193
|
}
|
|
171
194
|
});
|
|
172
195
|
const front = new Hono();
|
|
173
|
-
front.route('/_static', createStaticAssetsApp({ root: join(
|
|
196
|
+
front.route('/_static', createStaticAssetsApp({ root: join(outDir, 'static'), isDev: true }));
|
|
174
197
|
front.get('/_rshono/hmr', (c) => {
|
|
175
198
|
let ctrl;
|
|
176
199
|
const stream = new ReadableStream({
|
package/dist/cli/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAc,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAEvC,2GAA2G;AAC3G,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjF,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB;IAClD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEtC,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpD,MAAM,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1D,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+C,CAAC;IAC1E,IAAI,UAA8B,CAAC;IAEnC,MAAM,QAAQ,GAAG,CAAC,IAAa,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAExF;;;;OAIG;IACH,SAAS,SAAS,CAAC,KAAiB;QAClC,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,SAAS,CAAC,OAAmB;QACpC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,uBAAuB,GAAG,KAAK,CAAC;IACpC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,GAAG,aAAa,CAAC;QACjD,OAAO;QACP,KAAK,EAAE,IAAI;QACX,MAAM;QACN,iGAAiG;QACjG,kGAAkG;QAClG,MAAM,EAAE,WAAW;QACnB,wBAAwB,EAAE,GAAG,EAAE;YAC7B,uBAAuB,GAAG,IAAI,CAAC;QACjC,CAAC;KACF,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC;IAE5D,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,YAAY,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEpD,SAAS,UAAU;QACjB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAsB,CAAC;QACzE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,SAAS,WAAW;QAClB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE;gBAC7D,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE;gBAC9C,QAAQ,EAAE,CAAC,sBAAsB,CAAC;gBAClC,GAAG,EAAE,OAAO,CAAC,GAA6B;aAC3C,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,6CAA6C,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACpG,CAAC,EAAE,uBAAuB,CAAC,CAAC;YAE5B,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAyC,EAAE,EAAE;gBACnE,IAAI,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAClE,KAAK,GAAG,IAAI,CAAC;oBACb,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC,CAAC,CAAC;YACH,gGAAgG;YAChG,+FAA+F;YAC/F,wEAAwE;YACxE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC3B,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;oBACnD,OAAO;gBACT,CAAC;gBACD,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,IAAI,MAAM,KAAK,aAAa,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBAC3C,OAAO,CAAC,KAAK,CAAC,sCAAsC,IAAI,iCAAiC,CAAC,CAAC;oBAC3F,aAAa,GAAG,IAAI,CAAC;oBACrB,6FAA6F;oBAC7F,wFAAwF;oBACxF,6FAA6F;oBAC7F,4DAA4D;oBAC5D,UAAU,GAAG,UAAU,EAAE,CAAC;oBAC1B,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sCAAsC,IAAI,mDAAmD,EAAE,CAAC,CAAC;gBAC5H,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,EAAE;QACnD,UAAU,GAAG,UAAU,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,EAAE,KAAY,EAAE,EAAE;QAC3E,MAAM,IAAI,GAAG,UAAU,CAAC;QACxB,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAC1C,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC3E,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC/E,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,GAAG,GAAG,aAAa,CAAC;oBAC1B,aAAa,GAAG,IAAI,CAAC;oBACrB,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC;gBACxB,CAAC;gBACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;gBACtD,aAAa,GAAG,MAAM,CAAC;gBACvB,UAAU,GAAG,OAAO,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACd,IAAI,uBAAuB,EAAE,CAAC;oBAC5B,uBAAuB,GAAG,KAAK,CAAC;oBAChC,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;gBAC3D,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,gGAAgG;QAChG,iGAAiG;QACjG,kGAAkG;QAClG,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1C,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,KAAY,EAAE,EAAE;QAC3D,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,UAAU,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;QACrC,IAAI,UAAU;YAAE,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAU,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE;QACpD,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;YACxC,OAAO;QACT,CAAC;QACD,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YACvG,OAAO,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACnF,UAAU,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;IAEzB,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE/F,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;QAC9B,IAAI,IAAiD,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;YAC5C,KAAK,CAAC,UAAU;gBACd,IAAI,GAAG,UAAU,CAAC;gBAClB,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBAC3B,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBACrD,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAuB,CAAC,CAAC,CAAC;YACzF,CAAC;YACD,MAAM;gBACJ,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;SACF,CAAC,CAAC;QACH,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;YAC1B,OAAO,EAAE;gBACP,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,+FAA+F;IAC/F,+DAA+D;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1C,WAAW,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;IAEnD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACzB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAC3C,IAAI,KAAK,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,IAAI,CAAC,oBAAoB,KAAK,IAAI,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,oBAAoB,UAAU,GAAG,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAEtF,kGAAkG;QAClG,+FAA+F;QAC/F,iGAAiG;QACjG,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;YACnC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;YACd,8FAA8F;YAC9F,sFAAsF;YACtF,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE;gBACP,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;gBACjB,8FAA8F;gBAC9F,4FAA4F;gBAC5F,mEAAmE;gBACnE,kBAAkB,EAAE,QAAQ,CAAC,IAAI;gBACjC,mBAAmB,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;aACxD;SACF,CAAC,CAAC;QAEH,iGAAiG;QACjG,kGAAkG;QAClG,8DAA8D;QAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,UAAU,EAAE,EAAE,CAAC;YAClD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QAClE,OAAO,CAAC,GAAG,CAAC,2CAA2C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { serve } from '@hono/node-server';\nimport { rspack, type Stats } from '@rspack/core';\nimport { Hono } from 'hono';\nimport { proxy } from 'hono/proxy';\nimport { mkdir, rm } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { Worker } from 'node:worker_threads';\nimport { createConfigs } from '../builder/rspack-config.js';\nimport type { RshonoConfig } from '../config.js';\nimport { NODE_PRESET } from '../deploy/presets.js';\nimport type { DevMessage } from '../runtime/dev-protocol.js';\nimport { SERVER_DEFAULTS } from '../server/server-config.js';\nimport { createStaticAssetsApp } from '../server/static.js';\n\nconst WORKER_READY_TIMEOUT_MS = 15_000;\n\n/** An error as the dev server shows it in the browser: the stack where there is one, since this is dev. */\nfunction describe(error: unknown): string {\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\ninterface DevOptions {\n rootDir: string;\n port?: number;\n config: RshonoConfig;\n}\n\nexport async function devCommand(options: DevOptions): Promise<void> {\n const { rootDir, config } = options;\n const port = options.port ?? SERVER_DEFAULTS.port;\n const distDir = join(rootDir, 'dist');\n\n await rm(distDir, { recursive: true, force: true });\n await mkdir(join(distDir, 'static'), { recursive: true });\n\n const encoder = new TextEncoder();\n const sseClients = new Set<ReadableStreamDefaultController<Uint8Array>>();\n let clientHash: string | undefined;\n\n const sseChunk = (data: unknown) => encoder.encode(`data: ${JSON.stringify(data)}\\n\\n`);\n\n /**\n * Writes one already-encoded SSE frame to every open client, dropping the ones that have gone away.\n * A browser that navigated or closed leaves a controller whose `enqueue` throws, and `cancel` is not\n * always reached first — so a failed write is what retires a client.\n */\n function sendToAll(chunk: Uint8Array): void {\n for (const controller of sseClients) {\n try {\n controller.enqueue(chunk);\n } catch {\n sseClients.delete(controller);\n }\n }\n }\n\n function broadcast(message: DevMessage): void {\n sendToAll(sseChunk(message));\n }\n\n let serverComponentsChanged = false;\n const [clientConfig, serverConfig] = createConfigs({\n rootDir,\n isDev: true,\n config,\n // Always Node, whatever `deploy` says: the dev server runs the bundle in a worker thread of this\n // process and fronts it on one port. `deploy` is a property of `build` output, not of developing.\n preset: NODE_PRESET,\n onServerComponentChanges: () => {\n serverComponentsChanged = true;\n },\n });\n const compiler = rspack([clientConfig, serverConfig]);\n const [clientCompiler, serverCompiler] = compiler.compilers;\n\n let currentWorker: Worker | null = null;\n let workerPort: number | null = null;\n let workerGate = createGate();\n let restartChain: Promise<void> = Promise.resolve();\n\n function createGate() {\n const { promise, resolve } = Promise.withResolvers<{ error?: string }>();\n return { promise, open: resolve };\n }\n\n function spawnWorker(): Promise<{ worker: Worker; port: number }> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(join(distDir, 'server', 'main.mjs'), {\n workerData: { port: 0, hostname: '127.0.0.1' },\n execArgv: ['--enable-source-maps'],\n env: process.env as Record<string, string>,\n });\n const timeout = setTimeout(() => {\n worker.terminate();\n reject(new Error(`server worker did not become ready within ${WORKER_READY_TIMEOUT_MS / 1000}s`));\n }, WORKER_READY_TIMEOUT_MS);\n\n let ready = false;\n worker.once('message', (message: { type?: string; port?: number }) => {\n if (message?.type === 'ready' && typeof message.port === 'number') {\n ready = true;\n clearTimeout(timeout);\n resolve({ worker, port: message.port });\n }\n });\n // `on`, not `once`: an error *after* the worker is ready has no pending promise left to reject,\n // and a consumed `once` would leave that error with no listener at all — which Node turns into\n // an uncaught exception that takes the dev server down with the worker.\n worker.on('error', (error) => {\n if (ready) {\n console.error(' ✗ server worker crashed:', error);\n return;\n }\n clearTimeout(timeout);\n reject(error);\n });\n worker.on('exit', (code) => {\n if (worker === currentWorker && code !== 0) {\n console.error(` ✗ server worker exited with code ${code} — waiting for the next rebuild`);\n currentWorker = null;\n // Opened with the reason rather than left closed: a request arriving before the next rebuild\n // parks on this gate, and an unopened one would hang the browser with only the terminal\n // saying why. `hooks.invalid` installs a fresh closed gate the moment a file changes, so the\n // next build still holds requests until the worker is back.\n workerGate = createGate();\n workerGate.open({ error: `The server worker exited with code ${code}. See the terminal for the error it crashed with.` });\n }\n });\n });\n }\n\n serverCompiler.hooks.invalid.tap('rshono/gate', () => {\n workerGate = createGate();\n });\n\n serverCompiler.hooks.done.tapPromise('rshono/worker', async (stats: Stats) => {\n const gate = workerGate;\n restartChain = restartChain.then(async () => {\n if (stats.hasErrors()) {\n console.error(stats.toString({ preset: 'errors-warnings', colors: true }));\n gate.open({ error: stats.toString({ preset: 'errors-only', colors: false }) });\n return;\n }\n try {\n if (currentWorker) {\n const old = currentWorker;\n currentWorker = null;\n await old.terminate();\n }\n const { worker, port: newPort } = await spawnWorker();\n currentWorker = worker;\n workerPort = newPort;\n gate.open({});\n if (serverComponentsChanged) {\n serverComponentsChanged = false;\n broadcast({ type: 'rsc-update' });\n }\n } catch (error) {\n console.error(' ✗ failed to start server worker:', error);\n gate.open({ error: describe(error) });\n }\n });\n // No link in this queue may be left rejected: `.then` on a rejected promise short-circuits, and\n // from that point no worker is ever spawned again and no gate is ever opened — a dev server that\n // answers nothing and explains nothing. The `try` above covers the restart; this covers the rest.\n restartChain = restartChain.catch((error) => {\n console.error(' ✗ dev server restart failed:', error);\n gate.open({ error: describe(error) });\n });\n await restartChain;\n });\n\n clientCompiler.hooks.done.tap('rshono/hmr', (stats: Stats) => {\n if (stats.hasErrors()) {\n console.error(stats.toString({ preset: 'errors-warnings', colors: true }));\n return;\n }\n clientHash = stats.hash ?? undefined;\n if (clientHash) broadcast({ type: 'client-built', hash: clientHash });\n });\n\n let firstBuild = true;\n compiler.watch([{}, {}] as never, (err, multiStats) => {\n if (err) {\n console.error(' ✗ build failed:', err);\n return;\n }\n if (multiStats && !multiStats.hasErrors()) {\n const seconds = Math.max(...multiStats.stats.map((s) => (s.endTime ?? 0) - (s.startTime ?? 0))) / 1000;\n console.log(` ${firstBuild ? '✓ built' : '✓ rebuilt'} in ${seconds.toFixed(1)}s`);\n firstBuild = false;\n }\n });\n\n const front = new Hono();\n\n front.route('/_static', createStaticAssetsApp({ root: join(distDir, 'static'), isDev: true }));\n\n front.get('/_rshono/hmr', (c) => {\n let ctrl: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n ctrl = controller;\n sseClients.add(controller);\n controller.enqueue(encoder.encode('retry: 500\\n\\n'));\n controller.enqueue(sseChunk({ type: 'hello', hash: clientHash } satisfies DevMessage));\n },\n cancel() {\n sseClients.delete(ctrl);\n },\n });\n return new Response(stream, {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n });\n });\n\n // An SSE comment, not a message: it keeps an idle connection off a proxy's timeout without the\n // client having to know about a frame type that means nothing.\n const ping = encoder.encode(': ping\\n\\n');\n setInterval(() => sendToAll(ping), 15_000).unref();\n\n front.all('*', async (c) => {\n const { error } = await workerGate.promise;\n if (error || workerPort === null) {\n return c.text(`Build failed:\\n\\n${error ?? 'server not running'}`, 500);\n }\n\n const incoming = new URL(c.req.url);\n const target = `http://127.0.0.1:${workerPort}${incoming.pathname}${incoming.search}`;\n\n // Hono's proxy helper rather than a hand-rolled `fetch`: it carries the method, the streamed body\n // (with the `duplex` Node requires) and the client's abort signal, so a browser that goes away\n // takes the worker's render with it. On the way back it strips the hop-by-hop headers. `headers`\n // replaces the set wholesale, so the request's own are spread back in first.\n const response = await proxy(target, {\n raw: c.req.raw,\n // The worker's redirects are the app's answer to this request, not something to follow here —\n // they have to reach the browser, with the internal address rewritten off them below.\n redirect: 'manual',\n headers: {\n ...c.req.header(),\n // This front-end *is* the proxy the app sits behind, and `trustProxy` is forced on in dev for\n // exactly that reason: without these the app resolves every URL against the worker's random\n // 127.0.0.1 port instead of the address the browser actually used.\n 'x-forwarded-host': incoming.host,\n 'x-forwarded-proto': incoming.protocol.replace(':', ''),\n },\n });\n\n // A redirect to the worker's own address has to become a relative one, or the browser leaves the\n // dev server for a random port only this process knows about. `proxy` hands back a response whose\n // headers are still mutable, so the rewrite happens in place.\n const location = response.headers.get('location');\n const loc = location ? URL.parse(location, target) : null;\n if (loc && loc.host === `127.0.0.1:${workerPort}`) {\n response.headers.set('location', `${loc.pathname}${loc.search}${loc.hash}`);\n }\n return response;\n });\n\n serve({ fetch: front.fetch, port, hostname: '127.0.0.1' }, (info) => {\n console.log(` ➜ rshono dev server: http://localhost:${info.port}`);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAc,MAAM,cAAc,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAEvC,2GAA2G;AAC3G,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,aAAa,CAAC,IAAY,EAAE,QAAgB;IACnD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAW,CAAC;IAC9D,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1C,KAAK,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACrE,OAAO,OAAO,CAAC;AACjB,CAAC;AAQD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAmB;IAClD,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,eAAe,CAAC,IAAI,CAAC;IAClD,6FAA6F;IAC7F,qEAAqE;IACrE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC;IAE1C,oGAAoG;IACpG,IAAI,CAAC,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC,EAAE,CAAC;QAC9C,OAAO,CAAC,KAAK,CAAC,YAAY,IAAI,oBAAoB,CAAC,CAAC;QACpD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;IAClC,MAAM,UAAU,GAAG,IAAI,GAAG,EAA+C,CAAC;IAC1E,IAAI,UAA8B,CAAC;IAEnC,MAAM,QAAQ,GAAG,CAAC,IAAa,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAExF;;;;OAIG;IACH,SAAS,SAAS,CAAC,KAAiB;QAClC,KAAK,MAAM,UAAU,IAAI,UAAU,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;YAAC,MAAM,CAAC;gBACP,UAAU,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;YAChC,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,SAAS,CAAC,OAAmB;QACpC,SAAS,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,uBAAuB,GAAG,KAAK,CAAC;IACpC,MAAM,CAAC,YAAY,EAAE,YAAY,CAAC,GAAG,aAAa,CAAC;QACjD,OAAO;QACP,KAAK,EAAE,IAAI;QACX,MAAM;QACN,iGAAiG;QACjG,kGAAkG;QAClG,MAAM,EAAE,WAAW;QACnB,wBAAwB,EAAE,GAAG,EAAE;YAC7B,uBAAuB,GAAG,IAAI,CAAC;QACjC,CAAC;KACF,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,MAAM,CAAC,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IACtD,MAAM,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC;IAE5D,IAAI,aAAa,GAAkB,IAAI,CAAC;IACxC,IAAI,UAAU,GAAkB,IAAI,CAAC;IACrC,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;IAC9B,IAAI,YAAY,GAAkB,OAAO,CAAC,OAAO,EAAE,CAAC;IAEpD,SAAS,UAAU;QACjB,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,aAAa,EAAsB,CAAC;QACzE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAED,SAAS,WAAW;QAClB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE;gBAC5D,UAAU,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE;gBAC9C,QAAQ,EAAE,CAAC,sBAAsB,CAAC;gBAClC,GAAG,EAAE,OAAO,CAAC,GAA6B;aAC3C,CAAC,CAAC;YACH,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;gBAC9B,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM,CAAC,IAAI,KAAK,CAAC,6CAA6C,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC;YACpG,CAAC,EAAE,uBAAuB,CAAC,CAAC;YAE5B,IAAI,KAAK,GAAG,KAAK,CAAC;YAClB,MAAM,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,OAAyC,EAAE,EAAE;gBACnE,IAAI,OAAO,EAAE,IAAI,KAAK,OAAO,IAAI,OAAO,OAAO,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAClE,KAAK,GAAG,IAAI,CAAC;oBACb,YAAY,CAAC,OAAO,CAAC,CAAC;oBACtB,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;gBAC1C,CAAC;YACH,CAAC,CAAC,CAAC;YACH,gGAAgG;YAChG,+FAA+F;YAC/F,wEAAwE;YACxE,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,EAAE;gBAC3B,IAAI,KAAK,EAAE,CAAC;oBACV,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,KAAK,CAAC,CAAC;oBACnD,OAAO;gBACT,CAAC;gBACD,YAAY,CAAC,OAAO,CAAC,CAAC;gBACtB,MAAM,CAAC,KAAK,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,IAAI,MAAM,KAAK,aAAa,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBAC3C,OAAO,CAAC,KAAK,CAAC,sCAAsC,IAAI,iCAAiC,CAAC,CAAC;oBAC3F,aAAa,GAAG,IAAI,CAAC;oBACrB,6FAA6F;oBAC7F,wFAAwF;oBACxF,6FAA6F;oBAC7F,4DAA4D;oBAC5D,UAAU,GAAG,UAAU,EAAE,CAAC;oBAC1B,UAAU,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,sCAAsC,IAAI,mDAAmD,EAAE,CAAC,CAAC;gBAC5H,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,cAAc,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,GAAG,EAAE;QACnD,UAAU,GAAG,UAAU,EAAE,CAAC;IAC5B,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,EAAE,KAAK,EAAE,KAAY,EAAE,EAAE;QAC3E,MAAM,IAAI,GAAG,UAAU,CAAC;QACxB,YAAY,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;YAC1C,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC3E,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC/E,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,aAAa,EAAE,CAAC;oBAClB,MAAM,GAAG,GAAG,aAAa,CAAC;oBAC1B,aAAa,GAAG,IAAI,CAAC;oBACrB,MAAM,GAAG,CAAC,SAAS,EAAE,CAAC;gBACxB,CAAC;gBACD,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,MAAM,WAAW,EAAE,CAAC;gBACtD,aAAa,GAAG,MAAM,CAAC;gBACvB,UAAU,GAAG,OAAO,CAAC;gBACrB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACd,IAAI,uBAAuB,EAAE,CAAC;oBAC5B,uBAAuB,GAAG,KAAK,CAAC;oBAChC,SAAS,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC,CAAC;gBACpC,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,KAAK,CAAC,CAAC;gBAC3D,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,gGAAgG;QAChG,iGAAiG;QACjG,kGAAkG;QAClG,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YAC1C,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACvD,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,MAAM,YAAY,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,KAAY,EAAE,EAAE;QAC3D,IAAI,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC;YACtB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QACD,UAAU,GAAG,KAAK,CAAC,IAAI,IAAI,SAAS,CAAC;QACrC,IAAI,UAAU;YAAE,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAI,UAAU,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,CAAU,EAAE,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE;QACpD,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC;YACxC,OAAO;QACT,CAAC;QACD,IAAI,UAAU,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,EAAE,CAAC;YAC1C,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;YACvG,OAAO,CAAC,GAAG,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACnF,UAAU,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAG,IAAI,IAAI,EAAE,CAAC;IAEzB,KAAK,CAAC,KAAK,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAE9F,KAAK,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC,EAAE,EAAE;QAC9B,IAAI,IAAiD,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,cAAc,CAAa;YAC5C,KAAK,CAAC,UAAU;gBACd,IAAI,GAAG,UAAU,CAAC;gBAClB,UAAU,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;gBAC3B,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;gBACrD,UAAU,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAuB,CAAC,CAAC,CAAC;YACzF,CAAC;YACD,MAAM;gBACJ,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1B,CAAC;SACF,CAAC,CAAC;QACH,OAAO,IAAI,QAAQ,CAAC,MAAM,EAAE;YAC1B,OAAO,EAAE;gBACP,cAAc,EAAE,mBAAmB;gBACnC,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,YAAY;aACzB;SACF,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,+FAA+F;IAC/F,+DAA+D;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;IAC1C,WAAW,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC;IAEnD,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACzB,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC;QAC3C,IAAI,KAAK,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,IAAI,CAAC,oBAAoB,KAAK,IAAI,oBAAoB,EAAE,EAAE,GAAG,CAAC,CAAC;QAC1E,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,MAAM,GAAG,oBAAoB,UAAU,GAAG,QAAQ,CAAC,QAAQ,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;QAEtF,kGAAkG;QAClG,+FAA+F;QAC/F,iGAAiG;QACjG,6EAA6E;QAC7E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;YACnC,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG;YACd,8FAA8F;YAC9F,sFAAsF;YACtF,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE;gBACP,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,EAAE;gBACjB,8FAA8F;gBAC9F,4FAA4F;gBAC5F,mEAAmE;gBACnE,kBAAkB,EAAE,QAAQ,CAAC,IAAI;gBACjC,mBAAmB,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;aACxD;SACF,CAAC,CAAC;QAEH,iGAAiG;QACjG,kGAAkG;QAClG,8DAA8D;QAC9D,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,UAAU,EAAE,EAAE,CAAC;YAClD,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9E,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;QAClE,OAAO,CAAC,GAAG,CAAC,2CAA2C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import { serve } from '@hono/node-server';\nimport { rspack, type Stats } from '@rspack/core';\nimport { Hono } from 'hono';\nimport { proxy } from 'hono/proxy';\nimport { mkdir, rm } from 'node:fs/promises';\nimport { createServer } from 'node:net';\nimport { join } from 'node:path';\nimport { Worker } from 'node:worker_threads';\nimport { DEV_OUT_DIR, createConfigs } from '../builder/rspack-config.js';\nimport type { RshonoConfig } from '../config.js';\nimport { NODE_PRESET } from '../deploy/presets.js';\nimport type { DevMessage } from '../runtime/dev-protocol.js';\nimport { SERVER_DEFAULTS } from '../server/server-config.js';\nimport { createStaticAssetsApp } from '../server/static.js';\n\nconst WORKER_READY_TIMEOUT_MS = 15_000;\n\n/** An error as the dev server shows it in the browser: the stack where there is one, since this is dev. */\nfunction describe(error: unknown): string {\n return error instanceof Error ? (error.stack ?? error.message) : String(error);\n}\n\n/**\n * Whether nothing is listening on the port yet — checked before the output directory is emptied.\n *\n * `rshono dev` clears its own output on startup, so a second one started against a running server\n * wipes the directory that server is still importing route chunks from, and only then exits on\n * EADDRINUSE. The first server keeps serving from files that no longer exist, and its watcher never\n * re-emits them — it believes it already wrote them — so it 500s until it is restarted.\n */\nfunction portAvailable(port: number, hostname: string): Promise<boolean> {\n const { promise, resolve } = Promise.withResolvers<boolean>();\n const probe = createServer();\n probe.once('error', () => resolve(false));\n probe.listen(port, hostname, () => probe.close(() => resolve(true)));\n return promise;\n}\n\ninterface DevOptions {\n rootDir: string;\n port?: number;\n config: RshonoConfig;\n}\n\nexport async function devCommand(options: DevOptions): Promise<void> {\n const { rootDir, config } = options;\n const port = options.port ?? SERVER_DEFAULTS.port;\n // Its own directory, never `dist/`: a `rshono build` in another terminal must not be able to\n // delete the chunks this server is still importing. See DEV_OUT_DIR.\n const outDir = join(rootDir, DEV_OUT_DIR);\n\n // Before the `rm` below, not at `serve` where the bind actually happens: see {@link portAvailable}.\n if (!(await portAvailable(port, '127.0.0.1'))) {\n console.error(` ✗ port ${port} is already in use`);\n process.exit(1);\n }\n\n await rm(outDir, { recursive: true, force: true });\n await mkdir(join(outDir, 'static'), { recursive: true });\n\n const encoder = new TextEncoder();\n const sseClients = new Set<ReadableStreamDefaultController<Uint8Array>>();\n let clientHash: string | undefined;\n\n const sseChunk = (data: unknown) => encoder.encode(`data: ${JSON.stringify(data)}\\n\\n`);\n\n /**\n * Writes one already-encoded SSE frame to every open client, dropping the ones that have gone away.\n * A browser that navigated or closed leaves a controller whose `enqueue` throws, and `cancel` is not\n * always reached first — so a failed write is what retires a client.\n */\n function sendToAll(chunk: Uint8Array): void {\n for (const controller of sseClients) {\n try {\n controller.enqueue(chunk);\n } catch {\n sseClients.delete(controller);\n }\n }\n }\n\n function broadcast(message: DevMessage): void {\n sendToAll(sseChunk(message));\n }\n\n let serverComponentsChanged = false;\n const [clientConfig, serverConfig] = createConfigs({\n rootDir,\n isDev: true,\n config,\n // Always Node, whatever `deploy` says: the dev server runs the bundle in a worker thread of this\n // process and fronts it on one port. `deploy` is a property of `build` output, not of developing.\n preset: NODE_PRESET,\n onServerComponentChanges: () => {\n serverComponentsChanged = true;\n },\n });\n const compiler = rspack([clientConfig, serverConfig]);\n const [clientCompiler, serverCompiler] = compiler.compilers;\n\n let currentWorker: Worker | null = null;\n let workerPort: number | null = null;\n let workerGate = createGate();\n let restartChain: Promise<void> = Promise.resolve();\n\n function createGate() {\n const { promise, resolve } = Promise.withResolvers<{ error?: string }>();\n return { promise, open: resolve };\n }\n\n function spawnWorker(): Promise<{ worker: Worker; port: number }> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(join(outDir, 'server', 'main.mjs'), {\n workerData: { port: 0, hostname: '127.0.0.1' },\n execArgv: ['--enable-source-maps'],\n env: process.env as Record<string, string>,\n });\n const timeout = setTimeout(() => {\n worker.terminate();\n reject(new Error(`server worker did not become ready within ${WORKER_READY_TIMEOUT_MS / 1000}s`));\n }, WORKER_READY_TIMEOUT_MS);\n\n let ready = false;\n worker.once('message', (message: { type?: string; port?: number }) => {\n if (message?.type === 'ready' && typeof message.port === 'number') {\n ready = true;\n clearTimeout(timeout);\n resolve({ worker, port: message.port });\n }\n });\n // `on`, not `once`: an error *after* the worker is ready has no pending promise left to reject,\n // and a consumed `once` would leave that error with no listener at all — which Node turns into\n // an uncaught exception that takes the dev server down with the worker.\n worker.on('error', (error) => {\n if (ready) {\n console.error(' ✗ server worker crashed:', error);\n return;\n }\n clearTimeout(timeout);\n reject(error);\n });\n worker.on('exit', (code) => {\n if (worker === currentWorker && code !== 0) {\n console.error(` ✗ server worker exited with code ${code} — waiting for the next rebuild`);\n currentWorker = null;\n // Opened with the reason rather than left closed: a request arriving before the next rebuild\n // parks on this gate, and an unopened one would hang the browser with only the terminal\n // saying why. `hooks.invalid` installs a fresh closed gate the moment a file changes, so the\n // next build still holds requests until the worker is back.\n workerGate = createGate();\n workerGate.open({ error: `The server worker exited with code ${code}. See the terminal for the error it crashed with.` });\n }\n });\n });\n }\n\n serverCompiler.hooks.invalid.tap('rshono/gate', () => {\n workerGate = createGate();\n });\n\n serverCompiler.hooks.done.tapPromise('rshono/worker', async (stats: Stats) => {\n const gate = workerGate;\n restartChain = restartChain.then(async () => {\n if (stats.hasErrors()) {\n console.error(stats.toString({ preset: 'errors-warnings', colors: true }));\n gate.open({ error: stats.toString({ preset: 'errors-only', colors: false }) });\n return;\n }\n try {\n if (currentWorker) {\n const old = currentWorker;\n currentWorker = null;\n await old.terminate();\n }\n const { worker, port: newPort } = await spawnWorker();\n currentWorker = worker;\n workerPort = newPort;\n gate.open({});\n if (serverComponentsChanged) {\n serverComponentsChanged = false;\n broadcast({ type: 'rsc-update' });\n }\n } catch (error) {\n console.error(' ✗ failed to start server worker:', error);\n gate.open({ error: describe(error) });\n }\n });\n // No link in this queue may be left rejected: `.then` on a rejected promise short-circuits, and\n // from that point no worker is ever spawned again and no gate is ever opened — a dev server that\n // answers nothing and explains nothing. The `try` above covers the restart; this covers the rest.\n restartChain = restartChain.catch((error) => {\n console.error(' ✗ dev server restart failed:', error);\n gate.open({ error: describe(error) });\n });\n await restartChain;\n });\n\n clientCompiler.hooks.done.tap('rshono/hmr', (stats: Stats) => {\n if (stats.hasErrors()) {\n console.error(stats.toString({ preset: 'errors-warnings', colors: true }));\n return;\n }\n clientHash = stats.hash ?? undefined;\n if (clientHash) broadcast({ type: 'client-built', hash: clientHash });\n });\n\n let firstBuild = true;\n compiler.watch([{}, {}] as never, (err, multiStats) => {\n if (err) {\n console.error(' ✗ build failed:', err);\n return;\n }\n if (multiStats && !multiStats.hasErrors()) {\n const seconds = Math.max(...multiStats.stats.map((s) => (s.endTime ?? 0) - (s.startTime ?? 0))) / 1000;\n console.log(` ${firstBuild ? '✓ built' : '✓ rebuilt'} in ${seconds.toFixed(1)}s`);\n firstBuild = false;\n }\n });\n\n const front = new Hono();\n\n front.route('/_static', createStaticAssetsApp({ root: join(outDir, 'static'), isDev: true }));\n\n front.get('/_rshono/hmr', (c) => {\n let ctrl: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n ctrl = controller;\n sseClients.add(controller);\n controller.enqueue(encoder.encode('retry: 500\\n\\n'));\n controller.enqueue(sseChunk({ type: 'hello', hash: clientHash } satisfies DevMessage));\n },\n cancel() {\n sseClients.delete(ctrl);\n },\n });\n return new Response(stream, {\n headers: {\n 'content-type': 'text/event-stream',\n 'cache-control': 'no-cache',\n connection: 'keep-alive',\n },\n });\n });\n\n // An SSE comment, not a message: it keeps an idle connection off a proxy's timeout without the\n // client having to know about a frame type that means nothing.\n const ping = encoder.encode(': ping\\n\\n');\n setInterval(() => sendToAll(ping), 15_000).unref();\n\n front.all('*', async (c) => {\n const { error } = await workerGate.promise;\n if (error || workerPort === null) {\n return c.text(`Build failed:\\n\\n${error ?? 'server not running'}`, 500);\n }\n\n const incoming = new URL(c.req.url);\n const target = `http://127.0.0.1:${workerPort}${incoming.pathname}${incoming.search}`;\n\n // Hono's proxy helper rather than a hand-rolled `fetch`: it carries the method, the streamed body\n // (with the `duplex` Node requires) and the client's abort signal, so a browser that goes away\n // takes the worker's render with it. On the way back it strips the hop-by-hop headers. `headers`\n // replaces the set wholesale, so the request's own are spread back in first.\n const response = await proxy(target, {\n raw: c.req.raw,\n // The worker's redirects are the app's answer to this request, not something to follow here —\n // they have to reach the browser, with the internal address rewritten off them below.\n redirect: 'manual',\n headers: {\n ...c.req.header(),\n // This front-end *is* the proxy the app sits behind, and `trustProxy` is forced on in dev for\n // exactly that reason: without these the app resolves every URL against the worker's random\n // 127.0.0.1 port instead of the address the browser actually used.\n 'x-forwarded-host': incoming.host,\n 'x-forwarded-proto': incoming.protocol.replace(':', ''),\n },\n });\n\n // A redirect to the worker's own address has to become a relative one, or the browser leaves the\n // dev server for a random port only this process knows about. `proxy` hands back a response whose\n // headers are still mutable, so the rewrite happens in place.\n const location = response.headers.get('location');\n const loc = location ? URL.parse(location, target) : null;\n if (loc && loc.host === `127.0.0.1:${workerPort}`) {\n response.headers.set('location', `${loc.pathname}${loc.search}${loc.hash}`);\n }\n return response;\n });\n\n serve({ fetch: front.fetch, port, hostname: '127.0.0.1' }, (info) => {\n console.log(` ➜ rshono dev server: http://localhost:${info.port}`);\n });\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAqBnD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAiB7D,CAAC"}
|
|
@@ -3,10 +3,11 @@ import { join } from 'node:path';
|
|
|
3
3
|
import { loadEnvFiles } from '../server/load-env.js';
|
|
4
4
|
import { readPrerendered } from '../server/ssg.js';
|
|
5
5
|
import { createPublicFallback, createStaticAssetsApp } from '../server/static.js';
|
|
6
|
-
const isDev = __RSHONO_CONFIG__
|
|
6
|
+
const { isDev, outDir } = __RSHONO_CONFIG__;
|
|
7
7
|
/**
|
|
8
8
|
* The project root, derived from where the bundle ended up: this module is compiled into
|
|
9
|
-
* `<root>/
|
|
9
|
+
* `<root>/<outDir>/server/main.mjs`, so `import.meta.dirname` is `<root>/<outDir>/server` at
|
|
10
|
+
* runtime — which is why every output directory sits exactly one level under the root.
|
|
10
11
|
*
|
|
11
12
|
* Derived rather than baked in at build time, because an absolute build-time path would tie the
|
|
12
13
|
* output to the machine that produced it — and building in CI to run somewhere else is the normal
|
|
@@ -14,10 +15,10 @@ const isDev = __RSHONO_CONFIG__.isDev;
|
|
|
14
15
|
* for exactly this reason.
|
|
15
16
|
*/
|
|
16
17
|
const rootDir = join(import.meta.dirname, '..', '..');
|
|
17
|
-
const staticDir = join(rootDir,
|
|
18
|
-
const ssgDir = join(rootDir,
|
|
19
|
-
/** `public/` is copied into
|
|
20
|
-
const publicDir = isDev ? join(rootDir, 'public') : join(rootDir,
|
|
18
|
+
const staticDir = join(rootDir, outDir, 'static');
|
|
19
|
+
const ssgDir = join(rootDir, outDir, 'ssg');
|
|
20
|
+
/** `public/` is copied into the build output, so a deployed build is self-contained; dev reads the source. */
|
|
21
|
+
const publicDir = isDev ? join(rootDir, 'public') : join(rootDir, outDir, 'public');
|
|
21
22
|
/**
|
|
22
23
|
* Everything a deploy target with a real filesystem does the same way.
|
|
23
24
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGlF,MAAM,KAAK,GAAG,iBAAiB,CAAC
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGlF,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAAC;AAE5C;;;;;;;;;GASG;AACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAClD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAC5C,8GAA8G;AAC9G,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAoC;IAChE,iBAAiB,CAAC,GAAS;QACzB,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,mBAAmB,CAAC,GAAS;QAC3B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO;QACnC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,eAAe,CAAC,CAAC,EAAE,OAAO;QACxB,OAAO,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,OAAO;QACL,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;CACF,CAAC","sourcesContent":["import type { Hono } from 'hono';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { loadEnvFiles } from '../server/load-env.js';\nimport { readPrerendered } from '../server/ssg.js';\nimport { createPublicFallback, createStaticAssetsApp } from '../server/static.js';\nimport type { DeployRuntime } from './contract.js';\n\nconst { isDev, outDir } = __RSHONO_CONFIG__;\n\n/**\n * The project root, derived from where the bundle ended up: this module is compiled into\n * `<root>/<outDir>/server/main.mjs`, so `import.meta.dirname` is `<root>/<outDir>/server` at\n * runtime — which is why every output directory sits exactly one level under the root.\n *\n * Derived rather than baked in at build time, because an absolute build-time path would tie the\n * output to the machine that produced it — and building in CI to run somewhere else is the normal\n * case. A preset that relocates the bundle keeps `dist/server/main.mjs` intact inside its own layout\n * for exactly this reason.\n */\nconst rootDir = join(import.meta.dirname, '..', '..');\n\nconst staticDir = join(rootDir, outDir, 'static');\nconst ssgDir = join(rootDir, outDir, 'ssg');\n/** `public/` is copied into the build output, so a deployed build is self-contained; dev reads the source. */\nconst publicDir = isDev ? join(rootDir, 'public') : join(rootDir, outDir, 'public');\n\n/**\n * Everything a deploy target with a real filesystem does the same way.\n *\n * Node and the serverless runtimes that unpack a bundle onto a read-only disk (Vercel, AWS Lambda)\n * differ only in how the finished app is handed over — so each of those presets is this object plus\n * its own {@link DeployRuntime.serveApp}, and the implementations live once, in `server/`.\n */\nexport const fileSystemRuntime: Omit<DeployRuntime, 'serveApp'> = {\n mountStaticAssets(app: Hono): void {\n app.route('/_static', createStaticAssetsApp({ root: staticDir, isDev }));\n },\n\n mountPublicFallback(app: Hono): void {\n if (!existsSync(publicDir)) return;\n app.on(['GET', 'HEAD'], '/*', createPublicFallback({ root: publicDir, isDev }));\n },\n\n readPrerendered(c, variant) {\n return readPrerendered(ssgDir, c.req.path, variant);\n },\n\n loadEnv(): void {\n loadEnvFiles(rootDir);\n },\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.client.d.ts","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entry.client.d.ts","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":"AAoBA,OAAO,CAAC,MAAM,CAAC;IACb,6FAA6F;IAC7F,IAAI,aAAa,EAAE,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,GAAG,SAAS,CAAC;CAC3D"}
|
|
@@ -3,6 +3,9 @@ import React from 'react';
|
|
|
3
3
|
import { hydrateRoot } from 'react-dom/client';
|
|
4
4
|
import { createFromFetch, createFromReadableStream, createTemporaryReferenceSet, encodeReply, setServerCallback, } from 'react-server-dom-rspack/client.browser';
|
|
5
5
|
import { isControlDigest, parseRedirectDigest } from './control.js';
|
|
6
|
+
// Dev-only, and reached only from inside an `import.meta.webpackHot` branch — which a production
|
|
7
|
+
// build compiles to `false`, leaving this module unreferenced and dropped.
|
|
8
|
+
import { walkHotUpdates } from './hot-update.js';
|
|
6
9
|
import { RouterContext } from './navigation.js';
|
|
7
10
|
import { createRscRequest } from './request.js';
|
|
8
11
|
const isDev = process.env.NODE_ENV === 'development';
|
|
@@ -431,53 +434,58 @@ function listenNavigation(onNavigation) {
|
|
|
431
434
|
* guarded by import.meta.webpackHot). Listens to the CLI's SSE endpoint:
|
|
432
435
|
*
|
|
433
436
|
* client-built → hot-apply the waiting updates (react-refresh keeps
|
|
434
|
-
* component state);
|
|
437
|
+
* component state); anything the page can't be patched
|
|
438
|
+
* up to falls back to a reload — see walkHotUpdates.
|
|
435
439
|
* rsc-update → server component code changed: re-fetch the flight
|
|
436
440
|
* payload for the current URL, state preserved.
|
|
437
441
|
* hello → sent on (re)connect with the latest build hash; a
|
|
438
442
|
* mismatch means events were missed — resync.
|
|
439
443
|
*/
|
|
440
444
|
function initDevRefresh(fetchRscPayload) {
|
|
445
|
+
const hot = import.meta.webpackHot;
|
|
441
446
|
let connectedOnce = false;
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return;
|
|
449
|
-
}
|
|
450
|
-
try {
|
|
451
|
-
await hot.check(true);
|
|
452
|
-
if (hash !== __webpack_hash__)
|
|
453
|
-
await applyClientUpdate(hash);
|
|
454
|
-
}
|
|
455
|
-
catch (error) {
|
|
456
|
-
console.warn('[rshono] hot update failed, reloading:', error);
|
|
457
|
-
window.location.reload();
|
|
458
|
-
}
|
|
447
|
+
/** The newest build the dev server has announced — what {@link applyClientUpdate} walks towards. */
|
|
448
|
+
let targetHash;
|
|
449
|
+
/** Gives up on patching the page and takes the whole document from the dev server instead. */
|
|
450
|
+
function reload(reason, error) {
|
|
451
|
+
console.warn(`[rshono] ${reason} — reloading`, ...(error === undefined ? [] : [error]));
|
|
452
|
+
window.location.reload();
|
|
459
453
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
454
|
+
async function applyClientUpdate() {
|
|
455
|
+
const giveUp = await walkHotUpdates(hot, () => __webpack_hash__, () => targetHash);
|
|
456
|
+
if (giveUp)
|
|
457
|
+
reload(giveUp.reason, giveUp.error);
|
|
458
|
+
}
|
|
459
|
+
async function handle(message) {
|
|
463
460
|
switch (message.type) {
|
|
464
461
|
case 'hello':
|
|
462
|
+
targetHash = message.hash ?? targetHash;
|
|
465
463
|
if (connectedOnce) {
|
|
466
|
-
|
|
467
|
-
await applyClientUpdate(message.hash);
|
|
464
|
+
await applyClientUpdate();
|
|
468
465
|
await fetchRscPayload().catch(() => window.location.reload());
|
|
469
466
|
}
|
|
470
467
|
connectedOnce = true;
|
|
471
468
|
break;
|
|
472
469
|
case 'client-built':
|
|
473
|
-
|
|
474
|
-
|
|
470
|
+
targetHash = message.hash;
|
|
471
|
+
await applyClientUpdate();
|
|
475
472
|
break;
|
|
476
473
|
case 'rsc-update':
|
|
477
474
|
console.log('[rshono] server components updated');
|
|
478
475
|
await fetchRscPayload().catch(() => window.location.reload());
|
|
479
476
|
break;
|
|
480
477
|
}
|
|
478
|
+
}
|
|
479
|
+
const source = new EventSource('/_rshono/hmr');
|
|
480
|
+
// Chained rather than handled as they arrive: a burst of saves puts several frames on the wire
|
|
481
|
+
// inside the time one `hot.check` takes, and two of those overlapping is an error webpack throws
|
|
482
|
+
// on ("check() is only allowed in idle status") — which would turn every burst into a full reload.
|
|
483
|
+
// Nothing is dropped by queueing, because `targetHash` is shared: whichever handler runs next
|
|
484
|
+
// walks to the newest build rather than to the one its own frame named.
|
|
485
|
+
let queue = Promise.resolve();
|
|
486
|
+
source.onmessage = (event) => {
|
|
487
|
+
const message = JSON.parse(event.data);
|
|
488
|
+
queue = queue.then(() => handle(message)).catch((error) => reload('the dev client failed', error));
|
|
481
489
|
};
|
|
482
490
|
}
|
|
483
491
|
// Bootstrap failures (a truncated or malformed initial flight payload, most likely) would otherwise
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry.client.js","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { hydrateRoot } from 'react-dom/client';\nimport {\n createFromFetch,\n createFromReadableStream,\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\nimport { isControlDigest, parseRedirectDigest } from './control.js';\nimport type { DevMessage } from './dev-protocol.js';\nimport type { RscPayload } from './entry.rsc.js';\nimport { RouterContext, type NavigationRouter } from './navigation.js';\nimport { createRscRequest } from './request.js';\n\nconst isDev = process.env.NODE_ENV === 'development';\n\ndeclare global {\n /** The array the payload `<script>` tags `flight-inject.ts` emits push their chunks into. */\n var __FLIGHT_DATA: Array<string | Uint8Array> | undefined;\n}\n\n/** The flight payload the document carried, read back out of `__FLIGHT_DATA` — see `flight-inject.ts`, which writes it. */\nfunction readFlightPayload(): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n // Assigned synchronously by `start`, which `new ReadableStream` runs before it returns.\n let controller!: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (c) => void (controller = c),\n });\n const enqueue = (chunk: string | Uint8Array) => controller.enqueue(typeof chunk === 'string' ? encoder.encode(chunk) : chunk);\n\n // Payload scripts interleave with the document, so some have already run by the time this module\n // is evaluated — those are in the array — and the rest run after it, arriving through `push`.\n const data = (self.__FLIGHT_DATA ??= []);\n for (const chunk of data) enqueue(chunk);\n data.push = enqueue as typeof data.push;\n\n // The last payload script lands before the document finishes parsing, so that is what says there\n // is no more of it to come.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => controller.close(), { once: true });\n } else {\n controller.close();\n }\n return stream;\n}\n\n/** Created at module evaluation, not inside `main()`, so no chunk can be pushed before it is watching. */\nconst flightStream = readFlightPayload();\n\n/**\n * Guarantees somewhere to attach the fatal overlay. React's root container is the whole `document`,\n * so by the time an uncaught error has torn the tree down, `<body>` — or even `<html>` — may be gone.\n */\nfunction overlayHost(): HTMLElement {\n if (!document.documentElement) document.appendChild(document.createElement('html'));\n if (!document.body) document.documentElement.appendChild(document.createElement('body'));\n return document.body;\n}\n\n/**\n * Replaces the white screen of death with something readable.\n *\n * Because the root container is `document`, an uncaught render error leaves a genuinely blank page\n * with the reason only in the console — so this paints the reason over it instead. In development\n * that's the full stack; in production it's a generic notice plus a reload button, since the tree is\n * unrecoverable and reloading is the only way forward.\n *\n * Written with DOM calls rather than React (the renderer is what just failed) and `textContent`\n * rather than `innerHTML` (an error message is untrusted input).\n */\nfunction showFatal(error: unknown, componentStack?: string | null): void {\n // Queued rather than run inline: React's teardown happens after this callback returns, and would\n // remove a node appended synchronously along with the rest of the tree.\n setTimeout(() => {\n const host = overlayHost();\n host.querySelector('[data-rshono-fatal]')?.remove();\n\n const box = document.createElement('div');\n box.setAttribute('data-rshono-fatal', '');\n box.setAttribute('role', 'alert'); // the page is gone; announce it rather than leaving silence\n box.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;overflow:auto;padding:1.5rem;background:#18181b;color:#f4f4f5;' +\n 'font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:left';\n\n const title = document.createElement('div');\n title.textContent = isDev ? 'Unhandled error' : 'Something went wrong';\n title.style.cssText = 'font-size:1.0625rem;font-weight:700;color:#f87171;margin:0 0 0.75rem';\n box.appendChild(title);\n\n if (isDev) {\n const detail = document.createElement('pre');\n detail.style.cssText = 'margin:0;white-space:pre-wrap;word-break:break-word';\n detail.textContent =\n (error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error)) +\n (componentStack ? `\\n\\nComponent stack:${componentStack}` : '');\n box.appendChild(detail);\n } else {\n const message = document.createElement('p');\n message.textContent = 'This page hit an unexpected error and can’t continue.';\n message.style.cssText = 'margin:0 0 1rem;color:#d4d4d8';\n box.appendChild(message);\n }\n\n const reload = document.createElement('button');\n reload.textContent = 'Reload page';\n reload.style.cssText =\n 'margin-top:1.25rem;padding:0.5rem 1rem;font:inherit;color:#18181b;background:#f4f4f5;border:0;border-radius:4px;cursor:pointer';\n reload.addEventListener('click', () => window.location.reload());\n box.appendChild(reload);\n\n host.appendChild(box);\n }, 0);\n}\n\n/**\n * Asks a URL for its flight payload.\n *\n * Deliberately uncached: every navigation fetches at the moment it is asked for, so a payload can\n * never be staler than the click that wanted it, and the browser's own HTTP cache is what makes a\n * repeat visit cheap.\n */\nfunction requestPayload(href: string): Promise<RscPayload> {\n return createFromFetch<RscPayload>(fetch(createRscRequest(new URL(href, location.href).href)));\n}\n\nasync function main() {\n const cspMeta = document.querySelector('meta[property=\"csp-nonce\"]') as HTMLMetaElement | null;\n if (cspMeta?.nonce) __webpack_nonce__ = cspMeta.nonce;\n\n // Both are replaced by BrowserRoot's own on mount. The defaults matter: `setServerCallback` is\n // registered before hydration, so an action or refresh firing in that window would otherwise call\n // an unassigned binding. Until there's a root to update, a full reload is the honest fallback.\n let setPayload: (v: RscPayload) => void = () => {\n window.location.reload();\n };\n // Runs work inside the nav transition so useNavigation().pending stays true across the round-trip.\n let startNav: (run: () => void | Promise<void>) => void = (run) => {\n void run();\n };\n\n const initialPayload = await createFromReadableStream<RscPayload>(flightStream);\n\n function push(href: string) {\n const target = new URL(href, window.location.href);\n if (target.origin !== window.location.origin) {\n window.location.assign(target.href);\n return;\n }\n window.history.pushState(null, '', target.href);\n }\n\n function replace(href: string) {\n const target = new URL(href, window.location.href);\n if (target.origin !== window.location.origin) {\n window.location.replace(target.href);\n return;\n }\n window.history.replaceState(null, '', target.href);\n }\n\n // A refresh keeps the URL, so it can't ride the history patch like push/replace — it drives the\n // flight re-fetch directly.\n const refresh = () =>\n startNav(async () => {\n try {\n await fetchRscPayload();\n } catch {\n window.location.reload();\n }\n });\n\n /**\n * Turns a control-signal digest — how `redirect()` / `notFound()` reach the browser — into a real\n * navigation. Returns false for anything else, so callers can fall through to their own handling.\n *\n * `hard` forces a full document load, for signals that surfaced *through React* (a nested\n * component's redirect, reported via the root error handlers). React unmounts the root on an\n * uncaught error, so there is no live tree left to soft-navigate with. A signal caught earlier —\n * a top-level payload rejection — still swaps the payload in place.\n */\n function handleControlDigest(error: unknown, { hard = false }: { hard?: boolean } = {}): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n if (!isControlDigest(digest)) return false;\n const redirect = parseRedirectDigest(digest);\n if (!redirect) {\n window.location.reload();\n } else if (hard) {\n window.location.assign(new URL(redirect.location, window.location.href).href);\n } else {\n push(redirect.location);\n }\n return true;\n }\n\n async function fetchRscPayload() {\n let payload: RscPayload;\n try {\n payload = await requestPayload(window.location.href);\n } catch (error) {\n if (handleControlDigest(error)) return;\n throw error;\n }\n if (payload.redirect) return push(payload.redirect);\n setPayload(payload);\n }\n\n function BrowserRoot() {\n const [payload, setPayloadState] = React.useState(initialPayload);\n const [pending, startTransition] = React.useTransition();\n // The scroll a fetched navigation still owes, held until its payload is on screen.\n const pendingScroll = React.useRef<(() => void) | null>(null);\n\n React.useEffect(() => {\n setPayload = (v) => setPayloadState(v);\n startNav = (run) => startTransition(run);\n }, [startTransition]);\n\n /**\n * Scrolls where the navigation asked, once React has put its payload in the DOM.\n *\n * This has to wait for the commit rather than the fetch: a `#hash` target does not exist until the\n * new tree does, and until then the page a scroll would move is still the outgoing one. A layout\n * effect runs before the browser paints, so the pre-scroll position is never on screen.\n */\n React.useLayoutEffect(() => {\n const scroll = pendingScroll.current;\n pendingScroll.current = null;\n scroll?.();\n }, [payload]);\n\n React.useEffect(() => {\n const stopNavigating = listenNavigation((afterRender) =>\n startNav(async () => {\n try {\n await fetchRscPayload();\n pendingScroll.current = afterRender;\n } catch {\n window.location.reload();\n }\n }),\n );\n const stopUpgradingLinks = listenLinks();\n return () => {\n stopUpgradingLinks();\n stopNavigating();\n };\n }, []);\n\n const router = React.useMemo<NavigationRouter>(() => ({ push, replace, refresh, pending }), [pending]);\n\n return <RouterContext.Provider value={router}>{payload.root}</RouterContext.Provider>;\n }\n\n setServerCallback(async (id, args) => {\n const temporaryReferences = createTemporaryReferenceSet();\n const request = createRscRequest(window.location.href, {\n id,\n body: await encodeReply(args, { temporaryReferences }),\n });\n let payload: RscPayload;\n try {\n payload = await createFromFetch<RscPayload>(fetch(request), { temporaryReferences });\n } catch (error) {\n if (handleControlDigest(error)) return undefined;\n throw error;\n }\n if (payload.redirect) {\n push(payload.redirect);\n return undefined;\n }\n React.startTransition(() => setPayload(payload));\n if (payload.notFound) return undefined;\n const result = payload.returnValue!;\n if (!result.ok) throw result.error;\n return result.value;\n });\n\n // A `redirect()` / `notFound()` from a component *below* the page root reaches us through React: it\n // rides the flight payload as an error at that component's position, and boundaries re-throw it\n // (see boundaries.tsx) so it lands here rather than rendering an error fallback.\n //\n // Installing these hooks opts out of React's own defaults, so anything that isn't a control signal\n // has to be put back by hand: console for a caught error, `reportError` (i.e. window.onerror, so\n // error-reporting tools still see it) for an uncaught one.\n hydrateRoot(document, <BrowserRoot />, {\n formState: initialPayload.formState,\n onCaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // A boundary handled this and the tree is intact, so no overlay: whatever fallback the app\n // chose is the right thing to have on screen.\n console.error(error, errorInfo.componentStack ?? '');\n },\n onUncaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // Nothing caught it, so React tears the root down — and the root is `document`. This is the\n // white screen; paint the reason over it.\n globalThis.reportError(error);\n showFatal(error, errorInfo.componentStack);\n },\n });\n\n if (import.meta.webpackHot) {\n initDevRefresh(fetchRscPayload);\n }\n}\n\ntype NavigationType = 'push' | 'replace' | 'pop';\n\n/**\n * Runs teardown in reverse and empties the list, so a second call is a no-op. Collecting these as\n * setup goes keeps each undo next to the thing it undoes.\n */\nfunction disposeAll(undo: Array<() => void>): void {\n for (const dispose of undo.splice(0).reverse()) dispose();\n}\n\n// An `<a>` we intercept for soft navigation: same-origin, same tab, not a download,\n// and not explicitly opted out with `data-native` (which forces a full browser navigation).\nfunction isRouterLink(link: HTMLAnchorElement): boolean {\n return (\n !!link.href &&\n (!link.target || link.target === '_self') &&\n link.origin === location.origin &&\n !link.hasAttribute('download') &&\n !link.hasAttribute('data-native')\n );\n}\n\n/**\n * Upgrades the app's anchors: a plain left-click becomes a soft navigation.\n *\n * Kept apart from `listenNavigation` because the two share no state — a click here only calls\n * `history.pushState`, which is where that function picks the navigation up.\n */\nfunction listenLinks(): () => void {\n const undo: Array<() => void> = [];\n\n function onClick(e: MouseEvent) {\n const link = (e.target as Element).closest('a');\n if (\n link &&\n link instanceof HTMLAnchorElement &&\n isRouterLink(link) &&\n e.button === 0 &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.shiftKey &&\n !e.defaultPrevented\n ) {\n if (link.hash && link.pathname === location.pathname && link.search === location.search) return;\n e.preventDefault();\n history.pushState(null, '', link.href);\n }\n }\n document.addEventListener('click', onClick);\n undo.push(() => document.removeEventListener('click', onClick));\n\n return () => disposeAll(undo);\n}\n\n/**\n * The element the current `#fragment` names, if it is on the page.\n *\n * A fragment is percent-encoded and an `id` attribute is not, so it has to be decoded first. A\n * hand-written URL can carry a `%` that is not an escape, which throws — take the fragment literally\n * then, since that is the closest thing to an id it could have meant.\n */\nfunction fragmentTarget(): HTMLElement | null {\n const fragment = location.hash.slice(1);\n if (!fragment) return null;\n let id = fragment;\n try {\n id = decodeURIComponent(fragment);\n } catch {}\n return document.getElementById(id);\n}\n\nfunction listenNavigation(onNavigation: (afterRender: () => void) => void): () => void {\n const undo: Array<() => void> = [];\n\n // Scroll restoration is the browser's. `auto` is set explicitly rather than left at the default,\n // because it is a statement: the browser remembers a traversal's offset for us, and nothing here\n // tracks one.\n const prevRestoration = window.history.scrollRestoration;\n try {\n window.history.scrollRestoration = 'auto';\n } catch {}\n undo.push(() => {\n try {\n window.history.scrollRestoration = prevRestoration;\n } catch {}\n });\n\n /**\n * A push is not a real navigation to the browser, so nothing resets the scroll offset — without\n * this a click through to a new page lands wherever the last one was scrolled to. A `#hash` names\n * where to land instead, and one naming nothing on the page falls back to the top, as a browser\n * does. `replace` keeps its position deliberately, and a traversal is the browser's to restore.\n *\n * `scrollIntoView` rather than `scrollTo`, because it is the algorithm a browser's own fragment jump\n * uses — so `scroll-padding-top` still applies. Neither call passes a `behavior`, leaving\n * `scroll-behavior: smooth` the app's to ask for.\n *\n * The caller decides *when* this runs; for a navigation that fetched a payload it has to be after\n * the commit — see the layout effect in `BrowserRoot`.\n */\n const afterRenderFor = (type: NavigationType) => () => {\n if (type !== 'push') return;\n const target = fragmentTarget();\n if (target) target.scrollIntoView();\n else window.scrollTo(0, 0);\n };\n\n const documentUrl = () => location.pathname + location.search;\n\n // What the payload on screen was rendered for. Only the document part: the server never sees the\n // fragment, so two URLs differing by one render identically.\n let renderedUrl = documentUrl();\n\n /**\n * A navigation that moves only the fragment — `#a` → `#b`, or back out of a same-page anchor —\n * leaves the document unchanged, so the payload already on screen is the right one. Fetching\n * another would be a wasted round-trip that re-renders the page out from under the jump.\n *\n * `router.refresh()` is unaffected: it drives the re-fetch directly rather than through here, and\n * remains the way to ask for fresh data at an unchanged URL.\n */\n const notify = (type: NavigationType) => {\n const afterRender = afterRenderFor(type);\n if (documentUrl() === renderedUrl) {\n afterRender();\n return;\n }\n renderedUrl = documentUrl();\n onNavigation(afterRender);\n };\n\n const onPopState = () => notify('pop');\n window.addEventListener('popstate', onPopState);\n undo.push(() => window.removeEventListener('popstate', onPopState));\n\n const oldPushState = window.history.pushState;\n window.history.pushState = function (state, unused, url) {\n const res = oldPushState.call(this, state, unused, url as string);\n notify('push');\n return res;\n };\n undo.push(() => {\n window.history.pushState = oldPushState;\n });\n\n const oldReplaceState = window.history.replaceState;\n window.history.replaceState = function (state, unused, url) {\n const res = oldReplaceState.call(this, state, unused, url as string);\n notify('replace');\n return res;\n };\n undo.push(() => {\n window.history.replaceState = oldReplaceState;\n });\n\n return () => disposeAll(undo);\n}\n\n/**\n * Dev-only refresh client (stripped from prod bundles: the whole call is\n * guarded by import.meta.webpackHot). Listens to the CLI's SSE endpoint:\n *\n * client-built → hot-apply the waiting updates (react-refresh keeps\n * component state); any failure falls back to reload.\n * rsc-update → server component code changed: re-fetch the flight\n * payload for the current URL, state preserved.\n * hello → sent on (re)connect with the latest build hash; a\n * mismatch means events were missed — resync.\n */\nfunction initDevRefresh(fetchRscPayload: () => Promise<void>) {\n let connectedOnce = false;\n\n async function applyClientUpdate(hash: string) {\n const hot = import.meta.webpackHot!;\n if (hash === __webpack_hash__) return;\n if (hot.status() !== 'idle') {\n window.location.reload();\n return;\n }\n try {\n await hot.check(true);\n if (hash !== __webpack_hash__) await applyClientUpdate(hash);\n } catch (error) {\n console.warn('[rshono] hot update failed, reloading:', error);\n window.location.reload();\n }\n }\n\n const source = new EventSource('/_rshono/hmr');\n source.onmessage = async (event) => {\n const message = JSON.parse(event.data) as DevMessage;\n switch (message.type) {\n case 'hello':\n if (connectedOnce) {\n if (message.hash && message.hash !== __webpack_hash__) await applyClientUpdate(message.hash);\n await fetchRscPayload().catch(() => window.location.reload());\n }\n connectedOnce = true;\n break;\n case 'client-built':\n if (message.hash) await applyClientUpdate(message.hash);\n break;\n case 'rsc-update':\n console.log('[rshono] server components updated');\n await fetchRscPayload().catch(() => window.location.reload());\n break;\n }\n };\n}\n\n// Bootstrap failures (a truncated or malformed initial flight payload, most likely) would otherwise\n// be an unhandled rejection: nothing hydrates, nothing is reported, and the page just sits there.\nmain().catch((error) => {\n console.error('[rshono] the client runtime failed to start:', error);\n showFatal(error);\n});\n"]}
|
|
1
|
+
{"version":3,"file":"entry.client.js","sourceRoot":"","sources":["../../src/runtime/entry.client.tsx"],"names":[],"mappings":"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","sourcesContent":["import React from 'react';\nimport { hydrateRoot } from 'react-dom/client';\nimport {\n createFromFetch,\n createFromReadableStream,\n createTemporaryReferenceSet,\n encodeReply,\n setServerCallback,\n} from 'react-server-dom-rspack/client.browser';\nimport { isControlDigest, parseRedirectDigest } from './control.js';\nimport type { DevMessage } from './dev-protocol.js';\nimport type { RscPayload } from './entry.rsc.js';\n// Dev-only, and reached only from inside an `import.meta.webpackHot` branch — which a production\n// build compiles to `false`, leaving this module unreferenced and dropped.\nimport { walkHotUpdates } from './hot-update.js';\nimport { RouterContext, type NavigationRouter } from './navigation.js';\nimport { createRscRequest } from './request.js';\n\nconst isDev = process.env.NODE_ENV === 'development';\n\ndeclare global {\n /** The array the payload `<script>` tags `flight-inject.ts` emits push their chunks into. */\n var __FLIGHT_DATA: Array<string | Uint8Array> | undefined;\n}\n\n/** The flight payload the document carried, read back out of `__FLIGHT_DATA` — see `flight-inject.ts`, which writes it. */\nfunction readFlightPayload(): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n // Assigned synchronously by `start`, which `new ReadableStream` runs before it returns.\n let controller!: ReadableStreamDefaultController<Uint8Array>;\n const stream = new ReadableStream<Uint8Array>({\n start: (c) => void (controller = c),\n });\n const enqueue = (chunk: string | Uint8Array) => controller.enqueue(typeof chunk === 'string' ? encoder.encode(chunk) : chunk);\n\n // Payload scripts interleave with the document, so some have already run by the time this module\n // is evaluated — those are in the array — and the rest run after it, arriving through `push`.\n const data = (self.__FLIGHT_DATA ??= []);\n for (const chunk of data) enqueue(chunk);\n data.push = enqueue as typeof data.push;\n\n // The last payload script lands before the document finishes parsing, so that is what says there\n // is no more of it to come.\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', () => controller.close(), { once: true });\n } else {\n controller.close();\n }\n return stream;\n}\n\n/** Created at module evaluation, not inside `main()`, so no chunk can be pushed before it is watching. */\nconst flightStream = readFlightPayload();\n\n/**\n * Guarantees somewhere to attach the fatal overlay. React's root container is the whole `document`,\n * so by the time an uncaught error has torn the tree down, `<body>` — or even `<html>` — may be gone.\n */\nfunction overlayHost(): HTMLElement {\n if (!document.documentElement) document.appendChild(document.createElement('html'));\n if (!document.body) document.documentElement.appendChild(document.createElement('body'));\n return document.body;\n}\n\n/**\n * Replaces the white screen of death with something readable.\n *\n * Because the root container is `document`, an uncaught render error leaves a genuinely blank page\n * with the reason only in the console — so this paints the reason over it instead. In development\n * that's the full stack; in production it's a generic notice plus a reload button, since the tree is\n * unrecoverable and reloading is the only way forward.\n *\n * Written with DOM calls rather than React (the renderer is what just failed) and `textContent`\n * rather than `innerHTML` (an error message is untrusted input).\n */\nfunction showFatal(error: unknown, componentStack?: string | null): void {\n // Queued rather than run inline: React's teardown happens after this callback returns, and would\n // remove a node appended synchronously along with the rest of the tree.\n setTimeout(() => {\n const host = overlayHost();\n host.querySelector('[data-rshono-fatal]')?.remove();\n\n const box = document.createElement('div');\n box.setAttribute('data-rshono-fatal', '');\n box.setAttribute('role', 'alert'); // the page is gone; announce it rather than leaving silence\n box.style.cssText =\n 'position:fixed;inset:0;z-index:2147483647;overflow:auto;padding:1.5rem;background:#18181b;color:#f4f4f5;' +\n 'font:14px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;text-align:left';\n\n const title = document.createElement('div');\n title.textContent = isDev ? 'Unhandled error' : 'Something went wrong';\n title.style.cssText = 'font-size:1.0625rem;font-weight:700;color:#f87171;margin:0 0 0.75rem';\n box.appendChild(title);\n\n if (isDev) {\n const detail = document.createElement('pre');\n detail.style.cssText = 'margin:0;white-space:pre-wrap;word-break:break-word';\n detail.textContent =\n (error instanceof Error ? (error.stack ?? `${error.name}: ${error.message}`) : String(error)) +\n (componentStack ? `\\n\\nComponent stack:${componentStack}` : '');\n box.appendChild(detail);\n } else {\n const message = document.createElement('p');\n message.textContent = 'This page hit an unexpected error and can’t continue.';\n message.style.cssText = 'margin:0 0 1rem;color:#d4d4d8';\n box.appendChild(message);\n }\n\n const reload = document.createElement('button');\n reload.textContent = 'Reload page';\n reload.style.cssText =\n 'margin-top:1.25rem;padding:0.5rem 1rem;font:inherit;color:#18181b;background:#f4f4f5;border:0;border-radius:4px;cursor:pointer';\n reload.addEventListener('click', () => window.location.reload());\n box.appendChild(reload);\n\n host.appendChild(box);\n }, 0);\n}\n\n/**\n * Asks a URL for its flight payload.\n *\n * Deliberately uncached: every navigation fetches at the moment it is asked for, so a payload can\n * never be staler than the click that wanted it, and the browser's own HTTP cache is what makes a\n * repeat visit cheap.\n */\nfunction requestPayload(href: string): Promise<RscPayload> {\n return createFromFetch<RscPayload>(fetch(createRscRequest(new URL(href, location.href).href)));\n}\n\nasync function main() {\n const cspMeta = document.querySelector('meta[property=\"csp-nonce\"]') as HTMLMetaElement | null;\n if (cspMeta?.nonce) __webpack_nonce__ = cspMeta.nonce;\n\n // Both are replaced by BrowserRoot's own on mount. The defaults matter: `setServerCallback` is\n // registered before hydration, so an action or refresh firing in that window would otherwise call\n // an unassigned binding. Until there's a root to update, a full reload is the honest fallback.\n let setPayload: (v: RscPayload) => void = () => {\n window.location.reload();\n };\n // Runs work inside the nav transition so useNavigation().pending stays true across the round-trip.\n let startNav: (run: () => void | Promise<void>) => void = (run) => {\n void run();\n };\n\n const initialPayload = await createFromReadableStream<RscPayload>(flightStream);\n\n function push(href: string) {\n const target = new URL(href, window.location.href);\n if (target.origin !== window.location.origin) {\n window.location.assign(target.href);\n return;\n }\n window.history.pushState(null, '', target.href);\n }\n\n function replace(href: string) {\n const target = new URL(href, window.location.href);\n if (target.origin !== window.location.origin) {\n window.location.replace(target.href);\n return;\n }\n window.history.replaceState(null, '', target.href);\n }\n\n // A refresh keeps the URL, so it can't ride the history patch like push/replace — it drives the\n // flight re-fetch directly.\n const refresh = () =>\n startNav(async () => {\n try {\n await fetchRscPayload();\n } catch {\n window.location.reload();\n }\n });\n\n /**\n * Turns a control-signal digest — how `redirect()` / `notFound()` reach the browser — into a real\n * navigation. Returns false for anything else, so callers can fall through to their own handling.\n *\n * `hard` forces a full document load, for signals that surfaced *through React* (a nested\n * component's redirect, reported via the root error handlers). React unmounts the root on an\n * uncaught error, so there is no live tree left to soft-navigate with. A signal caught earlier —\n * a top-level payload rejection — still swaps the payload in place.\n */\n function handleControlDigest(error: unknown, { hard = false }: { hard?: boolean } = {}): boolean {\n const digest = (error as { digest?: unknown } | null)?.digest;\n if (!isControlDigest(digest)) return false;\n const redirect = parseRedirectDigest(digest);\n if (!redirect) {\n window.location.reload();\n } else if (hard) {\n window.location.assign(new URL(redirect.location, window.location.href).href);\n } else {\n push(redirect.location);\n }\n return true;\n }\n\n async function fetchRscPayload() {\n let payload: RscPayload;\n try {\n payload = await requestPayload(window.location.href);\n } catch (error) {\n if (handleControlDigest(error)) return;\n throw error;\n }\n if (payload.redirect) return push(payload.redirect);\n setPayload(payload);\n }\n\n function BrowserRoot() {\n const [payload, setPayloadState] = React.useState(initialPayload);\n const [pending, startTransition] = React.useTransition();\n // The scroll a fetched navigation still owes, held until its payload is on screen.\n const pendingScroll = React.useRef<(() => void) | null>(null);\n\n React.useEffect(() => {\n setPayload = (v) => setPayloadState(v);\n startNav = (run) => startTransition(run);\n }, [startTransition]);\n\n /**\n * Scrolls where the navigation asked, once React has put its payload in the DOM.\n *\n * This has to wait for the commit rather than the fetch: a `#hash` target does not exist until the\n * new tree does, and until then the page a scroll would move is still the outgoing one. A layout\n * effect runs before the browser paints, so the pre-scroll position is never on screen.\n */\n React.useLayoutEffect(() => {\n const scroll = pendingScroll.current;\n pendingScroll.current = null;\n scroll?.();\n }, [payload]);\n\n React.useEffect(() => {\n const stopNavigating = listenNavigation((afterRender) =>\n startNav(async () => {\n try {\n await fetchRscPayload();\n pendingScroll.current = afterRender;\n } catch {\n window.location.reload();\n }\n }),\n );\n const stopUpgradingLinks = listenLinks();\n return () => {\n stopUpgradingLinks();\n stopNavigating();\n };\n }, []);\n\n const router = React.useMemo<NavigationRouter>(() => ({ push, replace, refresh, pending }), [pending]);\n\n return <RouterContext.Provider value={router}>{payload.root}</RouterContext.Provider>;\n }\n\n setServerCallback(async (id, args) => {\n const temporaryReferences = createTemporaryReferenceSet();\n const request = createRscRequest(window.location.href, {\n id,\n body: await encodeReply(args, { temporaryReferences }),\n });\n let payload: RscPayload;\n try {\n payload = await createFromFetch<RscPayload>(fetch(request), { temporaryReferences });\n } catch (error) {\n if (handleControlDigest(error)) return undefined;\n throw error;\n }\n if (payload.redirect) {\n push(payload.redirect);\n return undefined;\n }\n React.startTransition(() => setPayload(payload));\n if (payload.notFound) return undefined;\n const result = payload.returnValue!;\n if (!result.ok) throw result.error;\n return result.value;\n });\n\n // A `redirect()` / `notFound()` from a component *below* the page root reaches us through React: it\n // rides the flight payload as an error at that component's position, and boundaries re-throw it\n // (see boundaries.tsx) so it lands here rather than rendering an error fallback.\n //\n // Installing these hooks opts out of React's own defaults, so anything that isn't a control signal\n // has to be put back by hand: console for a caught error, `reportError` (i.e. window.onerror, so\n // error-reporting tools still see it) for an uncaught one.\n hydrateRoot(document, <BrowserRoot />, {\n formState: initialPayload.formState,\n onCaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // A boundary handled this and the tree is intact, so no overlay: whatever fallback the app\n // chose is the right thing to have on screen.\n console.error(error, errorInfo.componentStack ?? '');\n },\n onUncaughtError: (error, errorInfo) => {\n if (handleControlDigest(error, { hard: true })) return;\n // Nothing caught it, so React tears the root down — and the root is `document`. This is the\n // white screen; paint the reason over it.\n globalThis.reportError(error);\n showFatal(error, errorInfo.componentStack);\n },\n });\n\n if (import.meta.webpackHot) {\n initDevRefresh(fetchRscPayload);\n }\n}\n\ntype NavigationType = 'push' | 'replace' | 'pop';\n\n/**\n * Runs teardown in reverse and empties the list, so a second call is a no-op. Collecting these as\n * setup goes keeps each undo next to the thing it undoes.\n */\nfunction disposeAll(undo: Array<() => void>): void {\n for (const dispose of undo.splice(0).reverse()) dispose();\n}\n\n// An `<a>` we intercept for soft navigation: same-origin, same tab, not a download,\n// and not explicitly opted out with `data-native` (which forces a full browser navigation).\nfunction isRouterLink(link: HTMLAnchorElement): boolean {\n return (\n !!link.href &&\n (!link.target || link.target === '_self') &&\n link.origin === location.origin &&\n !link.hasAttribute('download') &&\n !link.hasAttribute('data-native')\n );\n}\n\n/**\n * Upgrades the app's anchors: a plain left-click becomes a soft navigation.\n *\n * Kept apart from `listenNavigation` because the two share no state — a click here only calls\n * `history.pushState`, which is where that function picks the navigation up.\n */\nfunction listenLinks(): () => void {\n const undo: Array<() => void> = [];\n\n function onClick(e: MouseEvent) {\n const link = (e.target as Element).closest('a');\n if (\n link &&\n link instanceof HTMLAnchorElement &&\n isRouterLink(link) &&\n e.button === 0 &&\n !e.metaKey &&\n !e.ctrlKey &&\n !e.altKey &&\n !e.shiftKey &&\n !e.defaultPrevented\n ) {\n if (link.hash && link.pathname === location.pathname && link.search === location.search) return;\n e.preventDefault();\n history.pushState(null, '', link.href);\n }\n }\n document.addEventListener('click', onClick);\n undo.push(() => document.removeEventListener('click', onClick));\n\n return () => disposeAll(undo);\n}\n\n/**\n * The element the current `#fragment` names, if it is on the page.\n *\n * A fragment is percent-encoded and an `id` attribute is not, so it has to be decoded first. A\n * hand-written URL can carry a `%` that is not an escape, which throws — take the fragment literally\n * then, since that is the closest thing to an id it could have meant.\n */\nfunction fragmentTarget(): HTMLElement | null {\n const fragment = location.hash.slice(1);\n if (!fragment) return null;\n let id = fragment;\n try {\n id = decodeURIComponent(fragment);\n } catch {}\n return document.getElementById(id);\n}\n\nfunction listenNavigation(onNavigation: (afterRender: () => void) => void): () => void {\n const undo: Array<() => void> = [];\n\n // Scroll restoration is the browser's. `auto` is set explicitly rather than left at the default,\n // because it is a statement: the browser remembers a traversal's offset for us, and nothing here\n // tracks one.\n const prevRestoration = window.history.scrollRestoration;\n try {\n window.history.scrollRestoration = 'auto';\n } catch {}\n undo.push(() => {\n try {\n window.history.scrollRestoration = prevRestoration;\n } catch {}\n });\n\n /**\n * A push is not a real navigation to the browser, so nothing resets the scroll offset — without\n * this a click through to a new page lands wherever the last one was scrolled to. A `#hash` names\n * where to land instead, and one naming nothing on the page falls back to the top, as a browser\n * does. `replace` keeps its position deliberately, and a traversal is the browser's to restore.\n *\n * `scrollIntoView` rather than `scrollTo`, because it is the algorithm a browser's own fragment jump\n * uses — so `scroll-padding-top` still applies. Neither call passes a `behavior`, leaving\n * `scroll-behavior: smooth` the app's to ask for.\n *\n * The caller decides *when* this runs; for a navigation that fetched a payload it has to be after\n * the commit — see the layout effect in `BrowserRoot`.\n */\n const afterRenderFor = (type: NavigationType) => () => {\n if (type !== 'push') return;\n const target = fragmentTarget();\n if (target) target.scrollIntoView();\n else window.scrollTo(0, 0);\n };\n\n const documentUrl = () => location.pathname + location.search;\n\n // What the payload on screen was rendered for. Only the document part: the server never sees the\n // fragment, so two URLs differing by one render identically.\n let renderedUrl = documentUrl();\n\n /**\n * A navigation that moves only the fragment — `#a` → `#b`, or back out of a same-page anchor —\n * leaves the document unchanged, so the payload already on screen is the right one. Fetching\n * another would be a wasted round-trip that re-renders the page out from under the jump.\n *\n * `router.refresh()` is unaffected: it drives the re-fetch directly rather than through here, and\n * remains the way to ask for fresh data at an unchanged URL.\n */\n const notify = (type: NavigationType) => {\n const afterRender = afterRenderFor(type);\n if (documentUrl() === renderedUrl) {\n afterRender();\n return;\n }\n renderedUrl = documentUrl();\n onNavigation(afterRender);\n };\n\n const onPopState = () => notify('pop');\n window.addEventListener('popstate', onPopState);\n undo.push(() => window.removeEventListener('popstate', onPopState));\n\n const oldPushState = window.history.pushState;\n window.history.pushState = function (state, unused, url) {\n const res = oldPushState.call(this, state, unused, url as string);\n notify('push');\n return res;\n };\n undo.push(() => {\n window.history.pushState = oldPushState;\n });\n\n const oldReplaceState = window.history.replaceState;\n window.history.replaceState = function (state, unused, url) {\n const res = oldReplaceState.call(this, state, unused, url as string);\n notify('replace');\n return res;\n };\n undo.push(() => {\n window.history.replaceState = oldReplaceState;\n });\n\n return () => disposeAll(undo);\n}\n\n/**\n * Dev-only refresh client (stripped from prod bundles: the whole call is\n * guarded by import.meta.webpackHot). Listens to the CLI's SSE endpoint:\n *\n * client-built → hot-apply the waiting updates (react-refresh keeps\n * component state); anything the page can't be patched\n * up to falls back to a reload — see walkHotUpdates.\n * rsc-update → server component code changed: re-fetch the flight\n * payload for the current URL, state preserved.\n * hello → sent on (re)connect with the latest build hash; a\n * mismatch means events were missed — resync.\n */\nfunction initDevRefresh(fetchRscPayload: () => Promise<void>) {\n const hot = import.meta.webpackHot!;\n let connectedOnce = false;\n /** The newest build the dev server has announced — what {@link applyClientUpdate} walks towards. */\n let targetHash: string | undefined;\n\n /** Gives up on patching the page and takes the whole document from the dev server instead. */\n function reload(reason: string, error?: unknown): void {\n console.warn(`[rshono] ${reason} — reloading`, ...(error === undefined ? [] : [error]));\n window.location.reload();\n }\n\n async function applyClientUpdate(): Promise<void> {\n const giveUp = await walkHotUpdates(\n hot,\n () => __webpack_hash__,\n () => targetHash,\n );\n if (giveUp) reload(giveUp.reason, giveUp.error);\n }\n\n async function handle(message: DevMessage): Promise<void> {\n switch (message.type) {\n case 'hello':\n targetHash = message.hash ?? targetHash;\n if (connectedOnce) {\n await applyClientUpdate();\n await fetchRscPayload().catch(() => window.location.reload());\n }\n connectedOnce = true;\n break;\n case 'client-built':\n targetHash = message.hash;\n await applyClientUpdate();\n break;\n case 'rsc-update':\n console.log('[rshono] server components updated');\n await fetchRscPayload().catch(() => window.location.reload());\n break;\n }\n }\n\n const source = new EventSource('/_rshono/hmr');\n // Chained rather than handled as they arrive: a burst of saves puts several frames on the wire\n // inside the time one `hot.check` takes, and two of those overlapping is an error webpack throws\n // on (\"check() is only allowed in idle status\") — which would turn every burst into a full reload.\n // Nothing is dropped by queueing, because `targetHash` is shared: whichever handler runs next\n // walks to the newest build rather than to the one its own frame named.\n let queue: Promise<void> = Promise.resolve();\n source.onmessage = (event) => {\n const message = JSON.parse(event.data) as DevMessage;\n queue = queue.then(() => handle(message)).catch((error) => reload('the dev client failed', error));\n };\n}\n\n// Bootstrap failures (a truncated or malformed initial flight payload, most likely) would otherwise\n// be an unhandled rejection: nothing hydrates, nothing is reported, and the page just sits there.\nmain().catch((error) => {\n console.error('[rshono] the client runtime failed to start:', error);\n showFatal(error);\n});\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walking the page from the build it is running to the build the dev server has announced.
|
|
3
|
+
*
|
|
4
|
+
* Its own module, apart from `entry.client.tsx`, because this is the one piece of the dev client
|
|
5
|
+
* with enough decisions in it to be worth testing on its own — and every one of those decisions is
|
|
6
|
+
* about *giving up correctly*. Dev-only: the sole caller sits behind `import.meta.webpackHot`, which
|
|
7
|
+
* a production build replaces with `false`, so nothing here reaches a production bundle.
|
|
8
|
+
*/
|
|
9
|
+
/** The slice of `import.meta.webpackHot` the walk uses. */
|
|
10
|
+
export interface HotRuntime {
|
|
11
|
+
/**
|
|
12
|
+
* Fetches the update manifest for the build the page is running and, with `autoApply`, applies it.
|
|
13
|
+
*
|
|
14
|
+
* Resolves with the updated module ids — or with **null**, which is the case that has to be
|
|
15
|
+
* handled: the manifest 404s, meaning no build followed this one on disk, and the runtime treats
|
|
16
|
+
* that as "nothing to do" rather than an error. Rejects only when an update was found and could
|
|
17
|
+
* not be applied.
|
|
18
|
+
*/
|
|
19
|
+
check(autoApply?: boolean): Promise<Array<string | number> | null>;
|
|
20
|
+
status(): string;
|
|
21
|
+
}
|
|
22
|
+
/** Why the page has to be reloaded rather than patched — `error` only where one was thrown. */
|
|
23
|
+
export interface ReloadReason {
|
|
24
|
+
reason: string;
|
|
25
|
+
error?: unknown;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Advances the page to `targetHash()`, applying one build's worth of updates per round, and reports
|
|
29
|
+
* whether it got there.
|
|
30
|
+
*
|
|
31
|
+
* Both hashes are read through functions rather than passed by value because both move underneath
|
|
32
|
+
* this loop: `currentHash` is the bundler's own (`__webpack_hash__`, which an applied update
|
|
33
|
+
* rewrites), and `targetHash` is the newest build the dev server has announced, which a save landing
|
|
34
|
+
* mid-walk moves further out. Reading them fresh each round is what lets one walk absorb a burst of
|
|
35
|
+
* saves instead of finishing against a target that is already stale.
|
|
36
|
+
*
|
|
37
|
+
* Returns `null` once the page is on the target build, or the reason it cannot get there — every one
|
|
38
|
+
* of which is a reload, because the alternative is a page that silently stops updating:
|
|
39
|
+
*
|
|
40
|
+
* - **An update was already in flight.** `check` may only be called from `idle`.
|
|
41
|
+
* - **`check` rejected.** An update was found and could not be applied — a module that declines
|
|
42
|
+
* updates, most often, which is the ordinary cost of changing something react-refresh can't patch.
|
|
43
|
+
* - **`check` resolved with null, or applied without moving the hash.** The chain of
|
|
44
|
+
* `*.hot-update.json` files leading to the target is broken: the manifest for the build this page
|
|
45
|
+
* is on 404s, which the runtime reports as "no update available" rather than as an error. The
|
|
46
|
+
* everyday way to get there is restarting the dev server — its first act is to wipe `dist`, so
|
|
47
|
+
* every update file an already-open tab could ask for is gone. The hash cannot move from there, so
|
|
48
|
+
* this is the round that must not be retried: without it the walk re-requests the same 404 for as
|
|
49
|
+
* long as the tab stays open, and the page never picks up another change.
|
|
50
|
+
*/
|
|
51
|
+
export declare function walkHotUpdates(hot: HotRuntime, currentHash: () => string, targetHash: () => string | undefined): Promise<ReloadReason | null>;
|
|
52
|
+
//# sourceMappingURL=hot-update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hot-update.d.ts","sourceRoot":"","sources":["../../src/runtime/hot-update.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2DAA2D;AAC3D,MAAM,WAAW,UAAU;IACzB;;;;;;;OAOG;IACH,KAAK,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IACnE,MAAM,IAAI,MAAM,CAAC;CAClB;AAED,+FAA+F;AAC/F,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,MAAM,EAAE,UAAU,EAAE,MAAM,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAanJ"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Walking the page from the build it is running to the build the dev server has announced.
|
|
3
|
+
*
|
|
4
|
+
* Its own module, apart from `entry.client.tsx`, because this is the one piece of the dev client
|
|
5
|
+
* with enough decisions in it to be worth testing on its own — and every one of those decisions is
|
|
6
|
+
* about *giving up correctly*. Dev-only: the sole caller sits behind `import.meta.webpackHot`, which
|
|
7
|
+
* a production build replaces with `false`, so nothing here reaches a production bundle.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Advances the page to `targetHash()`, applying one build's worth of updates per round, and reports
|
|
11
|
+
* whether it got there.
|
|
12
|
+
*
|
|
13
|
+
* Both hashes are read through functions rather than passed by value because both move underneath
|
|
14
|
+
* this loop: `currentHash` is the bundler's own (`__webpack_hash__`, which an applied update
|
|
15
|
+
* rewrites), and `targetHash` is the newest build the dev server has announced, which a save landing
|
|
16
|
+
* mid-walk moves further out. Reading them fresh each round is what lets one walk absorb a burst of
|
|
17
|
+
* saves instead of finishing against a target that is already stale.
|
|
18
|
+
*
|
|
19
|
+
* Returns `null` once the page is on the target build, or the reason it cannot get there — every one
|
|
20
|
+
* of which is a reload, because the alternative is a page that silently stops updating:
|
|
21
|
+
*
|
|
22
|
+
* - **An update was already in flight.** `check` may only be called from `idle`.
|
|
23
|
+
* - **`check` rejected.** An update was found and could not be applied — a module that declines
|
|
24
|
+
* updates, most often, which is the ordinary cost of changing something react-refresh can't patch.
|
|
25
|
+
* - **`check` resolved with null, or applied without moving the hash.** The chain of
|
|
26
|
+
* `*.hot-update.json` files leading to the target is broken: the manifest for the build this page
|
|
27
|
+
* is on 404s, which the runtime reports as "no update available" rather than as an error. The
|
|
28
|
+
* everyday way to get there is restarting the dev server — its first act is to wipe `dist`, so
|
|
29
|
+
* every update file an already-open tab could ask for is gone. The hash cannot move from there, so
|
|
30
|
+
* this is the round that must not be retried: without it the walk re-requests the same 404 for as
|
|
31
|
+
* long as the tab stays open, and the page never picks up another change.
|
|
32
|
+
*/
|
|
33
|
+
export async function walkHotUpdates(hot, currentHash, targetHash) {
|
|
34
|
+
while (targetHash() !== undefined && targetHash() !== currentHash()) {
|
|
35
|
+
if (hot.status() !== 'idle')
|
|
36
|
+
return { reason: 'a hot update was already in flight' };
|
|
37
|
+
const before = currentHash();
|
|
38
|
+
let applied;
|
|
39
|
+
try {
|
|
40
|
+
applied = await hot.check(true);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
return { reason: 'a hot update failed to apply', error };
|
|
44
|
+
}
|
|
45
|
+
if (applied === null || currentHash() === before)
|
|
46
|
+
return { reason: 'this build cannot be applied on top of the page' };
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=hot-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hot-update.js","sourceRoot":"","sources":["../../src/runtime/hot-update.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAsBH;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,GAAe,EAAE,WAAyB,EAAE,UAAoC;IACnH,OAAO,UAAU,EAAE,KAAK,SAAS,IAAI,UAAU,EAAE,KAAK,WAAW,EAAE,EAAE,CAAC;QACpE,IAAI,GAAG,CAAC,MAAM,EAAE,KAAK,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;QACrF,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC;QAC7B,IAAI,OAAsC,CAAC;QAC3C,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,EAAE,MAAM,EAAE,8BAA8B,EAAE,KAAK,EAAE,CAAC;QAC3D,CAAC;QACD,IAAI,OAAO,KAAK,IAAI,IAAI,WAAW,EAAE,KAAK,MAAM;YAAE,OAAO,EAAE,MAAM,EAAE,iDAAiD,EAAE,CAAC;IACzH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/**\n * Walking the page from the build it is running to the build the dev server has announced.\n *\n * Its own module, apart from `entry.client.tsx`, because this is the one piece of the dev client\n * with enough decisions in it to be worth testing on its own — and every one of those decisions is\n * about *giving up correctly*. Dev-only: the sole caller sits behind `import.meta.webpackHot`, which\n * a production build replaces with `false`, so nothing here reaches a production bundle.\n */\n\n/** The slice of `import.meta.webpackHot` the walk uses. */\nexport interface HotRuntime {\n /**\n * Fetches the update manifest for the build the page is running and, with `autoApply`, applies it.\n *\n * Resolves with the updated module ids — or with **null**, which is the case that has to be\n * handled: the manifest 404s, meaning no build followed this one on disk, and the runtime treats\n * that as \"nothing to do\" rather than an error. Rejects only when an update was found and could\n * not be applied.\n */\n check(autoApply?: boolean): Promise<Array<string | number> | null>;\n status(): string;\n}\n\n/** Why the page has to be reloaded rather than patched — `error` only where one was thrown. */\nexport interface ReloadReason {\n reason: string;\n error?: unknown;\n}\n\n/**\n * Advances the page to `targetHash()`, applying one build's worth of updates per round, and reports\n * whether it got there.\n *\n * Both hashes are read through functions rather than passed by value because both move underneath\n * this loop: `currentHash` is the bundler's own (`__webpack_hash__`, which an applied update\n * rewrites), and `targetHash` is the newest build the dev server has announced, which a save landing\n * mid-walk moves further out. Reading them fresh each round is what lets one walk absorb a burst of\n * saves instead of finishing against a target that is already stale.\n *\n * Returns `null` once the page is on the target build, or the reason it cannot get there — every one\n * of which is a reload, because the alternative is a page that silently stops updating:\n *\n * - **An update was already in flight.** `check` may only be called from `idle`.\n * - **`check` rejected.** An update was found and could not be applied — a module that declines\n * updates, most often, which is the ordinary cost of changing something react-refresh can't patch.\n * - **`check` resolved with null, or applied without moving the hash.** The chain of\n * `*.hot-update.json` files leading to the target is broken: the manifest for the build this page\n * is on 404s, which the runtime reports as \"no update available\" rather than as an error. The\n * everyday way to get there is restarting the dev server — its first act is to wipe `dist`, so\n * every update file an already-open tab could ask for is gone. The hash cannot move from there, so\n * this is the round that must not be retried: without it the walk re-requests the same 404 for as\n * long as the tab stays open, and the page never picks up another change.\n */\nexport async function walkHotUpdates(hot: HotRuntime, currentHash: () => string, targetHash: () => string | undefined): Promise<ReloadReason | null> {\n while (targetHash() !== undefined && targetHash() !== currentHash()) {\n if (hot.status() !== 'idle') return { reason: 'a hot update was already in flight' };\n const before = currentHash();\n let applied: Array<string | number> | null;\n try {\n applied = await hot.check(true);\n } catch (error) {\n return { reason: 'a hot update failed to apply', error };\n }\n if (applied === null || currentHash() === before) return { reason: 'this build cannot be applied on top of the page' };\n }\n return null;\n}\n"]}
|
|
@@ -6,10 +6,9 @@ import type { RshonoConfig } from '../config.js';
|
|
|
6
6
|
* and compiled into the server bundle as the `__RSHONO_CONFIG__` literal (see
|
|
7
7
|
* `builder/rspack-config.ts`) — there is no runtime env-var interface for these.
|
|
8
8
|
*
|
|
9
|
-
* Only
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* per environment instead of once per bundle.
|
|
9
|
+
* Only what the *build* decides. The per-request security controls that used to live alongside these
|
|
10
|
+
* — the CSRF check, the CSP, the body cap — are Hono middleware an app registers in `src/server.ts`,
|
|
11
|
+
* where they can be configured per route and per environment instead of once per bundle.
|
|
13
12
|
*/
|
|
14
13
|
export interface ServerConfig {
|
|
15
14
|
/**
|
|
@@ -21,6 +20,14 @@ export interface ServerConfig {
|
|
|
21
20
|
isDev: boolean;
|
|
22
21
|
/** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */
|
|
23
22
|
trustProxy: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* The output directory this bundle was written to, relative to the project root — `dist` for a
|
|
25
|
+
* build, something of its own for `rshono dev` (see `BUILD_OUT_DIR` / `DEV_OUT_DIR`).
|
|
26
|
+
*
|
|
27
|
+
* Carried into the bundle because `deploy/filesystem.ts` locates the static assets and the
|
|
28
|
+
* prerendered pages beside it at runtime, and only the compiler knows which directory it used.
|
|
29
|
+
*/
|
|
30
|
+
outDir: string;
|
|
24
31
|
}
|
|
25
32
|
/**
|
|
26
33
|
* The framework's built-in defaults.
|
|
@@ -40,7 +47,8 @@ export declare const SERVER_DEFAULTS: {
|
|
|
40
47
|
* shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
|
|
41
48
|
* is the only way in (it sets the forwarded headers itself and binds to localhost).
|
|
42
49
|
*/
|
|
43
|
-
export declare function resolveServerConfig(config: RshonoConfig, { isDev }: {
|
|
50
|
+
export declare function resolveServerConfig(config: RshonoConfig, { isDev, outDir }: {
|
|
44
51
|
isDev: boolean;
|
|
52
|
+
outDir: string;
|
|
45
53
|
}): ServerConfig;
|
|
46
54
|
//# sourceMappingURL=server-config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD
|
|
1
|
+
{"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,OAAO,CAAC;IACf,oGAAoG;IACpG,UAAU,EAAE,OAAO,CAAC;IACpB;;;;;;OAMG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;aAC1B,IAAI,EAAE,IAAI;aACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAM7H"}
|
|
@@ -16,10 +16,11 @@ export const SERVER_DEFAULTS = {
|
|
|
16
16
|
* shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy
|
|
17
17
|
* is the only way in (it sets the forwarded headers itself and binds to localhost).
|
|
18
18
|
*/
|
|
19
|
-
export function resolveServerConfig(config, { isDev }) {
|
|
19
|
+
export function resolveServerConfig(config, { isDev, outDir }) {
|
|
20
20
|
return {
|
|
21
21
|
isDev,
|
|
22
22
|
trustProxy: isDev || (config.trustProxy ?? false),
|
|
23
|
+
outDir,
|
|
23
24
|
};
|
|
24
25
|
}
|
|
25
26
|
//# sourceMappingURL=server-config.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/server/server-config.ts"],"names":[],"mappings":"AAiCA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI,EAAE,IAAI;IACV,IAAI,EAAE,SAAS;CACP,CAAC;AAEX;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAsC;IAC7G,OAAO;QACL,KAAK;QACL,UAAU,EAAE,KAAK,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,KAAK,CAAC;QACjD,MAAM;KACP,CAAC;AACJ,CAAC","sourcesContent":["import type { RshonoConfig } from '../config.js';\n\n/**\n * The framework settings the server bundle needs at request time, fully resolved.\n *\n * The value is produced once by {@link resolveServerConfig} from `rshono.config.ts`\n * and compiled into the server bundle as the `__RSHONO_CONFIG__` literal (see\n * `builder/rspack-config.ts`) — there is no runtime env-var interface for these.\n *\n * Only what the *build* decides. The per-request security controls that used to live alongside these\n * — the CSRF check, the CSP, the body cap — are Hono middleware an app registers in `src/server.ts`,\n * where they can be configured per route and per environment instead of once per bundle.\n */\nexport interface ServerConfig {\n /**\n * `true` when the bundle came from `rshono dev`.\n *\n * Baked in rather than read from `process.env.NODE_ENV` at runtime: it is decided by which command\n * produced the bundle, and a deploy target need not have a `process` to read it from.\n */\n isDev: boolean;\n /** Honour `X-Forwarded-Host` / `-Proto` when resolving the browser-facing URL. Forced on in dev. */\n trustProxy: boolean;\n /**\n * The output directory this bundle was written to, relative to the project root — `dist` for a\n * build, something of its own for `rshono dev` (see `BUILD_OUT_DIR` / `DEV_OUT_DIR`).\n *\n * Carried into the bundle because `deploy/filesystem.ts` locates the static assets and the\n * prerendered pages beside it at runtime, and only the compiler knows which directory it used.\n */\n outDir: string;\n}\n\n/**\n * The framework's built-in defaults.\n *\n * `port` and `host` are not config fields at all — they come from `PORT` / `HOST` (or `--port`)\n * wherever the address is resolved, `deploy/node/runtime.ts` for a server bundle and `cli/dev.ts`\n * for the dev server, and this is what both fall back to.\n */\nexport const SERVER_DEFAULTS = {\n port: 3000,\n host: '0.0.0.0',\n} as const;\n\n/**\n * Resolve the user's {@link RshonoConfig} into the {@link ServerConfig} baked into the bundle.\n *\n * `isDev` is a build-time input rather than a config field because it decides one thing the user\n * shouldn't have to: `trustProxy` is forced on under `rshono dev`, where the framework's own proxy\n * is the only way in (it sets the forwarded headers itself and binds to localhost).\n */\nexport function resolveServerConfig(config: RshonoConfig, { isDev, outDir }: { isDev: boolean; outDir: string }): ServerConfig {\n return {\n isDev,\n trustProxy: isDev || (config.trustProxy ?? false),\n outDir,\n };\n}\n"]}
|
package/package.json
CHANGED