@rshono/core 1.0.0-rc.2 → 1.0.0-rc.21
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/LICENSE +21 -0
- package/README.md +348 -158
- package/bin/rshono.mjs +3 -4
- package/dist/builder/env-shadow-loader.cjs +123 -8
- package/dist/builder/page-entry-loader.cjs +28 -1
- package/dist/builder/page-files.d.ts +0 -1
- package/dist/builder/page-files.js +7 -3
- package/dist/builder/page-files.js.map +1 -1
- package/dist/builder/public-env.d.ts +7 -1
- package/dist/builder/public-env.js +7 -0
- package/dist/builder/public-env.js.map +1 -1
- package/dist/builder/react-versions.d.ts +12 -0
- package/dist/builder/react-versions.js +74 -0
- package/dist/builder/react-versions.js.map +1 -0
- package/dist/builder/rspack-config.d.ts +13 -4
- package/dist/builder/rspack-config.js +136 -53
- package/dist/builder/rspack-config.js.map +1 -1
- package/dist/builder/server-only-imports.d.ts +32 -0
- package/dist/builder/server-only-imports.js +51 -0
- package/dist/builder/server-only-imports.js.map +1 -0
- package/dist/cli/build.d.ts +2 -3
- package/dist/cli/build.js +51 -13
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts +2 -3
- package/dist/cli/dev.js +149 -45
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/exit.d.ts +12 -0
- package/dist/cli/exit.js +16 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +0 -1
- package/dist/cli/index.js +91 -30
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/start.d.ts +0 -1
- package/dist/cli/start.js +15 -18
- package/dist/cli/start.js.map +1 -1
- package/dist/config.d.ts +72 -78
- package/dist/config.js +17 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy/aws-lambda/runtime.d.ts +4 -7
- package/dist/deploy/aws-lambda/runtime.js +5 -8
- package/dist/deploy/aws-lambda/runtime.js.map +1 -1
- package/dist/deploy/build-marker.d.ts +9 -6
- package/dist/deploy/build-marker.js +8 -4
- package/dist/deploy/build-marker.js.map +1 -1
- package/dist/deploy/cloudflare/build.d.ts +0 -1
- package/dist/deploy/cloudflare/build.js +17 -13
- package/dist/deploy/cloudflare/build.js.map +1 -1
- package/dist/deploy/cloudflare/runtime.d.ts +2 -6
- package/dist/deploy/cloudflare/runtime.js +73 -68
- package/dist/deploy/cloudflare/runtime.js.map +1 -1
- package/dist/deploy/contract.d.ts +57 -41
- package/dist/deploy/contract.js.map +1 -1
- package/dist/deploy/filesystem.d.ts +3 -6
- package/dist/deploy/filesystem.js +23 -20
- package/dist/deploy/filesystem.js.map +1 -1
- package/dist/deploy/node/runtime.d.ts +5 -3
- package/dist/deploy/node/runtime.js +23 -9
- package/dist/deploy/node/runtime.js.map +1 -1
- package/dist/deploy/presets.d.ts +34 -30
- package/dist/deploy/presets.js +56 -44
- package/dist/deploy/presets.js.map +1 -1
- package/dist/deploy/public-paths.d.ts +42 -0
- package/dist/deploy/public-paths.js +66 -0
- package/dist/deploy/public-paths.js.map +1 -0
- package/dist/deploy/vercel/build.d.ts +0 -1
- package/dist/deploy/vercel/build.js +25 -16
- package/dist/deploy/vercel/build.js.map +1 -1
- package/dist/deploy/vercel/runtime.d.ts +10 -7
- package/dist/deploy/vercel/runtime.js +48 -11
- package/dist/deploy/vercel/runtime.js.map +1 -1
- package/dist/index.d.ts +19 -17
- package/dist/index.js +20 -10
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +212 -120
- package/dist/router.js +3 -8
- package/dist/router.js.map +1 -1
- package/dist/runtime/boundaries.d.ts +62 -48
- package/dist/runtime/boundaries.js +32 -34
- package/dist/runtime/boundaries.js.map +1 -1
- package/dist/runtime/client.d.ts +20 -11
- package/dist/runtime/client.js +20 -10
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/context.d.ts +304 -123
- package/dist/runtime/context.js +377 -149
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/control.d.ts +15 -1
- package/dist/runtime/control.js +24 -0
- package/dist/runtime/control.js.map +1 -1
- package/dist/runtime/dev-protocol.d.ts +4 -9
- package/dist/runtime/dev-protocol.js.map +1 -1
- package/dist/runtime/empty-server-app.d.ts +0 -1
- package/dist/runtime/entry.client.d.ts +4 -1
- package/dist/runtime/entry.client.js +455 -313
- package/dist/runtime/entry.client.js.map +1 -1
- package/dist/runtime/entry.rsc.d.ts +15 -7
- package/dist/runtime/entry.rsc.js +811 -252
- package/dist/runtime/entry.rsc.js.map +1 -1
- package/dist/runtime/entry.ssr.d.ts +27 -10
- package/dist/runtime/entry.ssr.js +30 -48
- package/dist/runtime/entry.ssr.js.map +1 -1
- package/dist/runtime/failure-document.d.ts +11 -0
- package/dist/runtime/failure-document.js +35 -0
- package/dist/runtime/failure-document.js.map +1 -0
- package/dist/runtime/flight-inject.d.ts +23 -0
- package/dist/runtime/flight-inject.js +403 -0
- package/dist/runtime/flight-inject.js.map +1 -0
- package/dist/runtime/hot-update.d.ts +44 -0
- package/dist/runtime/hot-update.js +44 -0
- package/dist/runtime/hot-update.js.map +1 -0
- package/dist/runtime/navigation.d.ts +46 -54
- package/dist/runtime/navigation.js +22 -63
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/request.d.ts +42 -8
- package/dist/runtime/request.js +84 -7
- package/dist/runtime/request.js.map +1 -1
- package/dist/runtime/server.d.ts +20 -18
- package/dist/runtime/server.js +22 -17
- package/dist/runtime/server.js.map +1 -1
- package/dist/runtime/validate-entries.d.ts +77 -0
- package/dist/runtime/validate-entries.js +405 -0
- package/dist/runtime/validate-entries.js.map +1 -0
- package/dist/server/headers.d.ts +41 -15
- package/dist/server/headers.js +53 -24
- package/dist/server/headers.js.map +1 -1
- package/dist/server/load-config.d.ts +4 -5
- package/dist/server/load-config.js +22 -14
- package/dist/server/load-config.js.map +1 -1
- package/dist/server/load-env.d.ts +0 -1
- package/dist/server/prerendered.d.ts +88 -34
- package/dist/server/prerendered.js +184 -24
- package/dist/server/prerendered.js.map +1 -1
- package/dist/server/server-config.d.ts +35 -50
- package/dist/server/server-config.js +27 -74
- package/dist/server/server-config.js.map +1 -1
- package/dist/server/shutdown.d.ts +5 -4
- package/dist/server/shutdown.js +5 -3
- package/dist/server/shutdown.js.map +1 -1
- package/dist/server/ssg.d.ts +9 -7
- package/dist/server/ssg.js +209 -65
- package/dist/server/ssg.js.map +1 -1
- package/dist/server/static.d.ts +0 -1
- package/dist/server/static.js +7 -1
- package/dist/server/static.js.map +1 -1
- package/package.json +21 -23
- package/dist/builder/page-files.d.ts.map +0 -1
- package/dist/builder/public-env.d.ts.map +0 -1
- package/dist/builder/rspack-config.d.ts.map +0 -1
- package/dist/cli/build.d.ts.map +0 -1
- package/dist/cli/dev.d.ts.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/start.d.ts.map +0 -1
- package/dist/config.d.ts.map +0 -1
- package/dist/deploy/aws-lambda/runtime.d.ts.map +0 -1
- package/dist/deploy/build-marker.d.ts.map +0 -1
- package/dist/deploy/bun/runtime.d.ts +0 -11
- package/dist/deploy/bun/runtime.d.ts.map +0 -1
- package/dist/deploy/bun/runtime.js +0 -22
- package/dist/deploy/bun/runtime.js.map +0 -1
- package/dist/deploy/cloudflare/build.d.ts.map +0 -1
- package/dist/deploy/cloudflare/runtime.d.ts.map +0 -1
- package/dist/deploy/contract.d.ts.map +0 -1
- package/dist/deploy/deno/runtime.d.ts +0 -11
- package/dist/deploy/deno/runtime.d.ts.map +0 -1
- package/dist/deploy/deno/runtime.js +0 -16
- package/dist/deploy/deno/runtime.js.map +0 -1
- package/dist/deploy/filesystem.d.ts.map +0 -1
- package/dist/deploy/listen.d.ts +0 -20
- package/dist/deploy/listen.d.ts.map +0 -1
- package/dist/deploy/listen.js +0 -24
- package/dist/deploy/listen.js.map +0 -1
- package/dist/deploy/netlify/build.d.ts +0 -8
- package/dist/deploy/netlify/build.d.ts.map +0 -1
- package/dist/deploy/netlify/build.js +0 -52
- package/dist/deploy/netlify/build.js.map +0 -1
- package/dist/deploy/netlify/runtime.d.ts +0 -13
- package/dist/deploy/netlify/runtime.d.ts.map +0 -1
- package/dist/deploy/netlify/runtime.js +0 -24
- package/dist/deploy/netlify/runtime.js.map +0 -1
- package/dist/deploy/node/runtime.d.ts.map +0 -1
- package/dist/deploy/presets.d.ts.map +0 -1
- package/dist/deploy/vercel/build.d.ts.map +0 -1
- package/dist/deploy/vercel/runtime.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/router.d.ts.map +0 -1
- package/dist/runtime/boundaries.d.ts.map +0 -1
- package/dist/runtime/client.d.ts.map +0 -1
- package/dist/runtime/context.d.ts.map +0 -1
- package/dist/runtime/control.d.ts.map +0 -1
- package/dist/runtime/dev-protocol.d.ts.map +0 -1
- package/dist/runtime/empty-server-app.d.ts.map +0 -1
- package/dist/runtime/entry.client.d.ts.map +0 -1
- package/dist/runtime/entry.rsc.d.ts.map +0 -1
- package/dist/runtime/entry.ssr.d.ts.map +0 -1
- package/dist/runtime/navigation.d.ts.map +0 -1
- package/dist/runtime/request.d.ts.map +0 -1
- package/dist/runtime/server.d.ts.map +0 -1
- package/dist/server/compress.d.ts +0 -15
- package/dist/server/compress.d.ts.map +0 -1
- package/dist/server/compress.js +0 -76
- package/dist/server/compress.js.map +0 -1
- package/dist/server/headers.d.ts.map +0 -1
- package/dist/server/load-config.d.ts.map +0 -1
- package/dist/server/load-env.d.ts.map +0 -1
- package/dist/server/prerendered.d.ts.map +0 -1
- package/dist/server/server-config.d.ts.map +0 -1
- package/dist/server/shutdown.d.ts.map +0 -1
- package/dist/server/ssg.d.ts.map +0 -1
- package/dist/server/static.d.ts.map +0 -1
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
import { rspack } from '@rspack/core';
|
|
2
2
|
import { ReactRefreshRspackPlugin } from '@rspack/plugin-react-refresh';
|
|
3
|
-
import { existsSync } from 'node:fs';
|
|
3
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
4
4
|
import { createRequire } from 'node:module';
|
|
5
|
-
import { basename, dirname, join, win32 } from 'node:path';
|
|
5
|
+
import { basename, dirname, join, sep, win32 } from 'node:path';
|
|
6
6
|
import { resolveServerConfig } from '../server/server-config.js';
|
|
7
|
+
import { serverOnlyImportPlugin } from './server-only-imports.js';
|
|
7
8
|
import { scanPageFiles } from './page-files.js';
|
|
8
9
|
import { publicEnv } from './public-env.js';
|
|
9
|
-
|
|
10
|
-
//
|
|
10
|
+
import { checkReactVersions } from './react-versions.js';
|
|
11
|
+
// This file lives in `dist/builder/`, so the entries and loaders below are the *built* framework.
|
|
11
12
|
const FRAMEWORK_DIST = join(import.meta.dirname, '..');
|
|
12
13
|
const FRAMEWORK_ROOT = join(FRAMEWORK_DIST, '..');
|
|
13
|
-
const BUNDLED_PACKAGES = /^(@rshono\/core|react|react-dom|react-server-dom-rspack|
|
|
14
|
+
const BUNDLED_PACKAGES = /^(@rshono\/core|react|react-dom|react-server-dom-rspack|hono|@hono\/node-server)(\/|$)/;
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* The directory a command writes its bundles to, relative to the project root — one per command, never
|
|
17
|
+
* shared: a `rshono build` alongside a running `rshono dev` would `clean` away the route chunks that
|
|
18
|
+
* server imports lazily, and Rspack's watch-mode emit never re-emits a file it believes it wrote.
|
|
19
|
+
*
|
|
20
|
+
* Both names are a single level under the root, which `deploy/filesystem.ts` relies on to derive the
|
|
21
|
+
* project root from where the bundle ended up.
|
|
22
|
+
*/
|
|
23
|
+
export const BUILD_OUT_DIR = 'dist';
|
|
24
|
+
export const DEV_OUT_DIR = '.rshono';
|
|
25
|
+
/**
|
|
26
|
+
* Packages the app's source ends up importing without ever naming them: the RSC transform rewrites a
|
|
27
|
+
* `'use client'` module, a page or an action into imports of the RSC runtime, resolved from the app's `src/`.
|
|
18
28
|
*/
|
|
19
29
|
const INJECTED_PACKAGES = ['react-server-dom-rspack'];
|
|
20
30
|
/** The `node_modules` directory a resolved file sits in — `…/node_modules/pkg/index.js` → `…/node_modules`. */
|
|
@@ -29,17 +39,13 @@ function enclosingNodeModules(file) {
|
|
|
29
39
|
return dir;
|
|
30
40
|
}
|
|
31
41
|
/**
|
|
32
|
-
* Where packages are resolved from: the app's own `node_modules`, then the framework's
|
|
42
|
+
* Where packages are resolved from: the app's own `node_modules`, then the framework's — which is what makes
|
|
43
|
+
* {@link INJECTED_PACKAGES} resolvable from app source under pnpm, where the framework's dependencies are
|
|
44
|
+
* installed as siblings of `@rshono/core` rather than hoisted into the app's tree.
|
|
33
45
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* rather than inside it, and nothing under the app's tree can see them — the build fails with
|
|
38
|
-
* `Can't resolve 'react-server-dom-rspack/client'` in a file the user never wrote that import into.
|
|
39
|
-
*
|
|
40
|
-
* Asking Node where the framework itself resolves the package finds the directory in any layout, and
|
|
41
|
-
* making it a search path rather than an alias keeps the package's own `exports` conditions in play —
|
|
42
|
-
* the RSC layer, the SSR layer and each deploy target need a different build of it.
|
|
46
|
+
* Asking Node where the framework resolves the package finds it in any layout, and a search path rather than
|
|
47
|
+
* an alias keeps the package's own `exports` conditions in play — the RSC layer, the SSR layer and each
|
|
48
|
+
* deploy target need a different build of it.
|
|
43
49
|
*/
|
|
44
50
|
function resolveModules() {
|
|
45
51
|
const require = createRequire(import.meta.url);
|
|
@@ -54,20 +60,16 @@ function resolveModules() {
|
|
|
54
60
|
// Left to the resolver to report against the request that actually needed it.
|
|
55
61
|
}
|
|
56
62
|
}
|
|
57
|
-
// A checkout or a vendored copy, where the framework has real dependencies of its own
|
|
58
|
-
// above found nothing to add.
|
|
63
|
+
// A checkout or a vendored copy, where the framework has real dependencies of its own.
|
|
59
64
|
dirs.add(join(FRAMEWORK_ROOT, 'node_modules'));
|
|
60
65
|
return ['node_modules', ...dirs];
|
|
61
66
|
}
|
|
62
67
|
/**
|
|
63
68
|
* Whether a request names a file rather than a package, and so belongs in the bundle.
|
|
64
69
|
*
|
|
65
|
-
* Rspack's RSC plugins ask for their
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
* `ERR_UNSUPPORTED_ESM_URL_SCHEME` ("Received protocol 'd:'") — a build that works everywhere else
|
|
69
|
-
* fails on Windows only. `win32.isAbsolute` also accepts the POSIX form, so it is used on every
|
|
70
|
-
* platform: one code path, and the Windows shapes stay testable off Windows.
|
|
70
|
+
* Rspack's RSC plugins ask for their proxies by absolute path, which on Windows carries a drive letter —
|
|
71
|
+
* externalizing one emits an `import("D:\\…")` Node rejects. `win32.isAbsolute` accepts the POSIX form too,
|
|
72
|
+
* so it runs on every platform and the Windows shapes stay testable off Windows.
|
|
71
73
|
*/
|
|
72
74
|
function isPathRequest(request) {
|
|
73
75
|
return request.startsWith('.') || win32.isAbsolute(request);
|
|
@@ -75,29 +77,71 @@ function isPathRequest(request) {
|
|
|
75
77
|
const BROWSER_TARGETS = ['last 2 versions', '> 0.2%', 'not dead', 'Firefox ESR'];
|
|
76
78
|
const NODE_TARGETS = ['node >= 22'];
|
|
77
79
|
/**
|
|
78
|
-
* Rspack's native CSS pipeline, which both compilers get.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* the loader through the {@link RSHonoConfig.rspack} hook, along with the two packages a PostCSS pass
|
|
82
|
-
* takes. The framework stays out of it: `postcss` is a dependency an app that wants one can have, rather
|
|
83
|
-
* than one every app pays for. The Styling section of the README has the four lines involved.
|
|
80
|
+
* Rspack's native CSS pipeline, which both compilers get. It parses *finished* CSS, so a stylesheet needing
|
|
81
|
+
* PostCSS — Tailwind, most obviously — adds that loader through the {@link RshonoConfig.rspack} hook, which
|
|
82
|
+
* keeps `postcss` a dependency of the apps that want one.
|
|
84
83
|
*
|
|
85
|
-
* A fresh object per compiler,
|
|
86
|
-
* an app that reaches in to change this rule should not find it has changed the other bundle's too.
|
|
84
|
+
* A fresh object per compiler, so an app changing this rule does not silently change the other bundle's.
|
|
87
85
|
*/
|
|
88
86
|
function cssRule() {
|
|
89
87
|
return { test: /\.css$/i, type: 'css/auto' };
|
|
90
88
|
}
|
|
89
|
+
/** Source files worth reading for {@link mentions} — the app's own code, whatever dialect it is written in. */
|
|
90
|
+
const SOURCE_FILE = /\.[cm]?[jt]sx?$/;
|
|
91
|
+
/**
|
|
92
|
+
* Whether `identifier` appears anywhere in the app's own source. The whole tree rather than `src/server.ts`
|
|
93
|
+
* alone, so middleware registered from a helper module counts.
|
|
94
|
+
*
|
|
95
|
+
* A textual scan on purpose. What is being answered is "did the author think about this at all", which is a
|
|
96
|
+
* question a build warning is allowed to get wrong: the failure mode is a warning that is unwarranted, never a
|
|
97
|
+
* build that fails or a behaviour that changes. Resolving it properly would mean reading the module graph, and
|
|
98
|
+
* a middleware registered from a package outside `src/` would still slip past.
|
|
99
|
+
*/
|
|
100
|
+
function mentions(srcDir, identifier) {
|
|
101
|
+
try {
|
|
102
|
+
for (const entry of readdirSync(srcDir, { recursive: true, withFileTypes: true })) {
|
|
103
|
+
if (!entry.isFile() || !SOURCE_FILE.test(entry.name))
|
|
104
|
+
continue;
|
|
105
|
+
if (readFileSync(join(entry.parentPath, entry.name), 'utf8').includes(identifier))
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// An unreadable `src/` is not this function's to report: the build is about to fail on `routes.ts`.
|
|
111
|
+
}
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
91
114
|
export function createConfigs(options) {
|
|
92
115
|
const { rootDir, isDev, config, preset, onServerComponentChanges } = options;
|
|
93
116
|
const srcDir = join(rootDir, 'src');
|
|
94
117
|
const mode = isDev ? 'development' : 'production';
|
|
118
|
+
const outDir = isDev ? DEV_OUT_DIR : BUILD_OUT_DIR;
|
|
119
|
+
// Before anything is compiled: a react/react-dom split fails inside React at render time, and this is the
|
|
120
|
+
// one place that can say so with the two versions in hand.
|
|
121
|
+
checkReactVersions(rootDir);
|
|
95
122
|
const routesFile = ['routes.ts', 'routes.tsx'].map((f) => join(srcDir, f)).find(existsSync);
|
|
96
123
|
if (!routesFile) {
|
|
97
124
|
throw new Error(`[rshono] src/routes.ts not found in ${rootDir} — it is the one required file.`);
|
|
98
125
|
}
|
|
99
126
|
const serverAppFile = ['server.ts', 'server.tsx'].map((f) => join(srcDir, f)).find(existsSync);
|
|
100
127
|
const serverAppAlias = serverAppFile ?? join(FRAMEWORK_DIST, 'runtime', 'empty-server-app.js');
|
|
128
|
+
// Optional, and staying optional — but per-request security is Hono middleware registered there, so an app
|
|
129
|
+
// without one has opted out of all of it, which is worth hearing once rather than discovering. Builds only:
|
|
130
|
+
// `dev` would print it on every rebuild, and it is not news on a developer's machine.
|
|
131
|
+
if (!isDev) {
|
|
132
|
+
if (!serverAppFile) {
|
|
133
|
+
console.warn(' ⚠ No src/server.ts — this build has no CSRF check and no request body cap. Both are Hono middleware\n' +
|
|
134
|
+
' (`csrf()`, `bodyLimit()`); `npx @rshono/create` scaffolds a src/server.ts with them registered.');
|
|
135
|
+
}
|
|
136
|
+
else if (!mentions(srcDir, 'bodyLimit')) {
|
|
137
|
+
// Having a src/server.ts is not the same as having the cap in it, and this half used to be warned about
|
|
138
|
+
// nowhere: every `'use server'` export is a public POST endpoint by design, and the action path buffers
|
|
139
|
+
// the whole body before it can decide anything about it.
|
|
140
|
+
console.warn(" ⚠ No bodyLimit() anywhere in src/ — this build has no request body cap. Every 'use server' export is\n" +
|
|
141
|
+
' a public POST endpoint, and the action path buffers whatever arrives before it can reject it.\n' +
|
|
142
|
+
' Add `server.use(bodyLimit({ maxSize: 1024 * 1024 }))` to src/server.ts (from `hono/body-limit`).');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
101
145
|
const rscEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.rsc.js');
|
|
102
146
|
const ssrEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.ssr.js');
|
|
103
147
|
const clientEntry = join(FRAMEWORK_DIST, 'runtime', 'entry.client.js');
|
|
@@ -123,9 +167,8 @@ export function createConfigs(options) {
|
|
|
123
167
|
extensionAlias: { '.js': ['.ts', '.tsx', '.js'] },
|
|
124
168
|
modules: resolveModules(),
|
|
125
169
|
};
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// one per runtime. Left unset for Node, where the target already implies the `node` condition.
|
|
170
|
+
// Ahead of whatever the Rspack target implies ('...'), which is what hands the server bundle the right
|
|
171
|
+
// build of React and the RSC runtime. Unset for Node, whose target already implies the `node` condition.
|
|
129
172
|
const runtimeConditions = preset.resolveConditions ?? [];
|
|
130
173
|
const serverResolveBase = runtimeConditions.length > 0 ? { ...resolveBase, conditionNames: [...runtimeConditions, '...'] } : resolveBase;
|
|
131
174
|
const rscConditionNames = ['react-server', ...runtimeConditions, '...'];
|
|
@@ -145,10 +188,12 @@ export function createConfigs(options) {
|
|
|
145
188
|
mode,
|
|
146
189
|
target: 'web',
|
|
147
190
|
context: rootDir,
|
|
191
|
+
// Never in a build: a client map is served from `/_static` like everything else beside it, and it would
|
|
192
|
+
// publish the original source of the app's own modules. Dev binds 127.0.0.1 only.
|
|
148
193
|
devtool: isDev ? 'source-map' : false,
|
|
149
194
|
entry: { main: clientEntry },
|
|
150
195
|
output: {
|
|
151
|
-
path: join(rootDir,
|
|
196
|
+
path: join(rootDir, outDir, 'static'),
|
|
152
197
|
publicPath: '/_static/',
|
|
153
198
|
clean: !isDev,
|
|
154
199
|
filename: isDev ? 'chunks/main.js' : 'chunks/main.[contenthash].js',
|
|
@@ -169,6 +214,7 @@ export function createConfigs(options) {
|
|
|
169
214
|
},
|
|
170
215
|
plugins: [
|
|
171
216
|
new ClientPlugin(),
|
|
217
|
+
serverOnlyImportPlugin(rootDir),
|
|
172
218
|
new rspack.DefinePlugin({ 'process.env': JSON.stringify(publicEnv(isDev)) }),
|
|
173
219
|
...(isDev ? [new rspack.HotModuleReplacementPlugin(), new ReactRefreshRspackPlugin()] : []),
|
|
174
220
|
],
|
|
@@ -179,11 +225,17 @@ export function createConfigs(options) {
|
|
|
179
225
|
mode,
|
|
180
226
|
target: 'node',
|
|
181
227
|
context: rootDir,
|
|
182
|
-
|
|
228
|
+
// In a build too, unlike the client's: the bundle is minified, and without a map every stack trace that
|
|
229
|
+
// reaches `onServerError` — the error-tracker funnel — is unmappable minified frames. A server map is
|
|
230
|
+
// never served to anyone; `dist/server` is not on a public path, and the runtime enables Node's own
|
|
231
|
+
// mapping so no host has to pass a flag.
|
|
232
|
+
devtool: 'source-map',
|
|
183
233
|
entry: { main: rscEntry },
|
|
184
234
|
output: {
|
|
185
|
-
path: join(rootDir,
|
|
186
|
-
|
|
235
|
+
path: join(rootDir, outDir, 'server'),
|
|
236
|
+
// Off in dev: route chunks are imported lazily, so a superseded one on disk is harmless where deleting
|
|
237
|
+
// one mid-request is not. `rshono dev` empties the directory on startup instead.
|
|
238
|
+
clean: !isDev,
|
|
187
239
|
module: true,
|
|
188
240
|
chunkFormat: 'module',
|
|
189
241
|
chunkLoading: 'import',
|
|
@@ -194,18 +246,30 @@ export function createConfigs(options) {
|
|
|
194
246
|
assetModuleFilename: 'assets/[name].[hash][ext]',
|
|
195
247
|
},
|
|
196
248
|
optimization: {
|
|
197
|
-
minimize: false,
|
|
249
|
+
minimize: isDev ? false : true,
|
|
198
250
|
},
|
|
199
251
|
externalsType: 'module-import',
|
|
200
252
|
externals: [
|
|
201
|
-
({ request }, callback) => {
|
|
253
|
+
({ request, contextInfo }, callback) => {
|
|
202
254
|
if (!request ||
|
|
203
255
|
isPathRequest(request) ||
|
|
204
256
|
request.startsWith('@/') ||
|
|
205
257
|
request.startsWith('@rshono/') ||
|
|
206
258
|
request.startsWith('builtin:') ||
|
|
207
259
|
request.includes('!') ||
|
|
208
|
-
BUNDLED_PACKAGES.test(request)
|
|
260
|
+
BUNDLED_PACKAGES.test(request) ||
|
|
261
|
+
// Anything reached from the SSR layer, which is where `'use client'` components are rendered on the
|
|
262
|
+
// server. It has to be *compiled* rather than imported by name, because the env-shadow loader is what
|
|
263
|
+
// keeps a secret out of SSR'd HTML and a loader cannot run on a module the bundle only names — an
|
|
264
|
+
// externalized third-party client component is loaded raw at request time and reads the real
|
|
265
|
+
// `process.env`. Widening the loader's rule to cover `node_modules` did not reach this: there was no
|
|
266
|
+
// module for it to run on.
|
|
267
|
+
//
|
|
268
|
+
// Free of the usual bundling trade-off, too. Every module in this layer is in the *browser* bundle as
|
|
269
|
+
// well, so it is already required to be bundleable — a native addon or a `__dirname` file read could
|
|
270
|
+
// not have been a client component in the first place. The RSC layer, where server-only dependencies
|
|
271
|
+
// live, keeps the externals policy.
|
|
272
|
+
contextInfo?.issuerLayer === Layers.ssr) {
|
|
209
273
|
return callback();
|
|
210
274
|
}
|
|
211
275
|
callback(undefined, `module-import ${request}`);
|
|
@@ -216,8 +280,7 @@ export function createConfigs(options) {
|
|
|
216
280
|
alias: {
|
|
217
281
|
'@rshono/routes$': routesFile,
|
|
218
282
|
'@rshono/server-app$': serverAppAlias,
|
|
219
|
-
//
|
|
220
|
-
// preset can declare a POSIX-looking path and still resolve on Windows.
|
|
283
|
+
// Split on '/' so a preset can declare a POSIX-looking path and still resolve on Windows.
|
|
221
284
|
'@rshono/deploy$': join(FRAMEWORK_DIST, ...preset.runtimeModule.split('/')),
|
|
222
285
|
'@': srcDir,
|
|
223
286
|
},
|
|
@@ -230,13 +293,33 @@ export function createConfigs(options) {
|
|
|
230
293
|
use: [{ loader: join(FRAMEWORK_DIST, 'builder', 'page-entry-loader.cjs') }],
|
|
231
294
|
},
|
|
232
295
|
{
|
|
296
|
+
// Deliberately not scoped to `srcDir`: a `'use client'` component from `node_modules` is SSR'd in
|
|
297
|
+
// the same layer, and scoping this to the app's own source left those rendering against the real
|
|
298
|
+
// `process.env` while the browser bundle saw the `PUBLIC_`-only view — a hydration mismatch on
|
|
299
|
+
// anything the host sets, and a leak for anything secret. The loader's own layer check is what
|
|
300
|
+
// decides; every other module gets one `includes('process')` scan.
|
|
233
301
|
test: /\.[cm]?[tj]sx?$/,
|
|
234
|
-
include: srcDir,
|
|
235
302
|
enforce: 'pre',
|
|
236
303
|
use: [
|
|
237
304
|
{
|
|
238
305
|
loader: join(FRAMEWORK_DIST, 'builder', 'env-shadow-loader.cjs'),
|
|
239
|
-
|
|
306
|
+
// `Object.create` over the real `process`, not a bare `{ env }`: the prelude shadows the whole
|
|
307
|
+
// binding for that module, and `react-dom/server` is in this layer too — anything reading
|
|
308
|
+
// `process.nextTick` or `process.platform` has to still find it. Not a `{ __proto__: … }`
|
|
309
|
+
// literal, whose meaning would change if a minifier ever quoted the key.
|
|
310
|
+
options: {
|
|
311
|
+
prelude: `const process = Object.assign(Object.create(globalThis.process ?? Object.prototype), { env: ${JSON.stringify(publicEnv(isDev))} }); `,
|
|
312
|
+
layer: Layers.ssr,
|
|
313
|
+
// The prelude's binding hides `process.env.NODE_ENV` from DefinePlugin, which is what erases
|
|
314
|
+
// React's `if (NODE_ENV === 'production')` wrappers. The loader substitutes it back so the
|
|
315
|
+
// dead half still goes; without it the SSR layer ships both builds of every React package.
|
|
316
|
+
nodeEnv: mode,
|
|
317
|
+
// Only the app's own source is warned about when it reaches `process` through the global
|
|
318
|
+
// object, which no prelude can shadow — a library feature-detecting `globalThis.process` is
|
|
319
|
+
// doing nothing wrong and has no app secret to read. The separator is part of the prefix so
|
|
320
|
+
// a sibling directory named `src-old` is not mistaken for it.
|
|
321
|
+
appSrcPrefix: srcDir + sep,
|
|
322
|
+
},
|
|
240
323
|
},
|
|
241
324
|
],
|
|
242
325
|
},
|
|
@@ -263,14 +346,14 @@ export function createConfigs(options) {
|
|
|
263
346
|
plugins: [
|
|
264
347
|
pageScanPlugin,
|
|
265
348
|
new ServerPlugin({ onServerComponentChanges }),
|
|
266
|
-
//
|
|
267
|
-
|
|
268
|
-
|
|
349
|
+
// Bakes rshono.config.ts into the bundle, read back as `__RSHONO_CONFIG__` at request time.
|
|
350
|
+
new rspack.DefinePlugin({
|
|
351
|
+
__RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev, outDir, envBindings: preset.envBindings })),
|
|
352
|
+
}),
|
|
269
353
|
],
|
|
270
354
|
performance: false,
|
|
271
355
|
};
|
|
272
|
-
// The platform's
|
|
273
|
-
// preset decided.
|
|
356
|
+
// The platform's overrides first, then the user's hook — so an app can adjust whatever a preset decided.
|
|
274
357
|
preset.configureServer?.(serverConfig);
|
|
275
358
|
const rspackHook = config.rspack;
|
|
276
359
|
if (rspackHook) {
|
|
@@ -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|rsc-html-stream|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 bun\n * hoist the framework's dependencies to the app's own `node_modules`, so they need nothing; pnpm gives\n * `@rshono/core` a private directory and installs its dependencies as *siblings* of the framework\n * rather than inside it, and nothing under the app's tree can see them — the build fails with\n * `Can't resolve 'react-server-dom-rspack/client'` in a file the user never wrote that import into.\n *\n * Asking Node where the framework itself resolves the package finds the directory in any layout, and\n * making it a search path rather than an alias keeps the package's own `exports` conditions in play —\n * the RSC 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\")`, and Node rejects that with\n * `ERR_UNSUPPORTED_ESM_URL_SCHEME` (\"Received protocol 'd:'\") — a build that works everywhere else\n * fails on Windows only. `win32.isAbsolute` also accepts the POSIX form, so it is used on every\n * 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 — adds\n * the loader through the {@link RSHonoConfig.rspack} hook, along with the two packages a PostCSS pass\n * takes. The framework stays out of it: `postcss` is a dependency an app that wants one can have, rather\n * than one every app pays for. The Styling section of the README has the four lines involved.\n *\n * A fresh object per compiler, not one shared between them — the hook is handed each config in turn, and\n * an app that reaches in to change this rule should not find it has 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: false,\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 // Bake the framework settings from rshono.config.ts into the bundle (read as __RSHONO_CONFIG__\n // in entry.rsc.tsx) — the server-side counterpart to the client's publicEnv injection.\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, readdirSync, readFileSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { basename, dirname, join, sep, 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 { serverOnlyImportPlugin } from './server-only-imports.js';\nimport { scanPageFiles } from './page-files.js';\nimport { publicEnv } from './public-env.js';\nimport { checkReactVersions } from './react-versions.js';\n\n// This file lives in `dist/builder/`, so the entries and loaders below are the *built* framework.\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, never\n * shared: a `rshono build` alongside a running `rshono dev` would `clean` away the route chunks that\n * server imports lazily, and Rspack's watch-mode emit never re-emits a file it believes it wrote.\n *\n * Both names are a single level under the root, which `deploy/filesystem.ts` relies on to derive the\n * project root from where the bundle ended up.\n */\nexport const BUILD_OUT_DIR = 'dist';\nexport const DEV_OUT_DIR = '.rshono';\n\n/**\n * Packages the app's source ends up importing without ever naming them: the RSC transform rewrites a\n * `'use client'` module, a page or an action into imports of the RSC runtime, resolved from the app's `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 — which is what makes\n * {@link INJECTED_PACKAGES} resolvable from app source under pnpm, where the framework's dependencies are\n * installed as siblings of `@rshono/core` rather than hoisted into the app's tree.\n *\n * Asking Node where the framework resolves the package finds it in any layout, and a search path rather than\n * an alias keeps the package's own `exports` conditions in play — the RSC layer, the SSR layer and each\n * 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.\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 proxies by absolute path, which on Windows carries a drive letter —\n * externalizing one emits an `import(\"D:\\\\…\")` Node rejects. `win32.isAbsolute` accepts the POSIX form too,\n * so it runs on every platform 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. It parses *finished* CSS, so a stylesheet needing\n * PostCSS — Tailwind, most obviously — adds that loader through the {@link RshonoConfig.rspack} hook, which\n * keeps `postcss` a dependency of the apps that want one.\n *\n * A fresh object per compiler, so an app changing this rule does not silently change the other bundle's.\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\n/** Source files worth reading for {@link mentions} — the app's own code, whatever dialect it is written in. */\nconst SOURCE_FILE = /\\.[cm]?[jt]sx?$/;\n\n/**\n * Whether `identifier` appears anywhere in the app's own source. The whole tree rather than `src/server.ts`\n * alone, so middleware registered from a helper module counts.\n *\n * A textual scan on purpose. What is being answered is \"did the author think about this at all\", which is a\n * question a build warning is allowed to get wrong: the failure mode is a warning that is unwarranted, never a\n * build that fails or a behaviour that changes. Resolving it properly would mean reading the module graph, and\n * a middleware registered from a package outside `src/` would still slip past.\n */\nfunction mentions(srcDir: string, identifier: string): boolean {\n try {\n for (const entry of readdirSync(srcDir, { recursive: true, withFileTypes: true })) {\n if (!entry.isFile() || !SOURCE_FILE.test(entry.name)) continue;\n if (readFileSync(join(entry.parentPath, entry.name), 'utf8').includes(identifier)) return true;\n }\n } catch {\n // An unreadable `src/` is not this function's to report: the build is about to fail on `routes.ts`.\n }\n return false;\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 // Before anything is compiled: a react/react-dom split fails inside React at render time, and this is the\n // one place that can say so with the two versions in hand.\n checkReactVersions(rootDir);\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 // Optional, and staying optional — but per-request security is Hono middleware registered there, so an app\n // without one has opted out of all of it, which is worth hearing once rather than discovering. Builds only:\n // `dev` would print it on every rebuild, and it is not news on a developer's machine.\n if (!isDev) {\n if (!serverAppFile) {\n console.warn(\n ' ⚠ No src/server.ts — this build has no CSRF check and no request body cap. Both are Hono middleware\\n' +\n ' (`csrf()`, `bodyLimit()`); `npx @rshono/create` scaffolds a src/server.ts with them registered.',\n );\n } else if (!mentions(srcDir, 'bodyLimit')) {\n // Having a src/server.ts is not the same as having the cap in it, and this half used to be warned about\n // nowhere: every `'use server'` export is a public POST endpoint by design, and the action path buffers\n // the whole body before it can decide anything about it.\n console.warn(\n \" ⚠ No bodyLimit() anywhere in src/ — this build has no request body cap. Every 'use server' export is\\n\" +\n ' a public POST endpoint, and the action path buffers whatever arrives before it can reject it.\\n' +\n ' Add `server.use(bodyLimit({ maxSize: 1024 * 1024 }))` to src/server.ts (from `hono/body-limit`).',\n );\n }\n }\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 // Ahead of whatever the Rspack target implies ('...'), which is what hands the server bundle the right\n // build of React and the RSC runtime. Unset for Node, whose 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 // Never in a build: a client map is served from `/_static` like everything else beside it, and it would\n // publish the original source of the app's own modules. Dev binds 127.0.0.1 only.\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 serverOnlyImportPlugin(rootDir),\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 // In a build too, unlike the client's: the bundle is minified, and without a map every stack trace that\n // reaches `onServerError` — the error-tracker funnel — is unmappable minified frames. A server map is\n // never served to anyone; `dist/server` is not on a public path, and the runtime enables Node's own\n // mapping so no host has to pass a flag.\n devtool: 'source-map',\n entry: { main: rscEntry },\n output: {\n path: join(rootDir, outDir, 'server'),\n // Off in dev: route chunks are imported lazily, so a superseded one on disk is harmless where deleting\n // one mid-request is not. `rshono dev` empties the directory on startup instead.\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, contextInfo }, 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 // Anything reached from the SSR layer, which is where `'use client'` components are rendered on the\n // server. It has to be *compiled* rather than imported by name, because the env-shadow loader is what\n // keeps a secret out of SSR'd HTML and a loader cannot run on a module the bundle only names — an\n // externalized third-party client component is loaded raw at request time and reads the real\n // `process.env`. Widening the loader's rule to cover `node_modules` did not reach this: there was no\n // module for it to run on.\n //\n // Free of the usual bundling trade-off, too. Every module in this layer is in the *browser* bundle as\n // well, so it is already required to be bundleable — a native addon or a `__dirname` file read could\n // not have been a client component in the first place. The RSC layer, where server-only dependencies\n // live, keeps the externals policy.\n contextInfo?.issuerLayer === Layers.ssr\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 // Split on '/' so a 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 // Deliberately not scoped to `srcDir`: a `'use client'` component from `node_modules` is SSR'd in\n // the same layer, and scoping this to the app's own source left those rendering against the real\n // `process.env` while the browser bundle saw the `PUBLIC_`-only view — a hydration mismatch on\n // anything the host sets, and a leak for anything secret. The loader's own layer check is what\n // decides; every other module gets one `includes('process')` scan.\n test: /\\.[cm]?[tj]sx?$/,\n enforce: 'pre',\n use: [\n {\n loader: join(FRAMEWORK_DIST, 'builder', 'env-shadow-loader.cjs'),\n // `Object.create` over the real `process`, not a bare `{ env }`: the prelude shadows the whole\n // binding for that module, and `react-dom/server` is in this layer too — anything reading\n // `process.nextTick` or `process.platform` has to still find it. Not a `{ __proto__: … }`\n // literal, whose meaning would change if a minifier ever quoted the key.\n options: {\n prelude: `const process = Object.assign(Object.create(globalThis.process ?? Object.prototype), { env: ${JSON.stringify(publicEnv(isDev))} }); `,\n layer: Layers.ssr,\n // The prelude's binding hides `process.env.NODE_ENV` from DefinePlugin, which is what erases\n // React's `if (NODE_ENV === 'production')` wrappers. The loader substitutes it back so the\n // dead half still goes; without it the SSR layer ships both builds of every React package.\n nodeEnv: mode,\n // Only the app's own source is warned about when it reaches `process` through the global\n // object, which no prelude can shadow — a library feature-detecting `globalThis.process` is\n // doing nothing wrong and has no app secret to read. The separator is part of the prefix so\n // a sibling directory named `src-old` is not mistaken for it.\n appSrcPrefix: srcDir + sep,\n },\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({\n __RSHONO_CONFIG__: JSON.stringify(resolveServerConfig(config, { isDev, outDir, envBindings: preset.envBindings })),\n }),\n ],\n performance: false,\n };\n\n // The platform's overrides first, then the user's hook — so an app can adjust whatever a 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"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one import mistake the client compiler could not explain: `@rshono/core/server` reached from a
|
|
3
|
+
* `'use client'` module.
|
|
4
|
+
*
|
|
5
|
+
* The entry point is server-only by construction — `getRequestContext()` is an `AsyncLocalStorage` lookup —
|
|
6
|
+
* so the browser bundle cannot have it, and the build is right to fail. What it used to fail *with* was the
|
|
7
|
+
* resolver's own report of the first `node:` builtin three modules down:
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* ERROR in node:async_hooks
|
|
11
|
+
* × Reading from "node:async_hooks" is not handled by plugins (Unhandled scheme).
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* No file path, no issuer, and no mention of rshono or of the import that caused it. Everything else in the
|
|
15
|
+
* framework names the file to open; this was the one common mistake that did not, and the docs warn against it
|
|
16
|
+
* often enough to suggest people make it.
|
|
17
|
+
*
|
|
18
|
+
* So the request is caught before it resolves, where the *issuer* is still known, and reported as itself.
|
|
19
|
+
*/
|
|
20
|
+
import type { Compiler } from '@rspack/core';
|
|
21
|
+
/**
|
|
22
|
+
* Reports a server-only import by naming the module that made it.
|
|
23
|
+
*
|
|
24
|
+
* Two halves, because the resolver and the error list are reachable at different times. `beforeResolve` is
|
|
25
|
+
* where `contextInfo.issuer` is still on the request, and returning `false` there drops the dependency — which
|
|
26
|
+
* is what keeps the raw `node:` scheme error from being the build's only output. The error itself is pushed
|
|
27
|
+
* once the compilation exists to hold it, so it prints as an error against the compilation rather than as a
|
|
28
|
+
* throw out of a resolver hook.
|
|
29
|
+
*/
|
|
30
|
+
export declare function serverOnlyImportPlugin(rootDir: string): {
|
|
31
|
+
apply(compiler: Compiler): void;
|
|
32
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
/** Requests that exist only on the server, and what a browser module should reach for instead. */
|
|
3
|
+
const SERVER_ONLY = {
|
|
4
|
+
'@rshono/core/server': [
|
|
5
|
+
'It is server-only by construction: `getRequestContext()` reads an AsyncLocalStorage store that exists only while a request is being handled.',
|
|
6
|
+
"In a 'use client' component, read the URL and params with `useNavigation()` from '@rshono/core/client', navigate with the `router` it returns, and take anything else as a prop from the server component that renders this one.",
|
|
7
|
+
"If this module was not meant to be a client component, the 'use client' directive at the top of it — or of a module it imports — is what put it in the browser bundle.",
|
|
8
|
+
].join('\n'),
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Reports a server-only import by naming the module that made it.
|
|
12
|
+
*
|
|
13
|
+
* Two halves, because the resolver and the error list are reachable at different times. `beforeResolve` is
|
|
14
|
+
* where `contextInfo.issuer` is still on the request, and returning `false` there drops the dependency — which
|
|
15
|
+
* is what keeps the raw `node:` scheme error from being the build's only output. The error itself is pushed
|
|
16
|
+
* once the compilation exists to hold it, so it prints as an error against the compilation rather than as a
|
|
17
|
+
* throw out of a resolver hook.
|
|
18
|
+
*/
|
|
19
|
+
export function serverOnlyImportPlugin(rootDir) {
|
|
20
|
+
const NAME = 'rshono/server-only-imports';
|
|
21
|
+
return {
|
|
22
|
+
apply(compiler) {
|
|
23
|
+
/** Issuer → the request it made. A Map, so one module importing the same thing twice is reported once. */
|
|
24
|
+
const offenders = new Map();
|
|
25
|
+
compiler.hooks.normalModuleFactory.tap(NAME, (factory) => {
|
|
26
|
+
factory.hooks.beforeResolve.tap(NAME, (data) => {
|
|
27
|
+
// `hasOwn`, not `in`: a module named `toString` would otherwise inherit a match from Object.prototype.
|
|
28
|
+
if (!Object.hasOwn(SERVER_ONLY, data.request))
|
|
29
|
+
return;
|
|
30
|
+
offenders.set(data.contextInfo?.issuer ?? '', data.request);
|
|
31
|
+
// Dropped rather than left to fail: the resolver's report would name a `node:` builtin the author
|
|
32
|
+
// never wrote, and it would arrive beside this one.
|
|
33
|
+
return false;
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
// Cleared per compilation, so a watch rebuild that fixed the import stops reporting it.
|
|
37
|
+
compiler.hooks.thisCompilation.tap(NAME, () => offenders.clear());
|
|
38
|
+
compiler.hooks.afterCompile.tap(NAME, (compilation) => {
|
|
39
|
+
for (const [issuer, request] of offenders) {
|
|
40
|
+
const where = issuer ? relative(rootDir, issuer) : 'a module in the browser bundle';
|
|
41
|
+
// `file` is what Rspack puts on its own "ERROR in …" line, so the path lands where a reader looks
|
|
42
|
+
// for one instead of being the first words of the message.
|
|
43
|
+
compilation.errors.push(Object.assign(new Error(`[rshono] ${where} imports '${request}', which the browser bundle cannot have.\n${SERVER_ONLY[request]}`), {
|
|
44
|
+
file: where,
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=server-only-imports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-only-imports.js","sourceRoot":"","sources":["../../src/builder/server-only-imports.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,kGAAkG;AAClG,MAAM,WAAW,GAA2B;IAC1C,qBAAqB,EAAE;QACrB,8IAA8I;QAC9I,kOAAkO;QAClO,wKAAwK;KACzK,CAAC,IAAI,CAAC,IAAI,CAAC;CACb,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,MAAM,IAAI,GAAG,4BAA4B,CAAC;IAC1C,OAAO;QACL,KAAK,CAAC,QAAkB;YACtB,0GAA0G;YAC1G,MAAM,SAAS,GAAG,IAAI,GAAG,EAAkB,CAAC;YAE5C,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,EAAE;gBACvD,OAAO,CAAC,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBAC7C,uGAAuG;oBACvG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC;wBAAE,OAAO;oBACtD,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;oBAC5D,kGAAkG;oBAClG,oDAAoD;oBACpD,OAAO,KAAK,CAAC;gBACf,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,wFAAwF;YACxF,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;YAElE,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;gBACpD,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,SAAS,EAAE,CAAC;oBAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,gCAAgC,CAAC;oBACpF,kGAAkG;oBAClG,2DAA2D;oBAC3D,WAAW,CAAC,MAAM,CAAC,IAAI,CACrB,MAAM,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,YAAY,KAAK,aAAa,OAAO,6CAA6C,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,EAAE;wBACjI,IAAI,EAAE,KAAK;qBACZ,CAAC,CACH,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The one import mistake the client compiler could not explain: `@rshono/core/server` reached from a\n * `'use client'` module.\n *\n * The entry point is server-only by construction — `getRequestContext()` is an `AsyncLocalStorage` lookup —\n * so the browser bundle cannot have it, and the build is right to fail. What it used to fail *with* was the\n * resolver's own report of the first `node:` builtin three modules down:\n *\n * ```\n * ERROR in node:async_hooks\n * × Reading from \"node:async_hooks\" is not handled by plugins (Unhandled scheme).\n * ```\n *\n * No file path, no issuer, and no mention of rshono or of the import that caused it. Everything else in the\n * framework names the file to open; this was the one common mistake that did not, and the docs warn against it\n * often enough to suggest people make it.\n *\n * So the request is caught before it resolves, where the *issuer* is still known, and reported as itself.\n */\nimport type { Compiler } from '@rspack/core';\nimport { relative } from 'node:path';\n\n/** Requests that exist only on the server, and what a browser module should reach for instead. */\nconst SERVER_ONLY: Record<string, string> = {\n '@rshono/core/server': [\n 'It is server-only by construction: `getRequestContext()` reads an AsyncLocalStorage store that exists only while a request is being handled.',\n \"In a 'use client' component, read the URL and params with `useNavigation()` from '@rshono/core/client', navigate with the `router` it returns, and take anything else as a prop from the server component that renders this one.\",\n \"If this module was not meant to be a client component, the 'use client' directive at the top of it — or of a module it imports — is what put it in the browser bundle.\",\n ].join('\\n'),\n};\n\n/**\n * Reports a server-only import by naming the module that made it.\n *\n * Two halves, because the resolver and the error list are reachable at different times. `beforeResolve` is\n * where `contextInfo.issuer` is still on the request, and returning `false` there drops the dependency — which\n * is what keeps the raw `node:` scheme error from being the build's only output. The error itself is pushed\n * once the compilation exists to hold it, so it prints as an error against the compilation rather than as a\n * throw out of a resolver hook.\n */\nexport function serverOnlyImportPlugin(rootDir: string): { apply(compiler: Compiler): void } {\n const NAME = 'rshono/server-only-imports';\n return {\n apply(compiler: Compiler): void {\n /** Issuer → the request it made. A Map, so one module importing the same thing twice is reported once. */\n const offenders = new Map<string, string>();\n\n compiler.hooks.normalModuleFactory.tap(NAME, (factory) => {\n factory.hooks.beforeResolve.tap(NAME, (data) => {\n // `hasOwn`, not `in`: a module named `toString` would otherwise inherit a match from Object.prototype.\n if (!Object.hasOwn(SERVER_ONLY, data.request)) return;\n offenders.set(data.contextInfo?.issuer ?? '', data.request);\n // Dropped rather than left to fail: the resolver's report would name a `node:` builtin the author\n // never wrote, and it would arrive beside this one.\n return false;\n });\n });\n\n // Cleared per compilation, so a watch rebuild that fixed the import stops reporting it.\n compiler.hooks.thisCompilation.tap(NAME, () => offenders.clear());\n\n compiler.hooks.afterCompile.tap(NAME, (compilation) => {\n for (const [issuer, request] of offenders) {\n const where = issuer ? relative(rootDir, issuer) : 'a module in the browser bundle';\n // `file` is what Rspack puts on its own \"ERROR in …\" line, so the path lands where a reader looks\n // for one instead of being the first words of the message.\n compilation.errors.push(\n Object.assign(new Error(`[rshono] ${where} imports '${request}', which the browser bundle cannot have.\\n${SERVER_ONLY[request]}`), {\n file: where,\n }),\n );\n }\n });\n },\n };\n}\n"]}
|
package/dist/cli/build.d.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RshonoConfig } from '../config.js';
|
|
2
2
|
import type { DeployPreset } from '../deploy/presets.js';
|
|
3
3
|
interface BuildOptions {
|
|
4
4
|
rootDir: string;
|
|
5
|
-
config:
|
|
5
|
+
config: RshonoConfig;
|
|
6
6
|
/** The platform to build for, already resolved from the flag, the environment and the config. */
|
|
7
7
|
preset: DeployPreset;
|
|
8
8
|
}
|
|
9
9
|
export declare function buildCommand(options: BuildOptions): Promise<void>;
|
|
10
10
|
export {};
|
|
11
|
-
//# sourceMappingURL=build.d.ts.map
|