rwsdk 0.2.0-alpha.12 → 0.2.0-alpha.14
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/dist/runtime/client/client.d.ts +10 -0
- package/dist/runtime/{client.js → client/client.js} +13 -10
- package/dist/runtime/{clientNavigation.test.js → client/navigation.test.js} +1 -1
- package/dist/runtime/client/setWebpackRequire.d.ts +1 -0
- package/dist/runtime/client/setWebpackRequire.js +2 -0
- package/dist/runtime/{client.d.ts → client/types.d.ts} +4 -10
- package/dist/runtime/client/types.js +1 -0
- package/dist/runtime/entries/client.d.ts +2 -2
- package/dist/runtime/entries/client.js +2 -2
- package/dist/runtime/imports/client.d.ts +3 -3
- package/dist/runtime/imports/client.js +6 -5
- package/dist/runtime/imports/ssr.d.ts +3 -3
- package/dist/runtime/imports/ssr.js +3 -3
- package/dist/runtime/imports/worker.d.ts +3 -3
- package/dist/runtime/imports/worker.js +3 -3
- package/dist/runtime/lib/manifest.d.ts +11 -2
- package/dist/runtime/lib/manifest.js +1 -1
- package/dist/runtime/lib/memoizeOnId.d.ts +1 -0
- package/dist/runtime/lib/memoizeOnId.js +11 -0
- package/dist/runtime/lib/realtime/client.d.ts +1 -1
- package/dist/runtime/lib/realtime/client.js +1 -1
- package/dist/runtime/register/ssr.d.ts +1 -1
- package/dist/runtime/register/ssr.js +2 -2
- package/dist/runtime/render/preloads.d.ts +6 -0
- package/dist/runtime/render/preloads.js +40 -0
- package/dist/runtime/render/renderRscThenableToHtmlStream.js +2 -1
- package/dist/runtime/render/stylesheets.js +1 -1
- package/dist/runtime/worker.js +1 -1
- package/dist/scripts/debug-sync.mjs +115 -36
- package/dist/vite/miniflareHMRPlugin.mjs +17 -2
- package/package.json +1 -1
- /package/dist/runtime/{imports → client}/ClientOnly.d.ts +0 -0
- /package/dist/runtime/{imports → client}/ClientOnly.js +0 -0
- /package/dist/runtime/{clientNavigation.d.ts → client/navigation.d.ts} +0 -0
- /package/dist/runtime/{clientNavigation.js → client/navigation.js} +0 -0
- /package/dist/runtime/{clientNavigation.test.d.ts → client/navigation.test.d.ts} +0 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import "./setWebpackRequire";
|
|
2
|
+
export { ClientOnly } from "./ClientOnly.js";
|
|
3
|
+
export { default as React } from "react";
|
|
4
|
+
import type { Transport, HydrationOptions } from "./types";
|
|
5
|
+
export declare const fetchTransport: Transport;
|
|
6
|
+
export declare const initClient: ({ transport, hydrateRootOptions, handleResponse, }?: {
|
|
7
|
+
transport?: Transport;
|
|
8
|
+
hydrateRootOptions?: HydrationOptions;
|
|
9
|
+
handleResponse?: (response: Response) => boolean;
|
|
10
|
+
}) => Promise<void>;
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
|
|
2
|
+
// note(justinvdm, 14 Aug 2025): Rendering related imports and logic go here.
|
|
3
|
+
// See client.tsx for the actual client entrypoint.
|
|
4
|
+
// context(justinvdm, 14 Aug 2025): `react-server-dom-webpack` uses this global
|
|
5
|
+
// to load modules, so we need to define it here before importing
|
|
6
|
+
// "react-server-dom-webpack."
|
|
7
|
+
import "./setWebpackRequire";
|
|
8
|
+
import React from "react";
|
|
9
|
+
import { hydrateRoot } from "react-dom/client";
|
|
10
|
+
import { createFromReadableStream, createFromFetch, encodeReply, } from "react-server-dom-webpack/client.browser";
|
|
11
|
+
import { rscStream } from "rsc-html-stream/client";
|
|
12
|
+
export { ClientOnly } from "./ClientOnly.js";
|
|
13
|
+
export { default as React } from "react";
|
|
6
14
|
export const fetchTransport = (transportContext) => {
|
|
7
15
|
const fetchCallServer = async (id, args) => {
|
|
8
|
-
const { createFromFetch, encodeReply } = await import("react-server-dom-webpack/client.browser");
|
|
9
16
|
const url = new URL(window.location.href);
|
|
10
17
|
url.searchParams.set("__rsc", "");
|
|
11
18
|
if (id != null) {
|
|
@@ -41,8 +48,6 @@ export const fetchTransport = (transportContext) => {
|
|
|
41
48
|
return fetchCallServer;
|
|
42
49
|
};
|
|
43
50
|
export const initClient = async ({ transport = fetchTransport, hydrateRootOptions, handleResponse, } = {}) => {
|
|
44
|
-
const React = await import("react");
|
|
45
|
-
const { hydrateRoot } = await import("react-dom/client");
|
|
46
51
|
const transportContext = {
|
|
47
52
|
setRscPayload: () => { },
|
|
48
53
|
handleResponse,
|
|
@@ -50,7 +55,7 @@ export const initClient = async ({ transport = fetchTransport, hydrateRootOption
|
|
|
50
55
|
let transportCallServer = transport(transportContext);
|
|
51
56
|
const callServer = (id, args) => transportCallServer(id, args);
|
|
52
57
|
const upgradeToRealtime = async ({ key } = {}) => {
|
|
53
|
-
const { realtimeTransport } = await import("
|
|
58
|
+
const { realtimeTransport } = await import("../lib/realtime/client");
|
|
54
59
|
const createRealtimeTransport = realtimeTransport({ key });
|
|
55
60
|
transportCallServer = createRealtimeTransport(transportContext);
|
|
56
61
|
};
|
|
@@ -67,8 +72,6 @@ export const initClient = async ({ transport = fetchTransport, hydrateRootOption
|
|
|
67
72
|
// context(justinvdm, 18 Jun 2025): We inject the RSC payload
|
|
68
73
|
// unless render(Document, [...], { rscPayload: false }) was used.
|
|
69
74
|
if (globalThis.__FLIGHT_DATA) {
|
|
70
|
-
const { createFromReadableStream } = await import("react-server-dom-webpack/client.browser");
|
|
71
|
-
const { rscStream } = await import("rsc-html-stream/client");
|
|
72
75
|
rscPayload = createFromReadableStream(rscStream, {
|
|
73
76
|
callServer,
|
|
74
77
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,19 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import type { CallServerCallback } from "react-server-dom-webpack/client.browser";
|
|
2
|
+
export type { CallServerCallback } from "react-server-dom-webpack/client.browser";
|
|
3
|
+
export type { HydrationOptions } from "react-dom/client";
|
|
3
4
|
export type ActionResponse<Result> = {
|
|
4
5
|
node: React.ReactNode;
|
|
5
6
|
actionResult: Result;
|
|
6
7
|
};
|
|
7
|
-
type TransportContext = {
|
|
8
|
+
export type TransportContext = {
|
|
8
9
|
setRscPayload: <Result>(v: Promise<ActionResponse<Result>>) => void;
|
|
9
10
|
handleResponse?: (response: Response) => boolean;
|
|
10
11
|
};
|
|
11
12
|
export type Transport = (context: TransportContext) => CallServerCallback;
|
|
12
13
|
export type CreateCallServer = (context: TransportContext) => <Result>(id: null | string, args: null | unknown[]) => Promise<Result>;
|
|
13
|
-
export declare const fetchTransport: Transport;
|
|
14
|
-
export declare const initClient: ({ transport, hydrateRootOptions, handleResponse, }?: {
|
|
15
|
-
transport?: Transport;
|
|
16
|
-
hydrateRootOptions?: HydrationOptions;
|
|
17
|
-
handleResponse?: (response: Response) => boolean;
|
|
18
|
-
}) => Promise<void>;
|
|
19
|
-
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const loadModule: (
|
|
2
|
-
export declare const clientWebpackRequire: (
|
|
1
|
+
export declare const loadModule: (id: string) => Promise<any>;
|
|
2
|
+
export declare const clientWebpackRequire: (id: string) => Promise<{
|
|
3
3
|
[x: string]: any;
|
|
4
|
-
}
|
|
4
|
+
}>;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import { ClientOnly } from "../client/client";
|
|
3
|
+
import { memoizeOnId } from "../lib/memoizeOnId";
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import { useClientLookup } from "virtual:use-client-lookup.js";
|
|
6
|
+
export const loadModule = memoizeOnId(async (id) => {
|
|
4
7
|
if (import.meta.env.VITE_IS_DEV_SERVER) {
|
|
5
8
|
return await import(/* @vite-ignore */ id);
|
|
6
9
|
}
|
|
7
10
|
else {
|
|
8
|
-
const { useClientLookup } = await import("virtual:use-client-lookup.js");
|
|
9
11
|
const moduleFn = useClientLookup[id];
|
|
10
12
|
if (!moduleFn) {
|
|
11
13
|
throw new Error(`(client) No module found for '${id}' in module lookup for "use client" directive`);
|
|
@@ -14,7 +16,7 @@ export const loadModule = memoize(async (id) => {
|
|
|
14
16
|
}
|
|
15
17
|
});
|
|
16
18
|
// context(justinvdm, 2 Dec 2024): re memoize(): React relies on the same promise instance being returned for the same id
|
|
17
|
-
export const clientWebpackRequire =
|
|
19
|
+
export const clientWebpackRequire = memoizeOnId(async (id) => {
|
|
18
20
|
const [file, name] = id.split("#");
|
|
19
21
|
const promisedModule = loadModule(file);
|
|
20
22
|
const promisedComponent = promisedModule.then((module) => module[name]);
|
|
@@ -23,7 +25,6 @@ export const clientWebpackRequire = memoize(async (id) => {
|
|
|
23
25
|
const awaitedComponent = await promisedComponent;
|
|
24
26
|
return { [id]: awaitedComponent };
|
|
25
27
|
}
|
|
26
|
-
const { ClientOnly } = await import("./ClientOnly");
|
|
27
28
|
const promisedDefault = promisedComponent.then((Component) => ({
|
|
28
29
|
default: Component,
|
|
29
30
|
}));
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const ssrLoadModule: (
|
|
1
|
+
export declare const ssrLoadModule: (id: string) => Promise<any>;
|
|
2
2
|
export declare const ssrGetModuleExport: (id: string) => Promise<any>;
|
|
3
|
-
export declare const ssrWebpackRequire: (
|
|
3
|
+
export declare const ssrWebpackRequire: (id: string) => Promise<{
|
|
4
4
|
[x: string]: any;
|
|
5
|
-
}
|
|
5
|
+
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
export const ssrLoadModule =
|
|
1
|
+
import { memoizeOnId } from "../lib/memoizeOnId";
|
|
2
|
+
export const ssrLoadModule = memoizeOnId(async (id) => {
|
|
3
3
|
const { useClientLookup } = await import("virtual:use-client-lookup.js");
|
|
4
4
|
const moduleFn = useClientLookup[id];
|
|
5
5
|
if (!moduleFn) {
|
|
@@ -13,7 +13,7 @@ export const ssrGetModuleExport = async (id) => {
|
|
|
13
13
|
return module[name];
|
|
14
14
|
};
|
|
15
15
|
// context(justinvdm, 2 Dec 2024): re memoize(): React relies on the same promise instance being returned for the same id
|
|
16
|
-
export const ssrWebpackRequire =
|
|
16
|
+
export const ssrWebpackRequire = memoizeOnId(async (id) => {
|
|
17
17
|
const [file, name] = id.split("#");
|
|
18
18
|
const module = await ssrLoadModule(file);
|
|
19
19
|
return { [id]: module[name] };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare const loadServerModule: (
|
|
1
|
+
export declare const loadServerModule: (id: string) => Promise<any>;
|
|
2
2
|
export declare const getServerModuleExport: (id: string) => Promise<any>;
|
|
3
|
-
export declare const ssrWebpackRequire: (
|
|
3
|
+
export declare const ssrWebpackRequire: (id: string) => Promise<{
|
|
4
4
|
[x: string]: any;
|
|
5
|
-
}
|
|
5
|
+
}>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import memoize from "lodash/memoize";
|
|
2
1
|
import { requestInfo } from "../requestInfo/worker";
|
|
3
2
|
import { ssrWebpackRequire as baseSsrWebpackRequire } from "rwsdk/__ssr_bridge";
|
|
4
|
-
|
|
3
|
+
import { memoizeOnId } from "../lib/memoizeOnId";
|
|
4
|
+
export const loadServerModule = memoizeOnId(async (id) => {
|
|
5
5
|
const { useServerLookup } = await import("virtual:use-server-lookup.js");
|
|
6
6
|
const moduleFn = useServerLookup[id];
|
|
7
7
|
if (!moduleFn) {
|
|
@@ -14,7 +14,7 @@ export const getServerModuleExport = async (id) => {
|
|
|
14
14
|
const module = await loadServerModule(file);
|
|
15
15
|
return module[name];
|
|
16
16
|
};
|
|
17
|
-
export const ssrWebpackRequire =
|
|
17
|
+
export const ssrWebpackRequire = memoizeOnId(async (id) => {
|
|
18
18
|
if (!requestInfo.rw.ssr) {
|
|
19
19
|
return { [id]: () => null };
|
|
20
20
|
}
|
|
@@ -1,2 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
export
|
|
1
|
+
export type Manifest = Record<string, ManifestChunk>;
|
|
2
|
+
export interface ManifestChunk {
|
|
3
|
+
file: string;
|
|
4
|
+
src?: string;
|
|
5
|
+
isEntry?: boolean;
|
|
6
|
+
isDynamicEntry?: boolean;
|
|
7
|
+
imports?: string[];
|
|
8
|
+
css?: string[];
|
|
9
|
+
assets?: string[];
|
|
10
|
+
}
|
|
11
|
+
export declare const getManifest: () => Promise<Manifest>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const memoizeOnId: <Result>(fn: (id: string) => Result) => (id: string) => Result;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const memoizeOnId = (fn) => {
|
|
2
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
3
|
+
const results = {};
|
|
4
|
+
const memoizedFn = (id) => {
|
|
5
|
+
if (hasOwnProperty.call(results, id)) {
|
|
6
|
+
return results[id];
|
|
7
|
+
}
|
|
8
|
+
return (results[id] = fn(id));
|
|
9
|
+
};
|
|
10
|
+
return memoizedFn;
|
|
11
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { initClient } from "../../client";
|
|
1
|
+
import { initClient } from "../../client/client";
|
|
2
2
|
import { createFromReadableStream } from "react-server-dom-webpack/client.browser";
|
|
3
3
|
import { MESSAGE_TYPE } from "./shared";
|
|
4
4
|
import { packMessage, unpackMessage, } from "./protocol";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const loadServerModule: (
|
|
1
|
+
export declare const loadServerModule: (id: string) => Promise<any>;
|
|
2
2
|
export declare const getServerModuleExport: (id: string) => Promise<any>;
|
|
3
3
|
export declare const createServerReference: (id: string, name: string) => any;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import memoize from "lodash/memoize";
|
|
2
1
|
import { createServerReference as baseCreateServerReference } from "react-server-dom-webpack/client.edge";
|
|
3
|
-
|
|
2
|
+
import { memoizeOnId } from "../lib/memoizeOnId";
|
|
3
|
+
export const loadServerModule = memoizeOnId(async (id) => {
|
|
4
4
|
const { useServerLookup } = await import("virtual:use-server-lookup.js");
|
|
5
5
|
const moduleFn = useServerLookup[id];
|
|
6
6
|
if (!moduleFn) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { RequestInfo } from "../requestInfo/types.js";
|
|
2
|
+
import type { Manifest, ManifestChunk } from "../lib/manifest.js";
|
|
3
|
+
export declare function findScriptForModule(id: string, manifest: Manifest): ManifestChunk | undefined;
|
|
4
|
+
export declare const Preloads: ({ requestInfo }: {
|
|
5
|
+
requestInfo: RequestInfo;
|
|
6
|
+
}) => import("react/jsx-runtime.js").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { use } from "react";
|
|
3
|
+
import { getManifest } from "../lib/manifest.js";
|
|
4
|
+
export function findScriptForModule(id, manifest) {
|
|
5
|
+
const visited = new Set();
|
|
6
|
+
function find(id) {
|
|
7
|
+
if (visited.has(id)) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
visited.add(id);
|
|
11
|
+
const manifestEntry = manifest[id];
|
|
12
|
+
if (!manifestEntry) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (manifestEntry.isEntry || manifestEntry.isDynamicEntry) {
|
|
16
|
+
return manifestEntry;
|
|
17
|
+
}
|
|
18
|
+
if (manifestEntry.imports) {
|
|
19
|
+
for (const dep of manifestEntry.imports) {
|
|
20
|
+
const entry = find(dep);
|
|
21
|
+
if (entry) {
|
|
22
|
+
return entry;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
return find(id);
|
|
29
|
+
}
|
|
30
|
+
export const Preloads = ({ requestInfo }) => {
|
|
31
|
+
const manifest = use(getManifest());
|
|
32
|
+
const allScripts = new Set();
|
|
33
|
+
for (const scriptId of requestInfo.rw.scriptsToBeLoaded) {
|
|
34
|
+
const script = findScriptForModule(scriptId, manifest);
|
|
35
|
+
if (script) {
|
|
36
|
+
allScripts.add(script.file);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return (_jsx(_Fragment, { children: Array.from(allScripts).map((href) => (_jsx("link", { rel: "modulepreload", href: href }, href))) }));
|
|
40
|
+
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { use } from "react";
|
|
3
3
|
import { renderToReadableStream } from "react-dom/server.edge";
|
|
4
|
+
import { Preloads } from "./preloads.js";
|
|
4
5
|
import { Stylesheets } from "./stylesheets.js";
|
|
5
6
|
export const renderRscThenableToHtmlStream = async ({ thenable, Document, requestInfo, shouldSSR, onError, }) => {
|
|
6
7
|
const Component = () => {
|
|
7
8
|
const RscApp = () => {
|
|
8
9
|
const node = use(thenable).node;
|
|
9
|
-
return (_jsxs(_Fragment, { children: [_jsx(Stylesheets, { requestInfo: requestInfo }), _jsx("div", { id: "hydrate-root", children: node })] }));
|
|
10
|
+
return (_jsxs(_Fragment, { children: [_jsx(Stylesheets, { requestInfo: requestInfo }), _jsx(Preloads, { requestInfo: requestInfo }), _jsx("div", { id: "hydrate-root", children: node })] }));
|
|
10
11
|
};
|
|
11
12
|
// todo(justinvdm, 18 Jun 2025): We can build on this later to allow users
|
|
12
13
|
// surface context. e.g:
|
|
@@ -23,7 +23,7 @@ const findCssForModule = (scriptId, manifest) => {
|
|
|
23
23
|
return Array.from(css);
|
|
24
24
|
};
|
|
25
25
|
export const Stylesheets = ({ requestInfo }) => {
|
|
26
|
-
const manifest = use(getManifest(
|
|
26
|
+
const manifest = use(getManifest());
|
|
27
27
|
const allStylesheets = new Set();
|
|
28
28
|
for (const scriptId of requestInfo.rw.scriptsToBeLoaded) {
|
|
29
29
|
const css = findCssForModule(scriptId, manifest);
|
package/dist/runtime/worker.js
CHANGED
|
@@ -24,15 +24,50 @@ const getPackageManagerInfo = (targetDir) => {
|
|
|
24
24
|
}
|
|
25
25
|
return pnpmResult;
|
|
26
26
|
};
|
|
27
|
+
const cleanupViteEntries = async (targetDir) => {
|
|
28
|
+
const nodeModulesDir = path.join(targetDir, "node_modules");
|
|
29
|
+
if (!existsSync(nodeModulesDir)) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const entries = await fs.readdir(nodeModulesDir);
|
|
34
|
+
const viteEntries = entries.filter((entry) => entry.startsWith(".vite"));
|
|
35
|
+
for (const entry of viteEntries) {
|
|
36
|
+
const entryPath = path.join(nodeModulesDir, entry);
|
|
37
|
+
try {
|
|
38
|
+
const stat = await fs.lstat(entryPath);
|
|
39
|
+
if (!stat.isSymbolicLink()) {
|
|
40
|
+
console.log(`Removing vite cache entry: ${entry}`);
|
|
41
|
+
await fs.rm(entryPath, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
console.log(`Skipping symlinked vite cache entry: ${entry}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// If we can't stat it, try to remove it
|
|
49
|
+
console.log(`Removing vite cache entry: ${entry}`);
|
|
50
|
+
await fs.rm(entryPath, { recursive: true, force: true });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
console.log(`Failed to cleanup vite cache entries: ${error}`);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
27
58
|
const performFullSync = async (sdkDir, targetDir) => {
|
|
28
59
|
const sdkPackageJsonPath = path.join(sdkDir, "package.json");
|
|
29
60
|
let originalSdkPackageJson = null;
|
|
30
61
|
let tarballPath = "";
|
|
31
62
|
let tarballName = "";
|
|
63
|
+
// Clean up vite cache
|
|
64
|
+
await cleanupViteEntries(targetDir);
|
|
32
65
|
try {
|
|
33
66
|
console.log("📦 Packing SDK...");
|
|
34
|
-
const packResult = await $({ cwd: sdkDir }) `npm pack`;
|
|
35
|
-
|
|
67
|
+
const packResult = await $({ cwd: sdkDir }) `npm pack --json`;
|
|
68
|
+
const json = JSON.parse(packResult.stdout || "[]");
|
|
69
|
+
const packInfo = Array.isArray(json) ? json[0] : undefined;
|
|
70
|
+
tarballName = (packInfo && (packInfo.filename || packInfo.name)) || "";
|
|
36
71
|
if (!tarballName) {
|
|
37
72
|
console.error("❌ Failed to get tarball name from npm pack.");
|
|
38
73
|
return;
|
|
@@ -86,23 +121,63 @@ const performFullSync = async (sdkDir, targetDir) => {
|
|
|
86
121
|
}
|
|
87
122
|
}
|
|
88
123
|
};
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
124
|
+
const syncFilesWithRsyncOrFs = async (sdkDir, destDir, filesEntries) => {
|
|
125
|
+
const sources = filesEntries.map((p) => path.join(sdkDir, p));
|
|
126
|
+
// Always include package.json in sync
|
|
127
|
+
const pkgJsonPath = path.join(sdkDir, "package.json");
|
|
128
|
+
sources.push(pkgJsonPath);
|
|
129
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
130
|
+
// Try rsync across all sources in one shot
|
|
131
|
+
try {
|
|
132
|
+
if (sources.length > 0) {
|
|
133
|
+
const rsyncArgs = [
|
|
134
|
+
"-a",
|
|
135
|
+
"--delete",
|
|
136
|
+
"--omit-dir-times",
|
|
137
|
+
"--no-perms",
|
|
138
|
+
"--no-owner",
|
|
139
|
+
"--no-group",
|
|
140
|
+
...sources,
|
|
141
|
+
destDir + path.sep,
|
|
142
|
+
];
|
|
143
|
+
await $({ stdio: "inherit" })("rsync", rsyncArgs);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// fall through to fs fallback
|
|
149
|
+
}
|
|
150
|
+
console.log("Rsync failed, falling back to fs");
|
|
151
|
+
// Fallback: destructive copy using Node fs to mirror content
|
|
152
|
+
await fs.rm(destDir, { recursive: true, force: true });
|
|
153
|
+
await fs.mkdir(destDir, { recursive: true });
|
|
154
|
+
for (const src of sources) {
|
|
155
|
+
const rel = path.relative(sdkDir, src);
|
|
156
|
+
const dst = path.join(destDir, rel);
|
|
157
|
+
await fs.mkdir(path.dirname(dst), { recursive: true });
|
|
158
|
+
try {
|
|
159
|
+
const stat = await fs.lstat(src);
|
|
160
|
+
if (stat.isDirectory()) {
|
|
161
|
+
await fs.cp(src, dst, { recursive: true, force: true });
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
await fs.copyFile(src, dst);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
await fs.cp(src, dst, { recursive: true, force: true }).catch(() => { });
|
|
98
169
|
}
|
|
99
170
|
}
|
|
100
|
-
// Always copy package.json
|
|
101
|
-
await fs.copyFile(path.join(sdkDir, "package.json"), path.join(targetDir, "node_modules/rwsdk/package.json"));
|
|
102
171
|
};
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
172
|
+
const performFastSync = async (sdkDir, targetDir) => {
|
|
173
|
+
console.log("⚡️ No dependency changes, performing fast sync...");
|
|
174
|
+
// Clean up vite cache
|
|
175
|
+
await cleanupViteEntries(targetDir);
|
|
176
|
+
const nodeModulesPkgDir = path.join(targetDir, "node_modules", "rwsdk");
|
|
177
|
+
// Copy directories/files declared in package.json#files (plus package.json)
|
|
178
|
+
const filesToSync = JSON.parse(await fs.readFile(path.join(sdkDir, "package.json"), "utf-8"))
|
|
179
|
+
.files || [];
|
|
180
|
+
await syncFilesWithRsyncOrFs(sdkDir, nodeModulesPkgDir, filesToSync);
|
|
106
181
|
};
|
|
107
182
|
const performSync = async (sdkDir, targetDir) => {
|
|
108
183
|
console.log("🏗️ Rebuilding SDK...");
|
|
@@ -120,13 +195,8 @@ const performSync = async (sdkDir, targetDir) => {
|
|
|
120
195
|
if (existsSync(installedSdkPackageJsonPath)) {
|
|
121
196
|
const sdkPackageJsonContent = await fs.readFile(sdkPackageJsonPath, "utf-8");
|
|
122
197
|
const installedSdkPackageJsonContent = await fs.readFile(installedSdkPackageJsonPath, "utf-8");
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (areDependenciesEqual(sdkPkg.dependencies, installedPkg.dependencies) &&
|
|
126
|
-
areDependenciesEqual(sdkPkg.devDependencies, installedPkg.devDependencies) &&
|
|
127
|
-
areDependenciesEqual(sdkPkg.peerDependencies, installedPkg.peerDependencies)) {
|
|
128
|
-
packageJsonChanged = false;
|
|
129
|
-
}
|
|
198
|
+
packageJsonChanged =
|
|
199
|
+
sdkPackageJsonContent !== installedSdkPackageJsonContent;
|
|
130
200
|
}
|
|
131
201
|
if (packageJsonChanged) {
|
|
132
202
|
console.log("📦 package.json changed, performing full sync...");
|
|
@@ -198,20 +268,19 @@ export const debugSync = async (opts) => {
|
|
|
198
268
|
cwd: sdkDir,
|
|
199
269
|
});
|
|
200
270
|
let syncing = false;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if (syncing || filePath.endsWith(".tgz")) {
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
if (expectingFileChanges && process.env.RWSDK_FORCE_FULL_SYNC) {
|
|
209
|
-
expectingFileChanges = false;
|
|
271
|
+
let pendingResync = false;
|
|
272
|
+
const triggerResync = async (reason) => {
|
|
273
|
+
if (syncing) {
|
|
274
|
+
pendingResync = true;
|
|
210
275
|
return;
|
|
211
276
|
}
|
|
212
277
|
syncing = true;
|
|
213
|
-
|
|
214
|
-
|
|
278
|
+
if (reason) {
|
|
279
|
+
console.log(`\nDetected change, re-syncing... (file: ${reason})`);
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
console.log(`\nDetected change, re-syncing...`);
|
|
283
|
+
}
|
|
215
284
|
if (childProc && !childProc.killed) {
|
|
216
285
|
console.log("Stopping running process...");
|
|
217
286
|
childProc.kill();
|
|
@@ -220,7 +289,6 @@ export const debugSync = async (opts) => {
|
|
|
220
289
|
});
|
|
221
290
|
}
|
|
222
291
|
try {
|
|
223
|
-
watcher.unwatch(filesToWatch);
|
|
224
292
|
await performSync(sdkDir, targetDir);
|
|
225
293
|
runWatchedCommand();
|
|
226
294
|
}
|
|
@@ -230,8 +298,19 @@ export const debugSync = async (opts) => {
|
|
|
230
298
|
}
|
|
231
299
|
finally {
|
|
232
300
|
syncing = false;
|
|
233
|
-
watcher.add(filesToWatch);
|
|
234
301
|
}
|
|
302
|
+
if (pendingResync) {
|
|
303
|
+
pendingResync = false;
|
|
304
|
+
// Coalesce any rapid additional events into a single follow-up sync
|
|
305
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
306
|
+
return triggerResync();
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
watcher.on("all", async (_event, filePath) => {
|
|
310
|
+
if (filePath.endsWith(".tgz")) {
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
await triggerResync(filePath);
|
|
235
314
|
});
|
|
236
315
|
const cleanup = async () => {
|
|
237
316
|
console.log("\nCleaning up...");
|
|
@@ -66,6 +66,9 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
66
66
|
};
|
|
67
67
|
},
|
|
68
68
|
async hotUpdate(ctx) {
|
|
69
|
+
if (ctx.file.includes(".wrangler")) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
69
72
|
if (hasErrored) {
|
|
70
73
|
const shortName = getShortName(ctx.file, ctx.server.config.root);
|
|
71
74
|
this.environment.logger.info(`${colors.cyan(`attempting to recover from error`)}: update to ${colors.dim(shortName)}`, {
|
|
@@ -77,6 +80,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
77
80
|
type: "full-reload",
|
|
78
81
|
path: "*",
|
|
79
82
|
});
|
|
83
|
+
log("hmr: Full reload after error");
|
|
80
84
|
return [];
|
|
81
85
|
}
|
|
82
86
|
const { clientFiles, serverFiles, viteEnvironment: { name: environment }, workerEntryPathname: entry, } = givenOptions;
|
|
@@ -84,6 +88,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
84
88
|
log(`Hot update: (env=${this.environment.name}) ${ctx.file}\nModule graph:\n\n${dumpFullModuleGraph(ctx.server, this.environment.name)}`);
|
|
85
89
|
}
|
|
86
90
|
if (!isJsFile(ctx.file) && !ctx.file.endsWith(".css")) {
|
|
91
|
+
log(`hmr: not a js file, skipping`);
|
|
87
92
|
return;
|
|
88
93
|
}
|
|
89
94
|
if (this.environment.name === "ssr") {
|
|
@@ -94,14 +99,17 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
94
99
|
server: ctx.server,
|
|
95
100
|
});
|
|
96
101
|
if (!isUseClientUpdate) {
|
|
102
|
+
log("hmr: not a use client update, short circuiting");
|
|
97
103
|
return [];
|
|
98
104
|
}
|
|
99
105
|
invalidateModule(ctx.server, "ssr", ctx.file);
|
|
100
106
|
invalidateModule(ctx.server, environment, VIRTUAL_SSR_PREFIX +
|
|
101
107
|
normalizeModulePath(ctx.file, givenOptions.rootDir));
|
|
108
|
+
log("hmr: invalidated ssr module");
|
|
102
109
|
return [];
|
|
103
110
|
}
|
|
104
111
|
if (!["client", environment].includes(this.environment.name)) {
|
|
112
|
+
log(`hmr: incorrect env, skipping (env=${this.environment.name}, worker env=${environment})`);
|
|
105
113
|
return [];
|
|
106
114
|
}
|
|
107
115
|
const hasClientDirective = await hasDirective(ctx.file, "use client");
|
|
@@ -165,8 +173,10 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
165
173
|
server: ctx.server,
|
|
166
174
|
});
|
|
167
175
|
if (!isUseClientUpdate && !ctx.file.endsWith(".css")) {
|
|
176
|
+
log("hmr: not a use client update and not css, short circuiting");
|
|
168
177
|
return [];
|
|
169
178
|
}
|
|
179
|
+
log("hmr: returning client modules for hmr");
|
|
170
180
|
return ctx.modules;
|
|
171
181
|
}
|
|
172
182
|
// The worker needs an update, and the hot check is for the worker environment
|
|
@@ -184,8 +194,12 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
184
194
|
if (m) {
|
|
185
195
|
invalidateModule(ctx.server, environment, m);
|
|
186
196
|
}
|
|
187
|
-
|
|
188
|
-
normalizeModulePath(ctx.file, givenOptions.rootDir)
|
|
197
|
+
let virtualSSRModuleId = VIRTUAL_SSR_PREFIX +
|
|
198
|
+
normalizeModulePath(ctx.file, givenOptions.rootDir);
|
|
199
|
+
if (ctx.file.endsWith(".css")) {
|
|
200
|
+
virtualSSRModuleId += ".js";
|
|
201
|
+
}
|
|
202
|
+
const virtualSSRModule = ctx.server.environments[environment].moduleGraph.idToModuleMap.get(virtualSSRModuleId);
|
|
189
203
|
if (virtualSSRModule) {
|
|
190
204
|
invalidateModule(ctx.server, environment, virtualSSRModule);
|
|
191
205
|
}
|
|
@@ -196,6 +210,7 @@ export const miniflareHMRPlugin = (givenOptions) => [
|
|
|
196
210
|
file: ctx.file,
|
|
197
211
|
},
|
|
198
212
|
});
|
|
213
|
+
log("hmr: sent rsc update");
|
|
199
214
|
return [];
|
|
200
215
|
}
|
|
201
216
|
},
|
package/package.json
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|