@cedarjs/vite 3.0.1-next.0 → 4.0.0-canary.13650

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 (41) hide show
  1. package/dist/bundled/react-server-dom-webpack.server.js +1224 -28468
  2. package/dist/cjs/devFeServer.js +269 -15
  3. package/dist/cjs/lib/registerFwGlobalsAndShims.js +9 -0
  4. package/dist/cjs/plugins/vite-plugin-rsc-ssr-router-import.js +2 -2
  5. package/dist/cjs/plugins/vite-plugin-rsc-transform-server.js +4 -0
  6. package/dist/cjs/rsc/rscRenderer.js +23 -9
  7. package/dist/cjs/rsc/rscRequestHandler.js +6 -6
  8. package/dist/cjs/rsc/rscWebSocketServer.js +56 -0
  9. package/dist/cjs/rsc/utils.js +56 -0
  10. package/dist/cjs/runFeServer.js +3 -22
  11. package/dist/cjs/streaming/createReactStreamingHandler.js +13 -10
  12. package/dist/cjs/streaming/streamHelpers.js +49 -32
  13. package/dist/cjs/streaming/triggerRouteHooks.js +3 -3
  14. package/dist/devFeServer.js +269 -16
  15. package/dist/lib/registerFwGlobalsAndShims.js +9 -0
  16. package/dist/plugins/vite-plugin-rsc-ssr-router-import.d.ts.map +1 -1
  17. package/dist/plugins/vite-plugin-rsc-ssr-router-import.js +2 -2
  18. package/dist/plugins/vite-plugin-rsc-transform-server.d.ts.map +1 -1
  19. package/dist/plugins/vite-plugin-rsc-transform-server.js +4 -0
  20. package/dist/rsc/rscRenderer.d.ts.map +1 -1
  21. package/dist/rsc/rscRenderer.js +19 -5
  22. package/dist/rsc/rscRequestHandler.d.ts +2 -2
  23. package/dist/rsc/rscRequestHandler.d.ts.map +1 -1
  24. package/dist/rsc/rscRequestHandler.js +4 -4
  25. package/dist/rsc/rscWebSocketServer.d.ts +2 -0
  26. package/dist/rsc/rscWebSocketServer.d.ts.map +1 -0
  27. package/dist/rsc/rscWebSocketServer.js +22 -0
  28. package/dist/rsc/utils.d.ts +10 -0
  29. package/dist/rsc/utils.d.ts.map +1 -0
  30. package/dist/rsc/utils.js +21 -0
  31. package/dist/runFeServer.js +2 -21
  32. package/dist/streaming/createReactStreamingHandler.d.ts +1 -1
  33. package/dist/streaming/createReactStreamingHandler.d.ts.map +1 -1
  34. package/dist/streaming/createReactStreamingHandler.js +13 -10
  35. package/dist/streaming/streamHelpers.d.ts +2 -2
  36. package/dist/streaming/streamHelpers.d.ts.map +1 -1
  37. package/dist/streaming/streamHelpers.js +49 -31
  38. package/dist/streaming/triggerRouteHooks.d.ts +2 -2
  39. package/dist/streaming/triggerRouteHooks.d.ts.map +1 -1
  40. package/dist/streaming/triggerRouteHooks.js +3 -3
  41. package/package.json +11 -11
@@ -37,13 +37,13 @@ var import_server = require("@whatwg-node/server");
37
37
  var import_dotenv_defaults = require("dotenv-defaults");
38
38
  var import_express = __toESM(require("express"), 1);
39
39
  var import_http_proxy_middleware = require("http-proxy-middleware");
40
- var import_ws = __toESM(require("ws"), 1);
41
40
  var import_project_config = require("@cedarjs/project-config");
42
41
  var import_rscCss = require("@cedarjs/router/rscCss");
43
42
  var import_server_store = require("@cedarjs/server-store");
44
43
  var import_registerFwGlobalsAndShims = require("./lib/registerFwGlobalsAndShims.js");
45
44
  var import_invokeMiddleware = require("./middleware/invokeMiddleware.js");
46
45
  var import_register = require("./middleware/register.js");
46
+ var import_rscWebSocketServer = require("./rsc/rscWebSocketServer.js");
47
47
  var import_createReactStreamingHandler = require("./streaming/createReactStreamingHandler.js");
48
48
  var import_utils = require("./utils.js");
49
49
  (0, import_dotenv_defaults.config)({
@@ -59,7 +59,7 @@ async function runFeServer() {
59
59
  (0, import_registerFwGlobalsAndShims.registerFwGlobalsAndShims)();
60
60
  if (rscEnabled) {
61
61
  const { setClientEntries } = await import("./rsc/rscRenderer.js");
62
- createWebSocketServer();
62
+ (0, import_rscWebSocketServer.createWebSocketServer)();
63
63
  try {
64
64
  await setClientEntries();
65
65
  } catch (e) {
@@ -118,7 +118,7 @@ async function runFeServer() {
118
118
  const { createRscRequestHandler } = await import("./rsc/rscRequestHandler.js");
119
119
  app.use(
120
120
  "/rw-rsc",
121
- createRscRequestHandler({
121
+ await createRscRequestHandler({
122
122
  getMiddlewareRouter: async () => middlewareRouter
123
123
  })
124
124
  );
@@ -138,25 +138,6 @@ async function runFeServer() {
138
138
  `Started production FE server on http://localhost:${rwConfig.web.port}`
139
139
  );
140
140
  }
141
- function createWebSocketServer() {
142
- const wsServer = new import_ws.WebSocketServer({ port: 18998 });
143
- wsServer.on("connection", (ws) => {
144
- console.log("A new client connected.");
145
- ws.on("message", (data) => {
146
- const message = data.toString();
147
- console.log("runFeServer.ts: Received message:");
148
- console.log(message.slice(0, 120) + "...");
149
- wsServer.clients.forEach((client) => {
150
- if (client.readyState === import_ws.default.OPEN) {
151
- client.send(message);
152
- }
153
- });
154
- });
155
- ws.on("close", () => {
156
- console.log("A client disconnected.");
157
- });
158
- });
159
- }
160
141
  runFeServer();
161
142
  // Annotate the CommonJS export names for ESM import in node:
162
143
  0 && (module.exports = {
@@ -50,10 +50,10 @@ const createReactStreamingHandler = async ({
50
50
  clientEntryPath,
51
51
  getStylesheetLinks,
52
52
  getMiddlewareRouter
53
- }, viteDevServer) => {
53
+ }, viteSsrDevServer) => {
54
54
  const rwPaths = (0, import_project_config.getPaths)();
55
55
  const rwConfig = (0, import_project_config.getConfig)();
56
- const isProd = !viteDevServer;
56
+ const isProd = !viteSsrDevServer;
57
57
  const middlewareRouter = await getMiddlewareRouter();
58
58
  let entryServerImport;
59
59
  let fallbackDocumentImport;
@@ -97,7 +97,7 @@ const createReactStreamingHandler = async ({
97
97
  route: currentRoute,
98
98
  cssPaths: cssLinks,
99
99
  params: matchedMw?.params,
100
- viteDevServer
100
+ viteSsrDevServer
101
101
  }
102
102
  );
103
103
  if (mwResponse.isRedirect() || mwResponse.body) {
@@ -116,8 +116,8 @@ const createReactStreamingHandler = async ({
116
116
  });
117
117
  }
118
118
  if (!isProd) {
119
- entryServerImport = await (0, import_utils.ssrLoadEntryServer)(viteDevServer);
120
- fallbackDocumentImport = await viteDevServer.ssrLoadModule(
119
+ entryServerImport = await (0, import_utils.ssrLoadEntryServer)(viteSsrDevServer);
120
+ fallbackDocumentImport = await viteSsrDevServer.ssrLoadModule(
121
121
  rwPaths.web.document
122
122
  );
123
123
  }
@@ -134,10 +134,12 @@ const createReactStreamingHandler = async ({
134
134
  req,
135
135
  parsedParams
136
136
  },
137
- viteDevServer
137
+ viteSsrDevServer
138
138
  });
139
139
  metaTags = routeHookOutput.meta;
140
- const jsBundles = [viteDevServer ? clientEntryPath : "/" + clientEntryPath];
140
+ const jsBundles = [
141
+ viteSsrDevServer ? clientEntryPath : "/" + clientEntryPath
142
+ ];
141
143
  if (currentRoute.bundle) {
142
144
  jsBundles.push("/" + currentRoute.bundle);
143
145
  }
@@ -157,12 +159,13 @@ const createReactStreamingHandler = async ({
157
159
  {
158
160
  waitForAllReady: isSeoCrawler,
159
161
  onError: (err) => {
160
- if (!isProd && viteDevServer) {
161
- viteDevServer.ssrFixStacktrace(err);
162
+ if (!isProd && viteSsrDevServer) {
163
+ viteSsrDevServer.ssrFixStacktrace(err);
162
164
  }
163
165
  console.error(err);
164
166
  }
165
- }
167
+ },
168
+ viteSsrDevServer
166
169
  );
167
170
  return reactResponse;
168
171
  };
@@ -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,7 @@
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 { createServer as createViteServer, createViteRuntime } from "vite";
4
5
  import { cjsInterop } from "vite-plugin-cjs-interop";
5
6
  import { getProjectRoutes } from "@cedarjs/internal/dist/routes.js";
6
7
  import { getConfig, getPaths } from "@cedarjs/project-config";
@@ -9,6 +10,10 @@ import { registerFwGlobalsAndShims } from "./lib/registerFwGlobalsAndShims.js";
9
10
  import { invoke } from "./middleware/invokeMiddleware.js";
10
11
  import { createMiddlewareRouter } from "./middleware/register.js";
11
12
  import { rscRoutesAutoLoader } from "./plugins/vite-plugin-rsc-routes-auto-loader.js";
13
+ import { rscRoutesImports } from "./plugins/vite-plugin-rsc-routes-imports.js";
14
+ import { rscSsrRouterImport } from "./plugins/vite-plugin-rsc-ssr-router-import.js";
15
+ import { rscTransformUseServerPlugin } from "./plugins/vite-plugin-rsc-transform-server.js";
16
+ import { createWebSocketServer } from "./rsc/rscWebSocketServer.js";
12
17
  import { collectCssPaths, componentsModules } from "./streaming/collectCss.js";
13
18
  import { createReactStreamingHandler } from "./streaming/createReactStreamingHandler.js";
14
19
  import {
@@ -17,10 +22,13 @@ import {
17
22
  getFullUrl
18
23
  } from "./utils.js";
19
24
  globalThis.__REDWOOD__PRERENDER_PAGES = {};
25
+ globalThis.__cedarjs__vite_ssr_runtime = void 0;
26
+ globalThis.__cedarjs__vite_rsc_runtime = void 0;
20
27
  async function createServer() {
21
28
  ensureProcessDirWeb();
22
29
  registerFwGlobalsAndShims();
23
30
  const app = express();
31
+ const server = http.createServer(app);
24
32
  const rwPaths = getPaths();
25
33
  const rscEnabled = getConfig().experimental.rsc?.enabled ?? false;
26
34
  const serverStorage = createServerStorage();
@@ -43,8 +51,78 @@ async function createServer() {
43
51
  "Vite config not found. You need to setup your project with Vite using `yarn cedar setup vite`"
44
52
  );
45
53
  }
46
- const vite = await createViteServer({
54
+ const viteSsrDevServer = await createViteServer({
47
55
  configFile: rwPaths.web.viteConfig,
56
+ envFile: false,
57
+ define: {
58
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
59
+ },
60
+ ssr: {
61
+ // Inline every file apart from node built-ins. We want vite/rollup to
62
+ // inline dependencies in the server build. This gets round runtime
63
+ // importing of "server-only" and other packages with poisoned imports.
64
+ //
65
+ // Files included in `noExternal` are files we want Vite to analyze
66
+ // As of vite 5.2 `true` here means "all except node built-ins"
67
+ // noExternal: true,
68
+ // TODO (RSC): Other frameworks build for RSC without `noExternal: true`.
69
+ // What are we missing here? When/why is that a better choice? I know
70
+ // we would have to explicitly add a bunch of packages to noExternal, if
71
+ // we wanted to go that route.
72
+ // noExternal: ['@tobbe.dev/rsc-test'],
73
+ // Can't inline prisma client (db calls fail at runtime) or react-dom
74
+ // (css pre-init failure)
75
+ // Server store has to be externalized, because it's a singleton (shared between FW and App)
76
+ external: [
77
+ "@prisma/client",
78
+ "@prisma/adapter-better-sqlite3",
79
+ "@prisma/fetch-engine",
80
+ "@prisma/internals",
81
+ "better-sqlite3",
82
+ "@cedarjs/auth-dbauth-api",
83
+ "@cedarjs/cookie-jar",
84
+ "@cedarjs/server-store",
85
+ "@simplewebauthn/server",
86
+ "graphql-scalars",
87
+ "minimatch",
88
+ "playwright",
89
+ "react-dom"
90
+ ],
91
+ resolve: {
92
+ // These conditions are used in the plugin pipeline, and only affect non-externalized
93
+ // dependencies during the SSR build. Which because of `noExternal: true` means all
94
+ // dependencies apart from node built-ins.
95
+ // TODO (RSC): What's the difference between `conditions` and
96
+ // `externalConditions`? When is one used over the other?
97
+ // conditions: ['react-server'],
98
+ // externalConditions: ['react-server'],
99
+ },
100
+ optimizeDeps: {
101
+ // We need Vite to optimize these dependencies so that they are resolved
102
+ // with the correct conditions. And so that CJS modules work correctly.
103
+ // include: [
104
+ // 'react/**/*',
105
+ // 'react-dom/server',
106
+ // 'react-dom/server.edge',
107
+ // 'rehackt',
108
+ // 'react-server-dom-webpack/server',
109
+ // 'react-server-dom-webpack/client',
110
+ // '@apollo/client/cache/*',
111
+ // '@apollo/client/utilities/*',
112
+ // '@apollo/client/react/hooks/*',
113
+ // 'react-fast-compare',
114
+ // 'invariant',
115
+ // 'shallowequal',
116
+ // 'graphql/language/*',
117
+ // 'stacktracey',
118
+ // 'deepmerge',
119
+ // 'fast-glob',
120
+ // ],
121
+ }
122
+ },
123
+ resolve: {
124
+ // conditions: ['react-server'],
125
+ },
48
126
  plugins: [
49
127
  cjsInterop({
50
128
  dependencies: [
@@ -58,16 +136,184 @@ async function createServer() {
58
136
  "@cedarjs/auth-!(dbauth)-web"
59
137
  ]
60
138
  }),
61
- rscEnabled && rscRoutesAutoLoader()
139
+ rscEnabled && rscRoutesAutoLoader(),
140
+ rscEnabled && rscSsrRouterImport()
62
141
  ],
63
142
  server: { middlewareMode: true },
64
143
  logLevel: "info",
65
144
  clearScreen: false,
66
145
  appType: "custom"
67
146
  });
147
+ globalThis.__cedarjs__vite_ssr_runtime = await createViteRuntime(viteSsrDevServer);
148
+ globalThis.__cedarjs__client_references = /* @__PURE__ */ new Set();
149
+ globalThis.__cedarjs__server_references = /* @__PURE__ */ new Set();
150
+ const viteRscServer = await createViteServer({
151
+ envFile: false,
152
+ define: {
153
+ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV)
154
+ },
155
+ ssr: {
156
+ // Inline every file apart from node built-ins. We want vite/rollup to
157
+ // inline dependencies in the server build. This gets round runtime
158
+ // importing of "server-only" and other packages with poisoned imports.
159
+ //
160
+ // Files included in `noExternal` are files we want Vite to analyze
161
+ // As of vite 5.2 `true` here means "all except node built-ins"
162
+ noExternal: true,
163
+ // TODO (RSC): Other frameworks build for RSC without `noExternal: true`.
164
+ // What are we missing here? When/why is that a better choice? I know
165
+ // we would have to explicitly add a bunch of packages to noExternal, if
166
+ // we wanted to go that route.
167
+ // noExternal: ['@tobbe.dev/rsc-test'],
168
+ // Can't inline prisma client (db calls fail at runtime) or react-dom
169
+ // (css pre-init failure)
170
+ // Server store has to be externalized, because it's a singleton (shared between FW and App)
171
+ external: [
172
+ "@prisma/client",
173
+ "@prisma/adapter-better-sqlite3",
174
+ "@prisma/fetch-engine",
175
+ "@prisma/internals",
176
+ "better-sqlite3",
177
+ "@cedarjs/auth-dbauth-api",
178
+ "@cedarjs/cookie-jar",
179
+ "@cedarjs/server-store",
180
+ "@cedarjs/structure",
181
+ "@simplewebauthn/server",
182
+ "graphql-scalars",
183
+ "minimatch",
184
+ "playwright",
185
+ "react-dom"
186
+ ],
187
+ resolve: {
188
+ // These conditions are used in the plugin pipeline, and only affect non-externalized
189
+ // dependencies during the SSR build. Which because of `noExternal: true` means all
190
+ // dependencies apart from node built-ins.
191
+ // TODO (RSC): What's the difference between `conditions` and
192
+ // `externalConditions`? When is one used over the other?
193
+ conditions: ["react-server"],
194
+ externalConditions: ["react-server"]
195
+ },
196
+ optimizeDeps: {
197
+ // We need Vite to optimize these dependencies so that they are resolved
198
+ // with the correct conditions. And so that CJS modules work correctly.
199
+ include: [
200
+ "react/**/*",
201
+ "react-dom/server",
202
+ "react-dom/server.edge",
203
+ "rehackt",
204
+ "react-server-dom-webpack/server",
205
+ "react-server-dom-webpack/server.edge",
206
+ "react-server-dom-webpack/client",
207
+ "react-server-dom-webpack/client.edge",
208
+ "@apollo/client/cache/*",
209
+ "@apollo/client/utilities/*",
210
+ "@apollo/client/react/hooks/*",
211
+ "react-fast-compare",
212
+ "invariant",
213
+ "shallowequal",
214
+ "graphql/language/*",
215
+ "stacktracey",
216
+ "deepmerge",
217
+ "fast-glob",
218
+ "@whatwg-node/fetch",
219
+ "busboy",
220
+ "cookie"
221
+ ],
222
+ // Without excluding `util` we get "TypeError: util.TextEncoder is not
223
+ // a constructor" in react-server-dom-webpack.server because it'll try
224
+ // to use Browserify's `util` instead of Node's. And Browserify's
225
+ // polyfill is missing TextEncoder+TextDecoder. The reason it's using
226
+ // the Browserify polyfill is because we have
227
+ // `vite-plugin-node-polyfills` as a dependency, and that'll add
228
+ // Browserify's `node-util` to `node_modules`, so when Vite goes to
229
+ // resolve `import { TextEncoder } from 'util` it'll find the one in
230
+ // `node_modules` instead of Node's internal version.
231
+ // We only see this in dev, and not in prod. I'm not entirely sure why
232
+ // but I have two guesses: 1. When RSC is enabled we don't actually use
233
+ // `vite-plugin-node-polyfill`, so some kind of tree shaking is
234
+ // happening, which prevents the issue from occurring. 2. In prod we
235
+ // only use Node's dependency resolution. Vite is not involved. And
236
+ // that difference in resolution is what prevents the issue from
237
+ // occurring.
238
+ exclude: ["util"]
239
+ }
240
+ },
241
+ resolve: {
242
+ conditions: ["react-server"]
243
+ },
244
+ plugins: [
245
+ {
246
+ name: "rsc-record-and-tranform-use-client-plugin",
247
+ transform(code, id, _options) {
248
+ globalThis.__cedarjs__client_references?.delete(id);
249
+ if (!/^(["'])use client\1/.test(code)) {
250
+ return void 0;
251
+ }
252
+ console.log(
253
+ "rsc-record-and-transform-use-client-plugin: adding client reference",
254
+ id
255
+ );
256
+ globalThis.__cedarjs__client_references?.add(id);
257
+ const fns = code.matchAll(/export function (\w+)\(/g);
258
+ const consts = code.matchAll(/export const (\w+) = \(/g);
259
+ const names = [...fns, ...consts].map(([, name]) => name);
260
+ const result = [
261
+ `import { registerClientReference } from "react-server-dom-webpack/server.edge";`,
262
+ "",
263
+ ...names.map((name) => {
264
+ return name === "default" ? `export default registerClientReference({}, "${id}", "${name}");` : `export const ${name} = registerClientReference({}, "${id}", "${name}");`;
265
+ })
266
+ ].join("\n");
267
+ console.log("rsc-record-and-transform-use-client-plugin result");
268
+ console.log(
269
+ result.split("\n").map((line, i) => ` ${i + 1}: ${line}`).join("\n")
270
+ );
271
+ return { code: result, map: null };
272
+ }
273
+ },
274
+ rscTransformUseServerPlugin("", {}),
275
+ // The rscTransformUseClientPlugin maps paths like
276
+ // /Users/tobbe/.../rw-app/node_modules/@tobbe.dev/rsc-test/dist/rsc-test.es.js
277
+ // to
278
+ // /Users/tobbe/.../rw-app/web/dist/ssr/assets/rsc0.js
279
+ // That's why it needs the `clientEntryFiles` data
280
+ // (It does other things as well, but that's why it needs clientEntryFiles)
281
+ // rscTransformUseClientPlugin(clientEntryFiles),
282
+ // rscTransformUseServerPlugin(outDir, serverEntryFiles),
283
+ rscRoutesImports(),
284
+ {
285
+ name: "rsc-hot-update",
286
+ handleHotUpdate(ctx) {
287
+ console.log("rsc-hot-update ctx.modules", ctx.modules);
288
+ return [];
289
+ }
290
+ }
291
+ ],
292
+ build: {
293
+ ssr: true
294
+ },
295
+ server: {
296
+ // We never call `viteRscServer.listen()`, so we should run this in
297
+ // middleware mode
298
+ middlewareMode: true,
299
+ // The hmr/fast-refresh websocket in this server collides with the one in
300
+ // the other Vite server. So we can either disable it or run it on a
301
+ // different port.
302
+ // TODO (RSC): Figure out if we should disable or just pick a different
303
+ // port
304
+ ws: false
305
+ // hmr: {
306
+ // port: 24679,
307
+ // },
308
+ },
309
+ appType: "custom",
310
+ // Using a unique cache dir here to not clash with our other vite server
311
+ cacheDir: "../node_modules/.vite-rsc"
312
+ });
313
+ globalThis.__cedarjs__vite_rsc_runtime = await createViteRuntime(viteRscServer);
68
314
  const handleWithMiddleware = (route) => {
69
315
  return createServerAdapter(async (req) => {
70
- const middlewareRouter = await createMiddlewareRouter(vite);
316
+ const middlewareRouter = await createMiddlewareRouter(viteSsrDevServer);
71
317
  const middleware = middlewareRouter.find(
72
318
  req.method,
73
319
  req.url
@@ -77,19 +323,22 @@ async function createServer() {
77
323
  }
78
324
  const [mwRes] = await invoke(req, middleware, {
79
325
  route,
80
- viteDevServer: vite
326
+ viteSsrDevServer
81
327
  });
82
328
  return mwRes.toResponse();
83
329
  });
84
330
  };
85
- app.use(vite.middlewares);
331
+ app.use(viteSsrDevServer.middlewares);
86
332
  if (rscEnabled) {
87
- const { createRscRequestHandler } = await import("./rsc/rscRequestHandler.js");
333
+ createWebSocketServer();
334
+ const { createRscRequestHandler } = await globalThis.__cedarjs__vite_rsc_runtime.executeUrl(
335
+ new URL("./rsc/rscRequestHandler.js", import.meta.url).pathname
336
+ );
88
337
  app.use(
89
338
  "/rw-rsc",
90
- createRscRequestHandler({
91
- getMiddlewareRouter: async () => createMiddlewareRouter(vite),
92
- viteDevServer: vite
339
+ await createRscRequestHandler({
340
+ getMiddlewareRouter: async () => createMiddlewareRouter(viteSsrDevServer),
341
+ viteSsrDevServer
93
342
  })
94
343
  );
95
344
  }
@@ -99,18 +348,22 @@ async function createServer() {
99
348
  routes,
100
349
  clientEntryPath: rwPaths.web.entryClient,
101
350
  getStylesheetLinks: (route) => {
102
- return getCssLinks({ rwPaths, route, vite });
351
+ return getCssLinks({
352
+ rwPaths,
353
+ route,
354
+ viteSsrDevServer
355
+ });
103
356
  },
104
357
  // Recreate middleware router on each request in dev
105
- getMiddlewareRouter: async () => createMiddlewareRouter(vite)
358
+ getMiddlewareRouter: async () => createMiddlewareRouter(viteSsrDevServer)
106
359
  },
107
- vite
360
+ viteSsrDevServer
108
361
  );
109
362
  app.get("*", createServerAdapter(routeHandler));
110
363
  app.post("*", handleWithMiddleware());
111
364
  const port = getConfig().web.port;
112
365
  console.log(`Started server on http://localhost:${port}`);
113
- return app.listen(port);
366
+ return server.listen(port);
114
367
  }
115
368
  let devApp = createServer();
116
369
  process.stdin.on("data", async (data) => {
@@ -125,11 +378,11 @@ process.stdin.on("data", async (data) => {
125
378
  function getCssLinks({
126
379
  rwPaths,
127
380
  route,
128
- vite
381
+ viteSsrDevServer
129
382
  }) {
130
383
  const appAndRouteModules = componentsModules(
131
384
  [rwPaths.web.app, route?.filePath].filter(Boolean),
132
- vite
385
+ viteSsrDevServer
133
386
  );
134
387
  const collectedCss = collectCssPaths(appAndRouteModules);
135
388
  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?.executeUrl(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"}