react-bun-ssr 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,48 +1,45 @@
1
1
  # react-bun-ssr
2
2
 
3
- `react-bun-ssr` is a TypeScript-first SSR React framework built for Bun.
3
+ `react-bun-ssr` is a Bun-native SSR React framework with file-based routing, loaders, actions, middleware, streaming, soft navigation, and first-class markdown routes.
4
4
 
5
- Documentation: https://react-bun-ssr.fly.dev/docs/getting-started/introduction
5
+ - Documentation: https://react-bun-ssr.fly.dev/docs
6
+ - API reference: https://react-bun-ssr.fly.dev/docs/api/overview
7
+ - Blog: https://react-bun-ssr.fly.dev/blog
8
+ - Repository: https://github.com/react-formation/react-bun-ssr
6
9
 
7
- This repository contains both:
8
- - The framework implementation (`framework/**`, `bin/**`).
9
- - The official documentation site built with the framework itself (`app/**`).
10
+ ## Why react-bun-ssr?
10
11
 
11
- ## Project layout
12
+ `react-bun-ssr` exists for teams that want server-rendered React without starting from Node-first assumptions.
12
13
 
13
- - `framework/`: runtime, router, renderer, build tooling, and CLI internals.
14
- - `bin/rbssr.ts`: CLI entrypoint.
15
- - `app/`: docs web app routes, layouts, middleware, and styles.
16
- - `app/routes/docs/**/*.md`: hand-authored markdown docs routes.
17
- - `app/routes/docs/_sidebar.ts`: docs navigation source of truth.
18
- - `app/routes/docs/api/*.md`: generated API docs.
19
- - `app/routes/docs/search-index.json`: generated search index.
20
- - `tests/`: unit + integration tests.
21
- - `e2e/`: Playwright end-to-end tests.
14
+ It is designed around Bun's runtime, server, bundler, markdown support, and file APIs instead of treating Bun as a compatibility layer. The goal is to stay small enough to understand, but complete enough to use seriously for real SSR applications. The documentation site in this repository is built with the framework itself, so the framework is continuously exercised by its own product surface.
22
15
 
23
- ## Requirements
16
+ ## What it includes
24
17
 
25
- - Bun `>= 1.3.9`
26
- - macOS/Linux (or equivalent Bun-supported environment)
18
+ - [File-based routing](/docs/routing/file-based-routing) for pages, APIs, dynamic params, and markdown routes
19
+ - [Layouts, route groups, and middleware](/docs/routing/layouts-and-groups) with a dedicated [middleware pipeline](/docs/routing/middleware)
20
+ - [Loaders and actions](/docs/data/loaders) for explicit data fetching and mutation flow
21
+ - [Streaming SSR and deferred data](/docs/rendering/streaming-deferred)
22
+ - Soft client transitions with [`Link` and `useRouter`](/docs/routing/navigation)
23
+ - [Bun-first runtime, build, and deployment model](/docs/deployment/bun-deployment)
24
+ - [CSS Modules and static asset support](/docs/styling/css-modules)
25
+ - [Response header config and static caching defaults](/docs/deployment/configuration)
27
26
 
28
- ## Runtime API policy
27
+ ## Installation
29
28
 
30
- - Prefer Bun APIs for file content I/O, hashing, build, and runtime operations.
31
- - `node:path` is intentionally retained for robust path resolution behavior.
32
- - `node:fs` is retained only for `watch` usage in dev mode.
29
+ Prerequisites:
33
30
 
34
- ## Run locally
31
+ - Bun `>= 1.3.10`
32
+ - `rbssr` available on PATH in the workflow you use to start a new app
35
33
 
36
- Install dependencies:
34
+ Minimal setup:
37
35
 
38
36
  ```bash
37
+ bun --version
38
+ mkdir my-app
39
+ cd my-app
40
+ rbssr init
39
41
  bun install
40
- ```
41
-
42
- Run docs site in development:
43
-
44
- ```bash
45
- bun run docs:dev
42
+ bun run dev
46
43
  ```
47
44
 
48
45
  Open:
@@ -51,155 +48,142 @@ Open:
51
48
  http://127.0.0.1:3000
52
49
  ```
53
50
 
54
- Build production artifacts:
55
-
56
- ```bash
57
- bun run docs:build
58
- ```
59
-
60
- Start production server:
51
+ For the full setup walkthrough, read the installation guide:
61
52
 
62
- ```bash
63
- bun run docs:preview
64
- ```
53
+ - https://react-bun-ssr.fly.dev/docs/start/installation
65
54
 
66
- ## Useful commands
55
+ ## What `rbssr init` gives you
67
56
 
68
- Framework:
57
+ `rbssr init` scaffolds a small Bun-first SSR app:
69
58
 
70
- ```bash
71
- bun run dev
72
- bun run build
73
- bun run start
74
- bun run typecheck
75
- bun run test
59
+ ```text
60
+ app/
61
+ root.tsx
62
+ middleware.ts
63
+ routes/
64
+ index.tsx
65
+ api/
66
+ health.ts
67
+ rbssr.config.ts
76
68
  ```
77
69
 
78
- Docs:
70
+ - `app/root.tsx`: document shell and top-level layout
71
+ - `app/middleware.ts`: global request pipeline hook
72
+ - `app/routes/index.tsx`: first SSR page route
73
+ - `app/routes/api/health.ts`: first API route
74
+ - `rbssr.config.ts`: runtime configuration entrypoint
79
75
 
80
- ```bash
81
- bun run docs:dev
82
- bun run docs:check
83
- bun run docs:build
84
- bun run docs:preview
85
- ```
76
+ The quickest follow-up is:
86
77
 
87
- ## Generated files
78
+ - https://react-bun-ssr.fly.dev/docs/start/quick-start
88
79
 
89
- Do not hand-edit generated docs artifacts:
90
- - `app/routes/docs/api/*.md`
91
- - `app/routes/docs/search-index.json`
80
+ ## How it works
92
81
 
93
- They are regenerated by:
94
- - `bun run scripts/generate-api-docs.ts`
95
- - `bun run scripts/build-search-index.ts`
96
- - or automatically via `bun run docs:build`
82
+ ### File-based routing
97
83
 
98
- ## Collaboration guide
84
+ Routes live under `app/routes`. Page routes, API routes, dynamic params, and markdown routes all share one route tree. Files like `_layout` and `_middleware` participate in routing and request flow without becoming public URL segments.
99
85
 
100
- ### 1. Create a branch
86
+ Read more:
101
87
 
102
- ```bash
103
- git checkout -b feat/<short-description>
104
- ```
88
+ - https://react-bun-ssr.fly.dev/docs/routing/file-based-routing
105
89
 
106
- ### 2. Make changes
90
+ ### Request pipeline
107
91
 
108
- - Framework code: update `framework/**`.
109
- - Docs content: update `app/routes/docs/**/*.md`.
110
- - Nav changes: update `app/routes/docs/_sidebar.ts`.
111
- - If exports change, regenerate API docs/search index.
92
+ For a page request, the framework resolves the matching route, runs global and nested middleware, executes the matched loader or action, and then renders an HTML response or returns a direct `Response` when the route short-circuits. API routes use the same route tree and middleware model, but return handler responses instead of page HTML.
112
93
 
113
- ### 3. Validate before pushing
94
+ Read more:
114
95
 
115
- ```bash
116
- bun run test
117
- bun run docs:check
118
- bun run docs:build
119
- ```
96
+ - https://react-bun-ssr.fly.dev/docs/routing/middleware
97
+ - https://react-bun-ssr.fly.dev/docs/data/loaders
120
98
 
121
- ### 4. Commit with generated artifacts when needed
99
+ ### Rendering model
122
100
 
123
- If your changes affect API docs or search corpus, commit updated files under `app/routes/docs/api/*.md` and `app/routes/docs/search-index.json`.
101
+ SSR is the default model. HTML responses stream, deferred loader data is supported, and soft client transitions are handled through `Link` and `useRouter`. The docs site in this repository uses the same routing, rendering, markdown, and transition model that framework users get.
124
102
 
125
- ### 5. Open a PR
103
+ Read more:
126
104
 
127
- Include:
128
- - Problem statement.
129
- - Approach and tradeoffs.
130
- - Testing performed.
131
- - Screenshots/GIF for docs UI changes (if relevant).
105
+ - https://react-bun-ssr.fly.dev/docs/rendering/streaming-deferred
106
+ - https://react-bun-ssr.fly.dev/docs/routing/navigation
132
107
 
133
- ## CI contract
108
+ ### Bun-first runtime
134
109
 
135
- CI runs:
136
- - `bun run test:unit`
137
- - `bun run test:integration`
138
- - `bun run docs:check`
139
- - `bun run docs:build`
110
+ Bun provides the runtime, server, bundler, markdown support, and file APIs that the framework is built around. `react-bun-ssr` is designed to use those primitives directly instead of layering itself on top of a Node-first base.
140
111
 
141
- `docs:check` fails when docs metadata, links, or generated artifacts are stale.
112
+ Read more:
142
113
 
143
- E2E (`bun run test:e2e`) runs on `push` to `main` only.
114
+ - https://react-bun-ssr.fly.dev/docs/api/bun-runtime-apis
144
115
 
145
- ## Deploy to Fly.io
116
+ ## Core commands
146
117
 
147
- ### Prerequisites
118
+ Framework commands:
148
119
 
149
- - Install `flyctl`: https://fly.io/docs/hands-on/install-flyctl/
150
- - Login:
120
+ - `rbssr init`: scaffold a new app in the current directory
121
+ - `rbssr dev`: start the Bun dev server
122
+ - `rbssr build`: create production output in `dist/`
123
+ - `rbssr start`: run the built app in production mode
151
124
 
152
- ```bash
153
- fly auth login
154
- ```
125
+ Repository maintenance commands:
126
+
127
+ - `bun run docs:dev`
128
+ - `bun run docs:check`
129
+ - `bun run docs:build`
130
+ - `bun run test`
131
+ - `bun run typecheck`
155
132
 
156
- ### One-time setup
133
+ CLI reference:
157
134
 
158
- `fly.toml` is included in this repository. Update the `app` name if needed:
135
+ - https://react-bun-ssr.fly.dev/docs/tooling/cli
159
136
 
160
- - `fly.toml`
137
+ ## Working on this repository
161
138
 
162
- Initialize without deploying (optional):
139
+ This repository contains both the framework and the official docs site built with it.
163
140
 
164
141
  ```bash
165
- fly launch --no-deploy
142
+ git clone git@github.com:react-formation/react-bun-ssr.git
143
+ cd react-bun-ssr
144
+ bun install
145
+ bun run docs:dev
166
146
  ```
167
147
 
168
- ### Deploy
148
+ That starts the docs site locally using the framework itself.
169
149
 
170
- ```bash
171
- fly deploy
172
- ```
150
+ ## Project layout
173
151
 
174
- ### Validate deployment
152
+ - `framework/`: runtime, renderer, route handling, build tooling, and CLI internals
153
+ - `bin/rbssr.ts`: CLI entrypoint
154
+ - `app/`: docs site routes, layouts, middleware, blog, and styles
155
+ - `app/routes/docs/**/*.md`: authored documentation pages
156
+ - `app/routes/blog/*.md`: authored blog posts
157
+ - `scripts/`: generators and validation scripts
158
+ - `tests/`: unit and integration tests
159
+ - `e2e/`: Playwright end-to-end tests
175
160
 
176
- ```bash
177
- fly status
178
- fly logs
179
- ```
161
+ ## Contributing
180
162
 
181
- Open:
163
+ Contributions should keep framework behavior, docs, tests, and generated artifacts aligned. For local setup, workflow, validation requirements, and generated-file policy, read [CONTRIBUTING.md](./CONTRIBUTING.md).
182
164
 
183
- ```text
184
- https://<your-fly-app>.fly.dev/docs/getting-started/introduction
185
- ```
165
+ ## Release and deploy
186
166
 
187
- ### Rollback
167
+ - Pushes to `main` run the main-branch CI gate and deploy automatically to Fly.io.
168
+ - Tags like `v0.1.1-rc.0` publish prereleases to npm under `rc`.
169
+ - Tags like `v0.1.1` publish stable releases to npm under `latest`.
170
+ - The release workflow derives the published package version from the Git tag and rewrites `package.json` in the release job before publishing.
171
+ - npm publishing uses trusted publishing with GitHub OIDC instead of an `NPM_TOKEN`.
172
+ - npm package settings must have a trusted publisher configured for `react-formation / react-bun-ssr / release.yml`.
188
173
 
189
- ```bash
190
- fly releases
191
- fly deploy --image <image-ref-from-release>
192
- ```
174
+ ## Deploying
175
+
176
+ Fly.io deployment support is already documented and used by this project.
193
177
 
194
- ### Scaling (optional)
178
+ Happy path:
195
179
 
196
180
  ```bash
197
- fly scale vm shared-cpu-1x
181
+ fly auth login
182
+ fly deploy
198
183
  ```
199
184
 
200
- ### Optional CI deploy
201
-
202
- The workflow includes an optional `deploy-fly` job on `main` push.
203
- Set this repository secret before enabling production deploys:
185
+ Full deployment docs:
204
186
 
205
- - `FLY_API_TOKEN`
187
+ - https://react-bun-ssr.fly.dev/docs/deployment/bun-deployment
188
+ - https://react-bun-ssr.fly.dev/docs/deployment/configuration
189
+ - https://react-bun-ssr.fly.dev/docs/deployment/troubleshooting
@@ -1,18 +1,23 @@
1
- import { watch, type FSWatcher } from "node:fs";
2
1
  import path from "node:path";
3
2
  import {
4
3
  buildRouteManifest,
5
4
  bundleClientEntries,
6
5
  copyDirRecursive,
7
6
  createBuildManifest,
8
- discoverFileSignature,
9
7
  ensureCleanDirectory,
10
8
  generateClientEntries,
11
9
  } from "../runtime/build-tools";
12
10
  import { loadUserConfig, resolveConfig } from "../runtime/config";
13
- import { ensureDir, existsPath, listEntries, removePath, writeText } from "../runtime/io";
14
- import { createServer } from "../runtime/server";
15
- import type { BuildRouteAsset, FrameworkConfig, ResolvedConfig } from "../runtime/types";
11
+ import { ensureDir, existsPath, writeText, writeTextIfChanged } from "../runtime/io";
12
+ import type { FrameworkConfig, ResolvedConfig } from "../runtime/types";
13
+ import {
14
+ createDevHotEntrypointSource,
15
+ createProductionServerEntrypointSource,
16
+ createTestCommands,
17
+ createTypecheckCommand,
18
+ parseFlags,
19
+ RBSSR_DEV_RESTART_EXIT_CODE,
20
+ } from "./internal";
16
21
  import { scaffoldApp } from "./scaffold";
17
22
 
18
23
  function log(message: string): void {
@@ -20,12 +25,6 @@ function log(message: string): void {
20
25
  console.log(`[rbssr] ${message}`);
21
26
  }
22
27
 
23
- function parseFlags(args: string[]): { force: boolean } {
24
- return {
25
- force: args.includes("--force"),
26
- };
27
- }
28
-
29
28
  async function getConfig(cwd: string): Promise<{ userConfig: FrameworkConfig; resolved: ResolvedConfig }> {
30
29
  const userConfig = await loadUserConfig(cwd);
31
30
  const resolved = resolveConfig(userConfig, cwd);
@@ -37,29 +36,7 @@ async function writeProductionServerEntrypoint(options: { distDir: string }): Pr
37
36
  await ensureDir(serverDir);
38
37
 
39
38
  const serverEntryPath = path.join(serverDir, "server.mjs");
40
- const content = `import path from "node:path";
41
- import config from "../../rbssr.config.ts";
42
- import { startHttpServer } from "../../framework/runtime/index.ts";
43
-
44
- const rootDir = path.resolve(path.dirname(Bun.fileURLToPath(import.meta.url)), "../..");
45
- process.chdir(rootDir);
46
-
47
- const manifestPath = path.resolve(rootDir, "dist/manifest.json");
48
- const manifest = await Bun.file(manifestPath).json();
49
-
50
- startHttpServer({
51
- config: {
52
- ...(config ?? {}),
53
- mode: "production",
54
- },
55
- runtimeOptions: {
56
- dev: false,
57
- buildManifest: manifest,
58
- },
59
- });
60
- `;
61
-
62
- await writeText(serverEntryPath, content);
39
+ await writeText(serverEntryPath, createProductionServerEntrypointSource());
63
40
  }
64
41
 
65
42
  export async function runInit(args: string[], cwd = process.cwd()): Promise<void> {
@@ -109,200 +86,64 @@ export async function runBuild(cwd = process.cwd()): Promise<void> {
109
86
  }
110
87
 
111
88
  export async function runDev(cwd = process.cwd()): Promise<void> {
112
- const { userConfig, resolved } = await getConfig(cwd);
113
- const generatedDir = path.resolve(cwd, ".rbssr/generated/client-entries");
114
- const devClientDir = path.resolve(cwd, ".rbssr/dev/client");
115
- const serverSnapshotsRoot = path.resolve(cwd, ".rbssr/dev/server-snapshots");
116
- const docsSourceDir = path.resolve(cwd, "docs");
117
- const docsSnapshotDir = path.join(serverSnapshotsRoot, "docs");
118
-
119
- await Promise.all([
120
- ensureDir(generatedDir),
121
- ensureDir(devClientDir),
122
- ensureCleanDirectory(serverSnapshotsRoot),
123
- ]);
124
-
125
- let routeAssets: Record<string, BuildRouteAsset> = {};
126
- let signature = "";
127
- let version = 0;
128
- let currentServerSnapshotDir = resolved.appDir;
129
- const reloadListeners = new Set<(nextVersion: number) => void>();
130
- const docsDir = path.resolve(cwd, "docs");
131
-
132
- const watchedRoots = [resolved.appDir];
133
- if (await existsPath(docsDir)) {
134
- watchedRoots.push(docsDir);
135
- }
136
-
137
- const getSourceSignature = async (): Promise<string> => {
138
- const signatures = await Promise.all(
139
- watchedRoots.map(root => discoverFileSignature(root)),
140
- );
141
- return signatures.join(":");
89
+ await getConfig(cwd);
90
+
91
+ const generatedDevDir = path.resolve(cwd, ".rbssr/generated/dev");
92
+ const generatedEntryPath = path.join(generatedDevDir, "entry.ts");
93
+ await ensureDir(generatedDevDir);
94
+ await writeTextIfChanged(generatedEntryPath, createDevHotEntrypointSource({
95
+ cwd,
96
+ runtimeModulePath: path.resolve(import.meta.dir, "dev-runtime.ts"),
97
+ }));
98
+
99
+ let activeChild: Bun.Subprocess<"inherit", "inherit", "inherit"> | null = null;
100
+ let shuttingDown = false;
101
+
102
+ const forwardSignal = (signal: NodeJS.Signals): void => {
103
+ shuttingDown = true;
104
+ activeChild?.kill(signal);
142
105
  };
143
106
 
144
- const notifyReload = (): void => {
145
- for (const listener of reloadListeners) {
146
- listener(version);
147
- }
148
- };
149
-
150
- const rebuildIfNeeded = async (force = false): Promise<void> => {
151
- const nextSignature = await getSourceSignature();
152
- if (!force && nextSignature === signature) {
153
- return;
154
- }
155
-
156
- signature = nextSignature;
157
-
158
- const snapshotDir = path.join(serverSnapshotsRoot, `v${version + 1}`);
159
- const hasDocsSourceDir = await existsPath(docsSourceDir);
160
- await Promise.all([
161
- (async () => {
162
- await ensureCleanDirectory(snapshotDir);
163
- await copyDirRecursive(resolved.appDir, snapshotDir);
164
- })(),
165
- hasDocsSourceDir
166
- ? (async () => {
167
- await ensureCleanDirectory(docsSnapshotDir);
168
- await copyDirRecursive(docsSourceDir, docsSnapshotDir);
169
- })()
170
- : removePath(docsSnapshotDir),
171
- ]);
172
-
173
- const snapshotConfig: ResolvedConfig = {
174
- ...resolved,
175
- appDir: snapshotDir,
176
- routesDir: path.join(snapshotDir, "routes"),
177
- rootModule: path.join(snapshotDir, "root.tsx"),
178
- middlewareFile: path.join(snapshotDir, "middleware.ts"),
179
- };
180
-
181
- const manifest = await buildRouteManifest(snapshotConfig);
182
- const entries = await generateClientEntries({
183
- config: snapshotConfig,
184
- manifest,
185
- generatedDir,
186
- });
187
-
188
- await ensureCleanDirectory(devClientDir);
189
-
190
- routeAssets = await bundleClientEntries({
191
- entries,
192
- outDir: devClientDir,
193
- dev: true,
194
- publicPrefix: "/__rbssr/client/",
195
- });
107
+ process.once("SIGINT", () => {
108
+ forwardSignal("SIGINT");
109
+ });
196
110
 
197
- currentServerSnapshotDir = snapshotDir;
198
-
199
- const staleVersions = (await listEntries(serverSnapshotsRoot))
200
- .filter(entry => entry.isDirectory && /^v\d+$/.test(entry.name))
201
- .map(entry => entry.name)
202
- .sort((a, b) => {
203
- const aNum = Number(a.slice(1));
204
- const bNum = Number(b.slice(1));
205
- return bNum - aNum;
206
- })
207
- .slice(3);
208
- await Promise.all(staleVersions.map(stale => removePath(path.join(serverSnapshotsRoot, stale))));
209
-
210
- version += 1;
211
- notifyReload();
212
- log(`rebuilt client assets (version ${version})`);
213
- };
111
+ process.once("SIGTERM", () => {
112
+ forwardSignal("SIGTERM");
113
+ });
214
114
 
215
- let rebuildQueue: Promise<void> = Promise.resolve();
216
- const enqueueRebuild = (force = false): Promise<void> => {
217
- const task = rebuildQueue.then(() => rebuildIfNeeded(force));
218
- rebuildQueue = task.catch(error => {
219
- // eslint-disable-next-line no-console
220
- console.error("[rbssr] rebuild failed", error);
115
+ while (true) {
116
+ activeChild = Bun.spawn({
117
+ cmd: ["bun", "--hot", generatedEntryPath],
118
+ cwd,
119
+ stdin: "inherit",
120
+ stdout: "inherit",
121
+ stderr: "inherit",
122
+ env: {
123
+ ...process.env,
124
+ RBSSR_DEV_LAUNCHER: "1",
125
+ RBSSR_DEV_CHILD: "1",
126
+ },
221
127
  });
222
- return task;
223
- };
224
128
 
225
- await enqueueRebuild(true);
129
+ const exitCode = await activeChild.exited;
130
+ activeChild = null;
226
131
 
227
- let rebuildTimer: ReturnType<typeof setTimeout> | undefined;
228
- const scheduleRebuild = (): void => {
229
- if (rebuildTimer) {
230
- clearTimeout(rebuildTimer);
132
+ if (shuttingDown) {
133
+ return;
231
134
  }
232
135
 
233
- rebuildTimer = setTimeout(() => {
234
- rebuildTimer = undefined;
235
- void enqueueRebuild(false);
236
- }, 75);
237
- };
238
-
239
- const watchers: FSWatcher[] = [];
240
- for (const root of watchedRoots) {
241
- try {
242
- const watcher = watch(root, { recursive: true }, () => {
243
- scheduleRebuild();
244
- });
245
- watchers.push(watcher);
246
- } catch {
247
- log(`recursive file watching unavailable for ${root}; relying on request-time rebuild checks`);
136
+ if (exitCode === RBSSR_DEV_RESTART_EXIT_CODE) {
137
+ log("restarting dev child after config change");
138
+ continue;
248
139
  }
249
- }
250
140
 
251
- const cleanup = (): void => {
252
- if (rebuildTimer) {
253
- clearTimeout(rebuildTimer);
254
- rebuildTimer = undefined;
255
- }
256
- for (const watcher of watchers) {
257
- watcher.close();
141
+ if (exitCode !== 0) {
142
+ process.exit(exitCode);
258
143
  }
259
- };
260
-
261
- process.once("SIGINT", () => {
262
- cleanup();
263
- process.exit(0);
264
- });
265
144
 
266
- process.once("SIGTERM", () => {
267
- cleanup();
268
- process.exit(0);
269
- });
270
-
271
- const server = createServer(
272
- {
273
- ...userConfig,
274
- mode: "development",
275
- },
276
- {
277
- dev: true,
278
- getDevAssets: () => routeAssets,
279
- reloadVersion: () => version,
280
- subscribeReload: listener => {
281
- reloadListeners.add(listener);
282
- return () => {
283
- reloadListeners.delete(listener);
284
- };
285
- },
286
- resolvePaths: () => ({
287
- appDir: currentServerSnapshotDir,
288
- routesDir: path.join(currentServerSnapshotDir, "routes"),
289
- rootModule: path.join(currentServerSnapshotDir, "root.tsx"),
290
- middlewareFile: path.join(currentServerSnapshotDir, "middleware.ts"),
291
- }),
292
- onBeforeRequest: () => {
293
- return enqueueRebuild(false);
294
- },
295
- },
296
- );
297
-
298
- const bunServer = Bun.serve({
299
- hostname: resolved.host,
300
- port: resolved.port,
301
- fetch: server.fetch,
302
- development: true,
303
- });
304
-
305
- log(`dev server listening on ${bunServer.url}`);
145
+ return;
146
+ }
306
147
  }
307
148
 
308
149
  export async function runStart(cwd = process.cwd()): Promise<void> {
@@ -328,16 +169,11 @@ function runSubprocess(cmd: string[]): void {
328
169
  }
329
170
 
330
171
  export async function runTypecheck(): Promise<void> {
331
- runSubprocess(["bun", "x", "tsc", "--noEmit"]);
172
+ runSubprocess(createTypecheckCommand());
332
173
  }
333
174
 
334
175
  export async function runTest(extraArgs: string[]): Promise<void> {
335
- if (extraArgs.length > 0) {
336
- runSubprocess(["bun", "test", ...extraArgs]);
337
- return;
176
+ for (const cmd of createTestCommands(extraArgs)) {
177
+ runSubprocess(cmd);
338
178
  }
339
-
340
- runSubprocess(["bun", "test", "./tests/unit"]);
341
- runSubprocess(["bun", "test", "./tests/integration"]);
342
- runSubprocess(["bun", "x", "playwright", "test"]);
343
179
  }