rwsdk 1.0.0-beta.17 → 1.0.0-beta.19

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.
@@ -6,6 +6,7 @@ export * from "../register/worker";
6
6
  export * from "../render/renderToStream";
7
7
  export * from "../render/renderToString";
8
8
  export * from "../requestInfo/types";
9
+ export * from "../requestInfo/utils";
9
10
  export * from "../requestInfo/worker";
10
11
  export * from "../script";
11
12
  export * from "../worker";
@@ -6,6 +6,7 @@ export * from "../register/worker";
6
6
  export * from "../render/renderToStream";
7
7
  export * from "../render/renderToString";
8
8
  export * from "../requestInfo/types";
9
+ export * from "../requestInfo/utils";
9
10
  export * from "../requestInfo/worker";
10
11
  export * from "../script";
11
12
  export * from "../worker";
@@ -1,10 +1,12 @@
1
1
  import { FC, ReactElement } from "react";
2
2
  import { DocumentProps } from "../lib/types.js";
3
+ import { type PartialRequestInfo } from "../requestInfo/types";
3
4
  export interface RenderToStreamOptions {
4
5
  Document?: FC<DocumentProps>;
5
6
  ssr?: boolean;
6
7
  injectRSCPayload?: boolean;
7
8
  onError?: (error: unknown) => void;
9
+ requestInfo?: PartialRequestInfo;
8
10
  }
9
11
  export declare const IdentityDocument: FC<DocumentProps>;
10
- export declare const renderToStream: (element: ReactElement, { ssr: shouldSSR, Document, injectRSCPayload: shouldInjectRSCPayload, onError, }?: RenderToStreamOptions) => Promise<ReadableStream>;
12
+ export declare const renderToStream: (element: ReactElement, { ssr: shouldSSR, Document, injectRSCPayload: shouldInjectRSCPayload, requestInfo: givenRequestInfo, onError, }?: RenderToStreamOptions) => Promise<ReadableStream>;
@@ -1,10 +1,29 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
2
  import { injectRSCPayload } from "rsc-html-stream/server";
3
- import { requestInfo } from "../requestInfo/worker";
3
+ import { constructWithDefaultRequestInfo } from "../requestInfo/utils";
4
+ import { getRequestInfo } from "../requestInfo/worker";
4
5
  import { renderDocumentHtmlStream } from "./renderDocumentHtmlStream";
5
6
  import { renderToRscStream } from "./renderToRscStream";
6
7
  export const IdentityDocument = ({ children }) => (_jsx(_Fragment, { children: children }));
7
- export const renderToStream = async (element, { ssr: shouldSSR = true, Document = IdentityDocument, injectRSCPayload: shouldInjectRSCPayload = true, onError = () => { }, } = {}) => {
8
+ export const renderToStream = async (element, { ssr: shouldSSR = true, Document = IdentityDocument, injectRSCPayload: shouldInjectRSCPayload = true, requestInfo: givenRequestInfo, onError = () => { }, } = {}) => {
9
+ // Try to get the context requestInfo from the async store.
10
+ let contextRequestInfo;
11
+ try {
12
+ contextRequestInfo = getRequestInfo();
13
+ }
14
+ catch (e) {
15
+ // No requestInfo detected from store.
16
+ }
17
+ // Construct requestInfo with defaults where overrides take precedence.
18
+ // If provided, `givenRequestInfo` will override values from context requestInfo if it exists
19
+ const requestInfo = constructWithDefaultRequestInfo({
20
+ ...contextRequestInfo,
21
+ ...givenRequestInfo,
22
+ rw: {
23
+ ...contextRequestInfo?.rw,
24
+ ...givenRequestInfo?.rw,
25
+ },
26
+ });
8
27
  let rscStream = renderToRscStream({
9
28
  input: {
10
29
  node: element,
@@ -1,7 +1,9 @@
1
1
  import { FC, ReactElement } from "react";
2
2
  import { DocumentProps } from "../lib/types.js";
3
+ import { type PartialRequestInfo } from "../requestInfo/types";
3
4
  export interface RenderToStringOptions {
4
5
  Document?: FC<DocumentProps>;
5
6
  injectRSCPayload?: boolean;
7
+ requestInfo?: PartialRequestInfo;
6
8
  }
7
9
  export declare const renderToString: (element: ReactElement, options?: RenderToStringOptions) => Promise<string>;
@@ -12,3 +12,6 @@ export interface RequestInfo<Params = any, AppContext = DefaultAppContext> {
12
12
  };
13
13
  isAction: boolean;
14
14
  }
15
+ export type PartialRequestInfo<Params = any, AppContext = DefaultAppContext> = Omit<Partial<RequestInfo<Params, AppContext>>, "rw"> & {
16
+ rw?: Partial<RwContext>;
17
+ };
@@ -0,0 +1,9 @@
1
+ import { FC } from "react";
2
+ import { type DocumentProps } from "../lib/types";
3
+ import { type PartialRequestInfo, type RequestInfo } from "./types";
4
+ export declare const DefaultRequestInfoDocument: FC<DocumentProps>;
5
+ /**
6
+ * Constructs a generic requestInfo that can be used as defaults.
7
+ * Allows for passing in overrides to initialize with defaults.
8
+ */
9
+ export declare const constructWithDefaultRequestInfo: (overrides?: PartialRequestInfo) => RequestInfo;
@@ -0,0 +1,44 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { generateNonce } from "../lib/utils";
3
+ export const DefaultRequestInfoDocument = ({ children }) => (_jsx(_Fragment, { children: children }));
4
+ /**
5
+ * Constructs a generic requestInfo that can be used as defaults.
6
+ * Allows for passing in overrides to initialize with defaults.
7
+ */
8
+ export const constructWithDefaultRequestInfo = (overrides = {}) => {
9
+ const { rw: rwOverrides, ...otherRequestInfoOverrides } = overrides;
10
+ const defaultRequestInfo = {
11
+ request: new Request("http://localhost/"),
12
+ params: {},
13
+ ctx: {},
14
+ cf: {
15
+ waitUntil: () => { },
16
+ passThroughOnException: () => { },
17
+ props: {},
18
+ },
19
+ response: {
20
+ status: 200,
21
+ headers: new Headers(),
22
+ },
23
+ isAction: false,
24
+ rw: {
25
+ Document: DefaultRequestInfoDocument,
26
+ nonce: generateNonce(),
27
+ rscPayload: true,
28
+ ssr: true,
29
+ databases: new Map(),
30
+ scriptsToBeLoaded: new Set(),
31
+ entryScripts: new Set(),
32
+ inlineScripts: new Set(),
33
+ pageRouteResolved: undefined,
34
+ },
35
+ };
36
+ return {
37
+ ...defaultRequestInfo,
38
+ ...otherRequestInfoOverrides,
39
+ rw: {
40
+ ...defaultRequestInfo.rw,
41
+ ...rwOverrides,
42
+ },
43
+ };
44
+ };
@@ -1,8 +1,9 @@
1
1
  import type { Plugin } from "vite";
2
- export declare function linkWorkerBundle({ code, manifestContent, projectRootDir, }: {
2
+ export declare function linkWorkerBundle({ code, manifestContent, projectRootDir, base, }: {
3
3
  code: string;
4
4
  manifestContent: string;
5
5
  projectRootDir: string;
6
+ base?: string;
6
7
  }): {
7
8
  code: string;
8
9
  map: null;
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { CLIENT_MANIFEST_RELATIVE_PATH } from "../lib/constants.mjs";
5
5
  import { normalizeModulePath } from "../lib/normalizeModulePath.mjs";
6
6
  const log = debug("rwsdk:vite:linker-plugin");
7
- export function linkWorkerBundle({ code, manifestContent, projectRootDir, }) {
7
+ export function linkWorkerBundle({ code, manifestContent, projectRootDir, base, }) {
8
8
  let newCode = code;
9
9
  const manifest = JSON.parse(manifestContent);
10
10
  // 1. Replace the manifest placeholder with the actual manifest content.
@@ -16,7 +16,10 @@ export function linkWorkerBundle({ code, manifestContent, projectRootDir, }) {
16
16
  const normalizedKey = normalizeModulePath(key, projectRootDir, {
17
17
  isViteStyle: false,
18
18
  });
19
- newCode = newCode.replaceAll(`rwsdk_asset:${normalizedKey}`, `/${value.file}`);
19
+ // If base is provided, prepend it with the final hashed path.
20
+ // Base is assumed to have a trailing "/".
21
+ const assetPath = (base ? base : "/") + value.file;
22
+ newCode = newCode.replaceAll(`rwsdk_asset:${normalizedKey}`, assetPath);
20
23
  }
21
24
  // 3. Deprefix any remaining placeholders that were not in the manifest.
22
25
  // This handles public assets that don't go through the bundler.
@@ -28,8 +31,12 @@ export function linkWorkerBundle({ code, manifestContent, projectRootDir, }) {
28
31
  };
29
32
  }
30
33
  export const linkerPlugin = ({ projectRootDir, }) => {
34
+ let config;
31
35
  return {
32
36
  name: "rwsdk:linker",
37
+ configResolved(resolvedConfig) {
38
+ config = resolvedConfig;
39
+ },
33
40
  async renderChunk(code) {
34
41
  if (this.environment.name !== "worker" ||
35
42
  process.env.RWSDK_BUILD_PASS !== "linker") {
@@ -41,6 +48,7 @@ export const linkerPlugin = ({ projectRootDir, }) => {
41
48
  code,
42
49
  manifestContent,
43
50
  projectRootDir,
51
+ base: config.base,
44
52
  });
45
53
  log("Final worker chunk rendered");
46
54
  return result;
@@ -29,6 +29,21 @@ describe("linkWorkerBundle", () => {
29
29
  expect(result.code).toContain(`const stylesheet = "/assets/styles.123.css";`);
30
30
  expect(result.code).toContain(`const logo = "/assets/logo.abc.svg";`);
31
31
  });
32
+ it("should replace asset placeholder with a base + hashed paths from the manifest if base is provided", () => {
33
+ const code = `
34
+ const stylesheet = "rwsdk_asset:/src/styles.css";
35
+ const logo = "rwsdk_asset:/src/logo.svg";
36
+ `;
37
+ const base = "/base/";
38
+ const result = linkWorkerBundle({
39
+ code,
40
+ manifestContent,
41
+ projectRootDir,
42
+ base,
43
+ });
44
+ expect(result.code).toContain(`const stylesheet = "/base/assets/styles.123.css";`);
45
+ expect(result.code).toContain(`const logo = "/base/assets/logo.abc.svg";`);
46
+ });
32
47
  it("should deprefix remaining asset placeholders not in the manifest", () => {
33
48
  const code = `const publicImg = "rwsdk_asset:/images/photo.jpg";`;
34
49
  const result = linkWorkerBundle({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rwsdk",
3
- "version": "1.0.0-beta.17",
3
+ "version": "1.0.0-beta.19",
4
4
  "description": "Build fast, server-driven webapps on Cloudflare with SSR, RSC, and realtime",
5
5
  "type": "module",
6
6
  "bin": {