@cedarjs/vite 4.0.0 → 5.0.0-canary.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.
Files changed (32) hide show
  1. package/dist/cjs/devFeServer.js +280 -15
  2. package/dist/cjs/lib/registerFwGlobalsAndShims.js +9 -0
  3. package/dist/cjs/plugins/vite-plugin-rsc-ssr-router-import.js +2 -2
  4. package/dist/cjs/plugins/vite-plugin-rsc-transform-server.js +4 -0
  5. package/dist/cjs/rsc/rscRenderer.js +23 -9
  6. package/dist/cjs/rsc/rscRequestHandler.js +6 -6
  7. package/dist/cjs/runFeServer.js +3 -22
  8. package/dist/cjs/streaming/createReactStreamingHandler.js +13 -10
  9. package/dist/cjs/streaming/streamHelpers.js +49 -32
  10. package/dist/cjs/streaming/triggerRouteHooks.js +3 -3
  11. package/dist/devFeServer.js +284 -16
  12. package/dist/lib/registerFwGlobalsAndShims.js +9 -0
  13. package/dist/plugins/vite-plugin-rsc-ssr-router-import.d.ts.map +1 -1
  14. package/dist/plugins/vite-plugin-rsc-ssr-router-import.js +2 -2
  15. package/dist/plugins/vite-plugin-rsc-transform-server.d.ts.map +1 -1
  16. package/dist/plugins/vite-plugin-rsc-transform-server.js +4 -0
  17. package/dist/rsc/rscRenderer.d.ts.map +1 -1
  18. package/dist/rsc/rscRenderer.js +19 -5
  19. package/dist/rsc/rscRequestHandler.d.ts +2 -2
  20. package/dist/rsc/rscRequestHandler.d.ts.map +1 -1
  21. package/dist/rsc/rscRequestHandler.js +4 -4
  22. package/dist/runFeServer.js +2 -21
  23. package/dist/streaming/createReactStreamingHandler.d.ts +1 -1
  24. package/dist/streaming/createReactStreamingHandler.d.ts.map +1 -1
  25. package/dist/streaming/createReactStreamingHandler.js +13 -10
  26. package/dist/streaming/streamHelpers.d.ts +2 -2
  27. package/dist/streaming/streamHelpers.d.ts.map +1 -1
  28. package/dist/streaming/streamHelpers.js +49 -31
  29. package/dist/streaming/triggerRouteHooks.d.ts +2 -2
  30. package/dist/streaming/triggerRouteHooks.d.ts.map +1 -1
  31. package/dist/streaming/triggerRouteHooks.js +3 -3
  32. package/package.json +11 -11
@@ -28,7 +28,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var streamHelpers_exports = {};
30
30
  __export(streamHelpers_exports, {
31
- importModule: () => importModule,
32
31
  reactRenderToStreamResponse: () => reactRenderToStreamResponse
33
32
  });
34
33
  module.exports = __toCommonJS(streamHelpers_exports);
@@ -62,7 +61,7 @@ globalThis.__webpack_require__ ||= (id) => {
62
61
  return globalThis.__rw_module_cache__.get(id)
63
62
  };
64
63
  `;
65
- async function reactRenderToStreamResponse(mwRes, renderOptions, streamOptions) {
64
+ async function reactRenderToStreamResponse(mwRes, renderOptions, streamOptions, viteDevServer) {
66
65
  const { waitForAllReady = false } = streamOptions;
67
66
  const {
68
67
  ServerEntry,
@@ -84,13 +83,13 @@ async function reactRenderToStreamResponse(mwRes, renderOptions, streamOptions)
84
83
  meta: metaTags
85
84
  });
86
85
  const rscEnabled = (0, import_project_config.getConfig)().experimental?.rsc?.enabled;
87
- const { createElement } = rscEnabled ? await importModule("__cedarjs__react") : await import("react");
86
+ const { createElement } = rscEnabled ? await importModule("__cedarjs__react", !!viteDevServer) : await import("react");
88
87
  const {
89
88
  createInjector,
90
89
  ServerHtmlProvider,
91
90
  ServerInjectedHtml
92
- } = rscEnabled ? await importModule("__cedarjs__server_inject") : await import("@cedarjs/web/serverInject");
93
- const { renderToString } = rscEnabled ? await importModule("rd-server") : await import("react-dom/server");
91
+ } = rscEnabled ? await importModule("__cedarjs__server_inject", !!viteDevServer) : await import("@cedarjs/web/serverInject");
92
+ const { renderToString } = rscEnabled ? await importModule("rd-server", !!viteDevServer) : await import("react-dom/server");
94
93
  const { injectionState, injectToPage } = createInjector();
95
94
  const bufferTransform = (0, import_bufferedTransform.createBufferedTransformStream)();
96
95
  const serverInjectionTransform = (0, import_serverInjectionTransform.createServerInjectionTransform)({
@@ -105,8 +104,8 @@ async function reactRenderToStreamResponse(mwRes, renderOptions, streamOptions)
105
104
  controller.abort();
106
105
  }, 1e4);
107
106
  const timeoutTransform = (0, import_cancelTimeoutTransform.createTimeoutTransform)(timeoutHandle);
108
- const { ServerAuthProvider } = rscEnabled ? await importModule("__cedarjs__server_auth_provider") : await import("@cedarjs/auth/dist/AuthProvider/ServerAuthProvider.js");
109
- const { LocationProvider } = rscEnabled ? await importModule("__cedarjs__location") : await import("@cedarjs/router/location");
107
+ const { ServerAuthProvider } = rscEnabled ? await importModule("__cedarjs__server_auth_provider", !!viteDevServer) : await import("@cedarjs/auth/dist/AuthProvider/ServerAuthProvider.js");
108
+ const { LocationProvider } = rscEnabled ? await importModule("__cedarjs__location", !!viteDevServer) : await import("@cedarjs/router/location");
110
109
  const renderRoot = (url) => {
111
110
  return createElement(
112
111
  ServerAuthProvider,
@@ -138,7 +137,7 @@ async function reactRenderToStreamResponse(mwRes, renderOptions, streamOptions)
138
137
  ),
139
138
  bootstrapModules: jsBundles
140
139
  };
141
- const { renderToReadableStream } = rscEnabled ? await importModule("rd-server") : await import("react-dom/server.edge");
140
+ const { renderToReadableStream } = rscEnabled ? await importModule("rd-server", !!viteDevServer) : await import("react-dom/server.edge");
142
141
  try {
143
142
  let didErrorOutsideShell = false;
144
143
  const renderToStreamOptions = {
@@ -197,34 +196,52 @@ function applyStreamTransforms(reactStream, transformsToApply) {
197
196
  }
198
197
  return outputStream;
199
198
  }
200
- async function importModule(mod) {
201
- const distSsr = (0, import_project_config.getPaths)().web.distSsr;
202
- const rdServerPath = (0, import_utils.makeFilePath)(import_node_path.default.join(distSsr, "rd-server.mjs"));
203
- const reactPath = (0, import_utils.makeFilePath)(import_node_path.default.join(distSsr, "__cedarjs__react.mjs"));
204
- const locationPath = (0, import_utils.makeFilePath)(
205
- import_node_path.default.join(distSsr, "__cedarjs__location.mjs")
206
- );
207
- const ServerAuthProviderPath = (0, import_utils.makeFilePath)(
208
- import_node_path.default.join(distSsr, "__cedarjs__server_auth_provider.mjs")
209
- );
210
- const ServerInjectPath = (0, import_utils.makeFilePath)(
211
- import_node_path.default.join(distSsr, "__cedarjs__server_inject.mjs")
212
- );
213
- if (mod === "rd-server") {
214
- return (await import(rdServerPath)).default;
215
- } else if (mod === "__cedarjs__react") {
216
- return (await import(reactPath)).default;
217
- } else if (mod === "__cedarjs__location") {
218
- return await import(locationPath);
219
- } else if (mod === "__cedarjs__server_auth_provider") {
220
- return await import(ServerAuthProviderPath);
221
- } else if (mod === "__cedarjs__server_inject") {
222
- return await import(ServerInjectPath);
199
+ async function importModule(mod, isDev) {
200
+ if (isDev) {
201
+ if (mod === "rd-server") {
202
+ const loadedMod = await import("react-dom/server.edge");
203
+ return loadedMod.default;
204
+ } else if (mod === "__cedarjs__react") {
205
+ const loadedMod = await import("react");
206
+ return loadedMod.default;
207
+ } else if (mod === "__cedarjs__location") {
208
+ const loadedMod = await import("@cedarjs/router/location");
209
+ return loadedMod;
210
+ } else if (mod === "__cedarjs__server_auth_provider") {
211
+ const loadedMod = await import("@cedarjs/auth/dist/AuthProvider/ServerAuthProvider.js");
212
+ return loadedMod;
213
+ } else if (mod === "__cedarjs__server_inject") {
214
+ const loadedMod = await import("@cedarjs/web/serverInject");
215
+ return loadedMod;
216
+ }
217
+ } else {
218
+ const distSsr = (0, import_project_config.getPaths)().web.distSsr;
219
+ const rdServerPath = (0, import_utils.makeFilePath)(import_node_path.default.join(distSsr, "rd-server.mjs"));
220
+ const reactPath = (0, import_utils.makeFilePath)(import_node_path.default.join(distSsr, "__cedarjs__react.mjs"));
221
+ const locationPath = (0, import_utils.makeFilePath)(
222
+ import_node_path.default.join(distSsr, "__cedarjs__location.mjs")
223
+ );
224
+ const serverAuthProviderPath = (0, import_utils.makeFilePath)(
225
+ import_node_path.default.join(distSsr, "__cedarjs__server_auth_provider.mjs")
226
+ );
227
+ const serverInjectPath = (0, import_utils.makeFilePath)(
228
+ import_node_path.default.join(distSsr, "__cedarjs__server_inject.mjs")
229
+ );
230
+ if (mod === "rd-server") {
231
+ return (await import(rdServerPath)).default;
232
+ } else if (mod === "__cedarjs__react") {
233
+ return (await import(reactPath)).default;
234
+ } else if (mod === "__cedarjs__location") {
235
+ return await import(locationPath);
236
+ } else if (mod === "__cedarjs__server_auth_provider") {
237
+ return await import(serverAuthProviderPath);
238
+ } else if (mod === "__cedarjs__server_inject") {
239
+ return await import(serverInjectPath);
240
+ }
223
241
  }
224
242
  throw new Error("Unknown module " + mod);
225
243
  }
226
244
  // Annotate the CommonJS export names for ESM import in node:
227
245
  0 && (module.exports = {
228
- importModule,
229
246
  reactRenderToStreamResponse
230
247
  });
@@ -55,11 +55,11 @@ const defaultRouteHookOutput = {
55
55
  const loadAndRunRouteHooks = async ({
56
56
  paths = [],
57
57
  reqMeta,
58
- viteDevServer,
58
+ viteSsrDevServer,
59
59
  previousOutput = defaultRouteHookOutput
60
60
  }) => {
61
61
  const loadModule = async (path) => {
62
- return viteDevServer ? viteDevServer.ssrLoadModule(path) : import(path);
62
+ return viteSsrDevServer ? viteSsrDevServer.ssrLoadModule(path) : import(path);
63
63
  };
64
64
  let currentRouteHooks;
65
65
  let rhOutput = defaultRouteHookOutput;
@@ -79,7 +79,7 @@ const loadAndRunRouteHooks = async ({
79
79
  paths,
80
80
  reqMeta,
81
81
  previousOutput: rhOutput,
82
- viteDevServer
82
+ viteSsrDevServer
83
83
  });
84
84
  } else {
85
85
  return rhOutput;
@@ -1,6 +1,11 @@
1
+ import http from "node:http";
1
2
  import { createServerAdapter } from "@whatwg-node/server";
2
3
  import express from "express";
3
- import { createServer as createViteServer } from "vite";
4
+ import {
5
+ createServer as createViteServer,
6
+ createServerModuleRunner,
7
+ defaultServerConditions
8
+ } from "vite";
4
9
  import { cjsInterop } from "vite-plugin-cjs-interop";
5
10
  import { getProjectRoutes } from "@cedarjs/internal/dist/routes.js";
6
11
  import { getConfig, getPaths } from "@cedarjs/project-config";
@@ -9,6 +14,10 @@ import { registerFwGlobalsAndShims } from "./lib/registerFwGlobalsAndShims.js";
9
14
  import { invoke } from "./middleware/invokeMiddleware.js";
10
15
  import { createMiddlewareRouter } from "./middleware/register.js";
11
16
  import { rscRoutesAutoLoader } from "./plugins/vite-plugin-rsc-routes-auto-loader.js";
17
+ import { rscRoutesImports } from "./plugins/vite-plugin-rsc-routes-imports.js";
18
+ import { rscSsrRouterImport } from "./plugins/vite-plugin-rsc-ssr-router-import.js";
19
+ import { rscTransformUseServerPlugin } from "./plugins/vite-plugin-rsc-transform-server.js";
20
+ import { createWebSocketServer } from "./rsc/rscWebSocketServer.js";
12
21
  import { collectCssPaths, componentsModules } from "./streaming/collectCss.js";
13
22
  import { createReactStreamingHandler } from "./streaming/createReactStreamingHandler.js";
14
23
  import {
@@ -17,10 +26,13 @@ import {
17
26
  getFullUrl
18
27
  } from "./utils.js";
19
28
  globalThis.__REDWOOD__PRERENDER_PAGES = {};
29
+ globalThis.__cedarjs__vite_ssr_runtime = void 0;
30
+ globalThis.__cedarjs__vite_rsc_runtime = void 0;
20
31
  async function createServer() {
21
32
  ensureProcessDirWeb();
22
33
  registerFwGlobalsAndShims();
23
34
  const app = express();
35
+ const server = http.createServer(app);
24
36
  const rwPaths = getPaths();
25
37
  const rscEnabled = getConfig().experimental.rsc?.enabled ?? false;
26
38
  const serverStorage = createServerStorage();
@@ -43,8 +55,78 @@ async function createServer() {
43
55
  "Vite config not found. You need to setup your project with Vite using `yarn cedar setup vite`"
44
56
  );
45
57
  }
46
- const vite = await createViteServer({
58
+ const viteSsrDevServer = await createViteServer({
47
59
  configFile: rwPaths.web.viteConfig,
60
+ envFile: false,
61
+ define: {
62
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
63
+ },
64
+ ssr: {
65
+ // Inline every file apart from node built-ins. We want vite/rollup to
66
+ // inline dependencies in the server build. This gets round runtime
67
+ // importing of "server-only" and other packages with poisoned imports.
68
+ //
69
+ // Files included in `noExternal` are files we want Vite to analyze
70
+ // As of vite 5.2 `true` here means "all except node built-ins"
71
+ // noExternal: true,
72
+ // TODO (RSC): Other frameworks build for RSC without `noExternal: true`.
73
+ // What are we missing here? When/why is that a better choice? I know
74
+ // we would have to explicitly add a bunch of packages to noExternal, if
75
+ // we wanted to go that route.
76
+ // noExternal: ['@tobbe.dev/rsc-test'],
77
+ // Can't inline prisma client (db calls fail at runtime) or react-dom
78
+ // (css pre-init failure)
79
+ // Server store has to be externalized, because it's a singleton (shared between FW and App)
80
+ external: [
81
+ "@prisma/client",
82
+ "@prisma/adapter-better-sqlite3",
83
+ "@prisma/fetch-engine",
84
+ "@prisma/internals",
85
+ "better-sqlite3",
86
+ "@cedarjs/auth-dbauth-api",
87
+ "@cedarjs/cookie-jar",
88
+ "@cedarjs/server-store",
89
+ "@simplewebauthn/server",
90
+ "graphql-scalars",
91
+ "minimatch",
92
+ "playwright",
93
+ "react-dom"
94
+ ],
95
+ resolve: {
96
+ // These conditions are used in the plugin pipeline, and only affect non-externalized
97
+ // dependencies during the SSR build. Which because of `noExternal: true` means all
98
+ // dependencies apart from node built-ins.
99
+ // TODO (RSC): What's the difference between `conditions` and
100
+ // `externalConditions`? When is one used over the other?
101
+ // conditions: ['react-server'],
102
+ // externalConditions: ['react-server'],
103
+ },
104
+ optimizeDeps: {
105
+ // We need Vite to optimize these dependencies so that they are resolved
106
+ // with the correct conditions. And so that CJS modules work correctly.
107
+ // include: [
108
+ // 'react/**/*',
109
+ // 'react-dom/server',
110
+ // 'react-dom/server.edge',
111
+ // 'rehackt',
112
+ // 'react-server-dom-webpack/server',
113
+ // 'react-server-dom-webpack/client',
114
+ // '@apollo/client/cache/*',
115
+ // '@apollo/client/utilities/*',
116
+ // '@apollo/client/react/hooks/*',
117
+ // 'react-fast-compare',
118
+ // 'invariant',
119
+ // 'shallowequal',
120
+ // 'graphql/language/*',
121
+ // 'stacktracey',
122
+ // 'deepmerge',
123
+ // 'fast-glob',
124
+ // ],
125
+ }
126
+ },
127
+ resolve: {
128
+ // conditions: ['react-server'],
129
+ },
48
130
  plugins: [
49
131
  cjsInterop({
50
132
  dependencies: [
@@ -58,16 +140,195 @@ async function createServer() {
58
140
  "@cedarjs/auth-!(dbauth)-web"
59
141
  ]
60
142
  }),
61
- rscEnabled && rscRoutesAutoLoader()
143
+ rscEnabled && rscRoutesAutoLoader(),
144
+ rscEnabled && rscSsrRouterImport()
62
145
  ],
63
146
  server: { middlewareMode: true },
64
147
  logLevel: "info",
65
148
  clearScreen: false,
66
149
  appType: "custom"
67
150
  });
151
+ globalThis.__cedarjs__vite_ssr_runtime = createServerModuleRunner(
152
+ viteSsrDevServer.environments.ssr
153
+ );
154
+ globalThis.__cedarjs__client_references = /* @__PURE__ */ new Set();
155
+ globalThis.__cedarjs__server_references = /* @__PURE__ */ new Set();
156
+ const viteRscServer = await createViteServer({
157
+ envFile: false,
158
+ define: {
159
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
160
+ },
161
+ ssr: {
162
+ // Inline every file apart from node built-ins. We want vite/rollup to
163
+ // inline dependencies in the server build. This gets round runtime
164
+ // importing of "server-only" and other packages with poisoned imports.
165
+ //
166
+ // Files included in `noExternal` are files we want Vite to analyze
167
+ // As of vite 5.2 `true` here means "all except node built-ins"
168
+ noExternal: true,
169
+ // TODO (RSC): Other frameworks build for RSC without `noExternal: true`.
170
+ // What are we missing here? When/why is that a better choice? I know
171
+ // we would have to explicitly add a bunch of packages to noExternal, if
172
+ // we wanted to go that route.
173
+ // noExternal: ['@tobbe.dev/rsc-test'],
174
+ // Can't inline prisma client (db calls fail at runtime) or react-dom
175
+ // (css pre-init failure)
176
+ // Server store has to be externalized, because it's a singleton (shared between FW and App)
177
+ external: [
178
+ "@prisma/client",
179
+ "@prisma/adapter-better-sqlite3",
180
+ "@prisma/fetch-engine",
181
+ "@prisma/internals",
182
+ "better-sqlite3",
183
+ "@cedarjs/auth-dbauth-api",
184
+ "@cedarjs/cookie-jar",
185
+ "@cedarjs/server-store",
186
+ "@cedarjs/structure",
187
+ "@simplewebauthn/server",
188
+ "graphql-scalars",
189
+ "minimatch",
190
+ "playwright",
191
+ "react-dom"
192
+ ],
193
+ resolve: {
194
+ // These conditions are used in the plugin pipeline, and only affect non-externalized
195
+ // dependencies during the SSR build. Which because of `noExternal: true` means all
196
+ // dependencies apart from node built-ins.
197
+ // TODO (RSC): What's the difference between `conditions` and
198
+ // `externalConditions`? When is one used over the other?
199
+ // In Vite 6, we must include `defaultServerConditions` alongside
200
+ // `react-server` so that nested condition maps (e.g. the `node`
201
+ // sub-condition inside `react-server-dom-webpack/server`'s exports)
202
+ // can still be resolved. Without `node` (or another environment
203
+ // condition), the resolver throws "No known conditions for
204
+ // './server' specifier in 'react-server-dom-webpack' package".
205
+ conditions: ["react-server", ...defaultServerConditions],
206
+ externalConditions: ["react-server", ...defaultServerConditions]
207
+ },
208
+ optimizeDeps: {
209
+ // We need Vite to optimize these dependencies so that they are resolved
210
+ // with the correct conditions. And so that CJS modules work correctly.
211
+ include: [
212
+ "react/**/*",
213
+ "react-dom/server",
214
+ "react-dom/server.edge",
215
+ "rehackt",
216
+ "react-server-dom-webpack/server",
217
+ "react-server-dom-webpack/server.edge",
218
+ "react-server-dom-webpack/client",
219
+ "react-server-dom-webpack/client.edge",
220
+ "@apollo/client/cache/*",
221
+ "@apollo/client/utilities/*",
222
+ "@apollo/client/react/hooks/*",
223
+ "react-fast-compare",
224
+ "invariant",
225
+ "shallowequal",
226
+ "graphql/language/*",
227
+ "stacktracey",
228
+ "deepmerge",
229
+ "fast-glob",
230
+ "@whatwg-node/fetch",
231
+ "busboy",
232
+ "cookie"
233
+ ],
234
+ // Without excluding `util` we get "TypeError: util.TextEncoder is not
235
+ // a constructor" in react-server-dom-webpack.server because it'll try
236
+ // to use Browserify's `util` instead of Node's. And Browserify's
237
+ // polyfill is missing TextEncoder+TextDecoder. The reason it's using
238
+ // the Browserify polyfill is because we have
239
+ // `vite-plugin-node-polyfills` as a dependency, and that'll add
240
+ // Browserify's `node-util` to `node_modules`, so when Vite goes to
241
+ // resolve `import { TextEncoder } from 'util` it'll find the one in
242
+ // `node_modules` instead of Node's internal version.
243
+ // We only see this in dev, and not in prod. I'm not entirely sure why
244
+ // but I have two guesses: 1. When RSC is enabled we don't actually use
245
+ // `vite-plugin-node-polyfill`, so some kind of tree shaking is
246
+ // happening, which prevents the issue from occurring. 2. In prod we
247
+ // only use Node's dependency resolution. Vite is not involved. And
248
+ // that difference in resolution is what prevents the issue from
249
+ // occurring.
250
+ exclude: ["util"]
251
+ }
252
+ },
253
+ resolve: {
254
+ // See comment above in ssr.resolve for why we include defaultServerConditions.
255
+ conditions: ["react-server", ...defaultServerConditions]
256
+ },
257
+ plugins: [
258
+ {
259
+ name: "rsc-record-and-tranform-use-client-plugin",
260
+ transform(code, id, _options) {
261
+ globalThis.__cedarjs__client_references?.delete(id);
262
+ if (!/^(["'])use client\1/.test(code)) {
263
+ return void 0;
264
+ }
265
+ console.log(
266
+ "rsc-record-and-transform-use-client-plugin: adding client reference",
267
+ id
268
+ );
269
+ globalThis.__cedarjs__client_references?.add(id);
270
+ const fns = code.matchAll(/export function (\w+)\(/g);
271
+ const consts = code.matchAll(/export const (\w+) = \(/g);
272
+ const names = [...fns, ...consts].map(([, name]) => name);
273
+ const result = [
274
+ `import { registerClientReference } from "react-server-dom-webpack/server.edge";`,
275
+ "",
276
+ ...names.map((name) => {
277
+ return name === "default" ? `export default registerClientReference({}, "${id}", "${name}");` : `export const ${name} = registerClientReference({}, "${id}", "${name}");`;
278
+ })
279
+ ].join("\n");
280
+ console.log("rsc-record-and-transform-use-client-plugin result");
281
+ console.log(
282
+ result.split("\n").map((line, i) => ` ${i + 1}: ${line}`).join("\n")
283
+ );
284
+ return { code: result, map: null };
285
+ }
286
+ },
287
+ rscTransformUseServerPlugin("", {}),
288
+ // The rscTransformUseClientPlugin maps paths like
289
+ // /Users/tobbe/.../rw-app/node_modules/@tobbe.dev/rsc-test/dist/rsc-test.es.js
290
+ // to
291
+ // /Users/tobbe/.../rw-app/web/dist/ssr/assets/rsc0.js
292
+ // That's why it needs the `clientEntryFiles` data
293
+ // (It does other things as well, but that's why it needs clientEntryFiles)
294
+ // rscTransformUseClientPlugin(clientEntryFiles),
295
+ // rscTransformUseServerPlugin(outDir, serverEntryFiles),
296
+ rscRoutesImports(),
297
+ {
298
+ name: "rsc-hot-update",
299
+ handleHotUpdate(ctx) {
300
+ console.log("rsc-hot-update ctx.modules", ctx.modules);
301
+ return [];
302
+ }
303
+ }
304
+ ],
305
+ build: {
306
+ ssr: true
307
+ },
308
+ server: {
309
+ // We never call `viteRscServer.listen()`, so we should run this in
310
+ // middleware mode
311
+ middlewareMode: true,
312
+ // The hmr/fast-refresh websocket in this server collides with the one in
313
+ // the other Vite server. So we can either disable it or run it on a
314
+ // different port.
315
+ // TODO (RSC): Figure out if we should disable or just pick a different
316
+ // port
317
+ ws: false
318
+ // hmr: {
319
+ // port: 24679,
320
+ // },
321
+ },
322
+ appType: "custom",
323
+ // Using a unique cache dir here to not clash with our other vite server
324
+ cacheDir: "../node_modules/.vite-rsc"
325
+ });
326
+ globalThis.__cedarjs__vite_rsc_runtime = createServerModuleRunner(
327
+ viteRscServer.environments.ssr
328
+ );
68
329
  const handleWithMiddleware = (route) => {
69
330
  return createServerAdapter(async (req) => {
70
- const middlewareRouter = await createMiddlewareRouter(vite);
331
+ const middlewareRouter = await createMiddlewareRouter(viteSsrDevServer);
71
332
  const middleware = middlewareRouter.find(
72
333
  req.method,
73
334
  req.url
@@ -77,19 +338,22 @@ async function createServer() {
77
338
  }
78
339
  const [mwRes] = await invoke(req, middleware, {
79
340
  route,
80
- viteDevServer: vite
341
+ viteSsrDevServer
81
342
  });
82
343
  return mwRes.toResponse();
83
344
  });
84
345
  };
85
- app.use(vite.middlewares);
346
+ app.use(viteSsrDevServer.middlewares);
86
347
  if (rscEnabled) {
87
- const { createRscRequestHandler } = await import("./rsc/rscRequestHandler.js");
348
+ createWebSocketServer();
349
+ const { createRscRequestHandler } = await globalThis.__cedarjs__vite_rsc_runtime.import(
350
+ new URL("./rsc/rscRequestHandler.js", import.meta.url).pathname
351
+ );
88
352
  app.use(
89
353
  "/rw-rsc",
90
- createRscRequestHandler({
91
- getMiddlewareRouter: async () => createMiddlewareRouter(vite),
92
- viteDevServer: vite
354
+ await createRscRequestHandler({
355
+ getMiddlewareRouter: async () => createMiddlewareRouter(viteSsrDevServer),
356
+ viteSsrDevServer
93
357
  })
94
358
  );
95
359
  }
@@ -99,18 +363,22 @@ async function createServer() {
99
363
  routes,
100
364
  clientEntryPath: rwPaths.web.entryClient,
101
365
  getStylesheetLinks: (route) => {
102
- return getCssLinks({ rwPaths, route, vite });
366
+ return getCssLinks({
367
+ rwPaths,
368
+ route,
369
+ viteSsrDevServer
370
+ });
103
371
  },
104
372
  // Recreate middleware router on each request in dev
105
- getMiddlewareRouter: async () => createMiddlewareRouter(vite)
373
+ getMiddlewareRouter: async () => createMiddlewareRouter(viteSsrDevServer)
106
374
  },
107
- vite
375
+ viteSsrDevServer
108
376
  );
109
377
  app.get("*", createServerAdapter(routeHandler));
110
378
  app.post("*", handleWithMiddleware());
111
379
  const port = getConfig().web.port;
112
380
  console.log(`Started server on http://localhost:${port}`);
113
- return app.listen(port);
381
+ return server.listen(port);
114
382
  }
115
383
  let devApp = createServer();
116
384
  process.stdin.on("data", async (data) => {
@@ -125,11 +393,11 @@ process.stdin.on("data", async (data) => {
125
393
  function getCssLinks({
126
394
  rwPaths,
127
395
  route,
128
- vite
396
+ viteSsrDevServer
129
397
  }) {
130
398
  const appAndRouteModules = componentsModules(
131
399
  [rwPaths.web.app, route?.filePath].filter(Boolean),
132
- vite
400
+ viteSsrDevServer
133
401
  );
134
402
  const collectedCss = collectCssPaths(appAndRouteModules);
135
403
  const cssLinks = Array.from(collectedCss);
@@ -55,6 +55,15 @@ function registerFwShims() {
55
55
  globalThis.__rw_module_cache__ ||= /* @__PURE__ */ new Map();
56
56
  globalThis.__webpack_chunk_load__ ||= async (id) => {
57
57
  console.log("registerFwShims chunk load id", id);
58
+ if (globalThis.__cedarjs__vite_ssr_runtime) {
59
+ return globalThis.__cedarjs__vite_ssr_runtime?.import(id).then((mod) => {
60
+ console.log("registerFwShims chunk load mod", mod);
61
+ if (mod.default && typeof mod.default === "object") {
62
+ return globalThis.__rw_module_cache__.set(id, mod.default);
63
+ }
64
+ return globalThis.__rw_module_cache__.set(id, mod);
65
+ });
66
+ }
58
67
  return import(id).then((mod) => {
59
68
  console.log("registerFwShims chunk load mod", mod);
60
69
  if (mod.default && typeof mod.default === "object") {
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-rsc-ssr-router-import.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-rsc-ssr-router-import.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAKlC;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAqC3C"}
1
+ {"version":3,"file":"vite-plugin-rsc-ssr-router-import.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-rsc-ssr-router-import.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAKlC;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAsC3C"}
@@ -11,8 +11,8 @@ function rscSsrRouterImport() {
11
11
  const routesFileId = normalizePath(getPaths().web.routes);
12
12
  return {
13
13
  name: "rsc-ssr-router-import",
14
- transform: async function(code, id) {
15
- if (id !== routesFileId) {
14
+ transform: async function(code, id, options) {
15
+ if (!options?.ssr || id !== routesFileId) {
16
16
  return null;
17
17
  }
18
18
  const ext = path.extname(id);
@@ -1 +1 @@
1
- {"version":3,"file":"vite-plugin-rsc-transform-server.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-rsc-transform-server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,MAAM,CA8GR"}
1
+ {"version":3,"file":"vite-plugin-rsc-transform-server.d.ts","sourceRoot":"","sources":["../../src/plugins/vite-plugin-rsc-transform-server.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAElC,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACvC,MAAM,CAuHR"}
@@ -8,6 +8,10 @@ function rscTransformUseServerPlugin(outDir, serverEntryFiles) {
8
8
  if (!code.includes("use server")) {
9
9
  return code;
10
10
  }
11
+ if (id.includes("node_modules/.vite") || id.includes("/react-server-dom-webpack/") || id.includes("/react-server-dom-webpack.server")) {
12
+ console.log("vite-plugin-rsc-transform-server.ts: Skipping", id);
13
+ return code;
14
+ }
11
15
  let mod;
12
16
  const isTypescript = id.endsWith(".ts") || id.endsWith(".tsx");
13
17
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"rscRenderer.d.ts","sourceRoot":"","sources":["../../src/rsc/rscRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAWrD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAA;CAC7B,CAAA;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,cAAc,CAAC,CAE7E;AAyBD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BtD"}
1
+ {"version":3,"file":"rscRenderer.d.ts","sourceRoot":"","sources":["../../src/rsc/rscRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AASrD,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IAC1B,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,SAAS,CAAA;CAC7B,CAAA;AAID,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC,cAAc,CAAC,CAEzB;AAyCD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BtD"}
@@ -1,18 +1,26 @@
1
1
  import path from "node:path";
2
- import { createElement } from "react";
3
- import { renderToReadableStream } from "react-server-dom-webpack/server.edge";
4
2
  import { getPaths } from "@cedarjs/project-config";
5
3
  import { getEntriesFromDist } from "../lib/entries.js";
6
4
  import { StatusError } from "../lib/StatusError.js";
5
+ import { importRscReact, importRsdwServer } from "./utils.js";
7
6
  let absoluteClientEntries = {};
8
- function renderRscToStream(input) {
7
+ async function renderRscToStream(input) {
9
8
  return input.rscId ? renderRsc(input) : executeRsa(input);
10
9
  }
11
10
  async function loadServerFile(filePath) {
12
11
  console.log("rscRenderer.ts loadServerFile filePath", filePath);
12
+ if (globalThis.__cedarjs__vite_rsc_runtime) {
13
+ const serverMod = await globalThis.__cedarjs__vite_rsc_runtime.import(filePath);
14
+ return serverMod.default ? serverMod.default : serverMod;
15
+ }
13
16
  return import(`file://${filePath}`);
14
17
  }
15
18
  const getRoutesComponent = async () => {
19
+ if (globalThis.__cedarjs__vite_rsc_runtime) {
20
+ const routesPath2 = getPaths().web.routes;
21
+ const routesMod = await globalThis.__cedarjs__vite_rsc_runtime.import(routesPath2);
22
+ return routesMod.default;
23
+ }
16
24
  const serverEntries = await getEntriesFromDist();
17
25
  console.log("rscRenderer.ts serverEntries", serverEntries);
18
26
  const routesPath = path.join(
@@ -53,10 +61,12 @@ function getBundlerConfig() {
53
61
  {},
54
62
  {
55
63
  get(_target, encodedId) {
56
- console.log("Proxy get encodedId", encodedId);
64
+ console.log("rscRenderer.ts Proxy get encodedId", encodedId);
57
65
  const [filePath, name] = encodedId.split("#");
66
+ console.log("filePath", filePath);
67
+ console.log("name", name);
58
68
  const filePathSlash = filePath.replaceAll("\\", "/");
59
- const id = absoluteClientEntries[filePathSlash];
69
+ const id = globalThis.__cedarjs__vite_rsc_runtime ? filePath : absoluteClientEntries[filePathSlash];
60
70
  console.log("absoluteClientEntries", absoluteClientEntries);
61
71
  console.log("filePath", filePathSlash);
62
72
  if (!id) {
@@ -79,6 +89,8 @@ async function renderRsc(input) {
79
89
  throw new Error("Unexpected input. Missing rscId or props.");
80
90
  }
81
91
  console.log("renderRsc input", input);
92
+ const { createElement } = await importRscReact();
93
+ const { renderToReadableStream } = await importRsdwServer();
82
94
  const serverRoutes = await getRoutesComponent();
83
95
  const model = {
84
96
  __cedarjs__Routes: createElement(serverRoutes)
@@ -115,6 +127,8 @@ async function executeRsa(input) {
115
127
  console.log("rscRenderer.ts args", ...input.args);
116
128
  const data = await method(...input.args);
117
129
  console.log("rscRenderer.ts rsa return data", data);
130
+ const { createElement } = await importRscReact();
131
+ const { renderToReadableStream } = await importRsdwServer();
118
132
  const serverRoutes = await getRoutesComponent();
119
133
  console.log("rscRenderer.ts executeRsa serverRoutes", serverRoutes);
120
134
  const model = {