Skip to content

Commit 66298e9

Browse files
uhyoclaude
andauthored
fix: change default rscPayloadDir to avoid Windows-incompatible colon (#94)
The default value `fun:rsc-payload` contains a colon which is not allowed in file/directory names on Windows, causing build errors. Change to `fun__rsc-payload` which is Windows-safe and still unlikely to collide with user code. Closes #92 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8185d8f commit 66298e9

File tree

13 files changed

+32
-29
lines changed

13 files changed

+32
-29
lines changed

packages/docs/src/pages/advanced/MultipleEntrypoints.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ dist/public/
202202
├── blog/
203203
│ └── post-1.html
204204
├── funstack__/
205-
│ └── fun:rsc-payload/
205+
│ └── fun__rsc-payload/
206206
│ ├── a1b2c3d4.txt # RSC payload for index.html
207207
│ ├── e5f6g7h8.txt # RSC payload for about.html
208208
│ ├── i9j0k1l2.txt # RSC payload for blog/post-1.html

packages/docs/src/pages/api/Defer.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ interface DeferOptions {
6565
```
6666

6767
- **name:** An optional identifier to help with debugging. When provided:
68-
- In development mode, the name is included in the RSC payload file name (e.g., `/funstack__/fun:rsc-payload/HomePage-b5698be72eea3c37`)
68+
- In development mode, the name is included in the RSC payload file name (e.g., `/funstack__/fun__rsc-payload/HomePage-b5698be72eea3c37`)
6969
- In production mode, the name is logged when the payload file is emitted
7070

7171
### Returns
@@ -105,6 +105,6 @@ Using the `name` option makes it easier to identify which deferred component cor
105105

106106
By default, FUNSTACK Static puts the entire app (`<App />`) into one RSC payload (`/funstack__/index.txt`). The client fetches this payload to render your SPA.
107107

108-
When you use `defer(<Component />)`, FUNSTACK Static creates **additional RSC payloads** for the rendering result of the element. This results in an additional emit of RSC payload files like `/funstack__/fun:rsc-payload/b5698be72eea3c37`. If you provide a `name` option, the file name will include it (e.g., `/funstack__/fun:rsc-payload/HomePage-b5698be72eea3c37`).
108+
When you use `defer(<Component />)`, FUNSTACK Static creates **additional RSC payloads** for the rendering result of the element. This results in an additional emit of RSC payload files like `/funstack__/fun__rsc-payload/b5698be72eea3c37`. If you provide a `name` option, the file name will include it (e.g., `/funstack__/fun__rsc-payload/HomePage-b5698be72eea3c37`).
109109

110-
In the main RSC payload, the `defer` call is replaced with a client component `<DeferredComponent moduleId="fun:rsc-payload/b5698be72eea3c37" />`. This component is responsible for fetching the additional RSC payload from client and renders it when it's ready.
110+
In the main RSC payload, the `defer` call is replaced with a client component `<DeferredComponent moduleId="fun__rsc-payload/b5698be72eea3c37" />`. This component is responsible for fetching the additional RSC payload from client and renders it when it's ready.

packages/docs/src/pages/api/FunstackStatic.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -229,19 +229,19 @@ Sentry.init({
229229
### rscPayloadDir (optional)
230230

231231
**Type:** `string`
232-
**Default:** `"fun:rsc-payload"`
232+
**Default:** `"fun__rsc-payload"`
233233

234234
Directory name used for RSC payload files in the build output. The final file paths follow the pattern `/funstack__/{rscPayloadDir}/{hash}.txt`.
235235

236-
Change this if your hosting platform has issues with the default directory name. For example, Cloudflare Workers redirects URLs containing colons to percent-encoded equivalents, adding an extra round trip.
236+
Change this if your hosting platform has issues with the default directory name.
237237

238-
**Important:** The value is used as a marker for string replacement during the build process. Choose a value that is unique enough that it does not appear in your application's source code. The default value `"fun:rsc-payload"` is designed to be unlikely to collide with user code.
238+
**Important:** The value is used as a marker for string replacement during the build process. Choose a value that is unique enough that it does not appear in your application's source code. The default value `"fun__rsc-payload"` is designed to be unlikely to collide with user code.
239239

240240
```typescript
241241
funstackStatic({
242242
root: "./src/root.tsx",
243243
app: "./src/App.tsx",
244-
rscPayloadDir: "fun-rsc-payload", // Avoid colons for Cloudflare Workers
244+
rscPayloadDir: "my-custom-rsc-payload",
245245
});
246246
```
247247

packages/docs/src/pages/learn/HowItWorks.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ dist/public
4545
│ ├── root-DvE5ENz2.css
4646
│ └── rsc-D0fjt5Ie.js
4747
├── funstack__
48-
│ └── fun:rsc-payload
48+
│ └── fun__rsc-payload
4949
│ └── db1923b9b6507ab4.txt
5050
└── index.html
5151
```
5252

53-
The RSC payload files under `funstack__` are loaded by the client-side code to bootstrap the application with server-rendered content. The `fun:rsc-payload` directory name is [configurable](/api/funstack-static#rscpayloaddir-optional) via the `rscPayloadDir` option.
53+
The RSC payload files under `funstack__` are loaded by the client-side code to bootstrap the application with server-rendered content. The `fun__rsc-payload` directory name is [configurable](/api/funstack-static#rscpayloaddir-optional) via the `rscPayloadDir` option.
5454

5555
This can been seen as an **optimized version of traditional client-only SPAs**, where the entire application is bundled into JavaScript files. By using RSC, some of the rendering work is offloaded to the build time, resulting in smaller JavaScript bundles combined with RSC payloads that require less client-side processing (parsing is easier, no JavaScript execution needed).
5656

packages/docs/src/pages/learn/OptimizingPayloads.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Without any optimization, your entire application is rendered into one RSC paylo
88

99
```
1010
dist/public/funstack__/
11-
└── fun:rsc-payload/
11+
└── fun__rsc-payload/
1212
└── b62ec6668fd49300.txt ← Contains everything
1313
```
1414

@@ -75,7 +75,7 @@ After building with route-level `defer()`, your output looks like this:
7575

7676
```
7777
dist/public/funstack__/
78-
└── fun:rsc-payload/
78+
└── fun__rsc-payload/
7979
├── a3f2b1c9d8e7f6a5.txt ← Home page
8080
├── b5698be72eea3c37.txt ← About page
8181
├── b62ec6668fd49300.txt ← Main app shell

packages/static/design/multiple-entries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ dist/public/
477477
├── blog/
478478
│ └── post-1.html # path: "blog/post-1.html"
479479
├── funstack__/
480-
│ └── fun:rsc-payload/
480+
│ └── fun__rsc-payload/
481481
│ ├── a1b2c3d4e5f6g7h8.txt # RSC payload for index.html
482482
│ ├── i9j0k1l2m3n4o5p6.txt # RSC payload for about.html
483483
│ ├── q7r8s9t0u1v2w3x4.txt # RSC payload for blog/post-1.html

packages/static/e2e/tests/build.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ test.describe("Build output verification", () => {
2020
expect(html).toContain("__FUNSTACK_APP_ENTRY__");
2121
// Verify the RSC payload is preloaded
2222
expect(html).toContain('rel="preload"');
23-
expect(html).toContain("funstack__/fun:rsc-payload/");
23+
expect(html).toContain("funstack__/fun__rsc-payload/");
2424
});
2525

2626
test("generates RSC payload files at /funstack__/*.txt", async ({
@@ -32,7 +32,7 @@ test.describe("Build output verification", () => {
3232

3333
// Look for the RSC payload in preload link or FUNSTACK config
3434
const rscPayloadMatch = html.match(
35-
/funstack__\/fun:rsc-payload\/[^"'\s]+\.txt/,
35+
/funstack__\/fun__rsc-payload\/[^"'\s]+\.txt/,
3636
);
3737
expect(rscPayloadMatch).not.toBeNull();
3838

packages/static/e2e/tests/hydration.spec.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ test.describe("Client-side hydration", () => {
6262

6363
page.on("request", (request) => {
6464
const url = request.url();
65-
if (url.includes("funstack__/fun:rsc-payload/") && url.endsWith(".txt")) {
65+
if (
66+
url.includes("funstack__/fun__rsc-payload/") &&
67+
url.endsWith(".txt")
68+
) {
6669
rscRequests.push(url);
6770
}
6871
});

packages/static/e2e/tests/multi-entry.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ test.describe("Multi-entry build output", () => {
1111
expect(html).toContain("<!DOCTYPE html>");
1212
expect(html).toContain("<html");
1313
expect(html).toContain("__FUNSTACK_APP_ENTRY__");
14-
expect(html).toContain("funstack__/fun:rsc-payload/");
14+
expect(html).toContain("funstack__/fun__rsc-payload/");
1515
});
1616

1717
test("generates about.html with expected HTML structure", async ({
@@ -24,7 +24,7 @@ test.describe("Multi-entry build output", () => {
2424
expect(html).toContain("<!DOCTYPE html>");
2525
expect(html).toContain("<html");
2626
expect(html).toContain("__FUNSTACK_APP_ENTRY__");
27-
expect(html).toContain("funstack__/fun:rsc-payload/");
27+
expect(html).toContain("funstack__/fun__rsc-payload/");
2828
});
2929

3030
test("each page has its own RSC payload", async ({ request }) => {
@@ -36,10 +36,10 @@ test.describe("Multi-entry build output", () => {
3636

3737
// Both pages should reference RSC payloads
3838
const homePayloadMatch = homeHtml.match(
39-
/funstack__\/fun:rsc-payload\/[^"'\s]+\.txt/,
39+
/funstack__\/fun__rsc-payload\/[^"'\s]+\.txt/,
4040
);
4141
const aboutPayloadMatch = aboutHtml.match(
42-
/funstack__\/fun:rsc-payload\/[^"'\s]+\.txt/,
42+
/funstack__\/fun__rsc-payload\/[^"'\s]+\.txt/,
4343
);
4444

4545
expect(homePayloadMatch).not.toBeNull();

packages/static/src/build/dependencyGraph.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ describe("findReferencedIds", () => {
3030
});
3131

3232
it("finds IDs with special characters", () => {
33-
const content = "Reference to fun:rsc-payload/abc-123 here";
33+
const content = "Reference to fun__rsc-payload/abc-123 here";
3434
const allKnownIds = new Set([
35-
"fun:rsc-payload/abc-123",
36-
"fun:rsc-payload/def-456",
35+
"fun__rsc-payload/abc-123",
36+
"fun__rsc-payload/def-456",
3737
]);
3838

3939
const result = findReferencedIds(content, allKnownIds);
4040

41-
expect(result).toEqual(new Set(["fun:rsc-payload/abc-123"]));
41+
expect(result).toEqual(new Set(["fun__rsc-payload/abc-123"]));
4242
});
4343
});
4444

0 commit comments

Comments
 (0)