@kasperpeulen/vitest-plugin-nextjs 0.0.0-stage → 0.1.0-alpha.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 (250) hide show
  1. package/README.md +249 -2
  2. package/dist/_virtual/_rolldown/runtime.js +14 -0
  3. package/dist/action-ids.d.ts +18 -0
  4. package/dist/action-ids.js +44 -0
  5. package/dist/adapter.d.ts +8 -0
  6. package/dist/adapter.js +12 -0
  7. package/dist/app-requests.d.ts +63 -0
  8. package/dist/app-requests.js +253 -0
  9. package/dist/browser-context.d.ts +24 -0
  10. package/dist/browser-context.js +157 -0
  11. package/dist/build-output.d.ts +68 -0
  12. package/dist/build-output.js +216 -0
  13. package/dist/build.d.ts +26 -0
  14. package/dist/build.js +39 -0
  15. package/dist/built-files.d.ts +9 -0
  16. package/dist/built-files.js +22 -0
  17. package/dist/cache.d.ts +44 -0
  18. package/dist/cache.js +99 -0
  19. package/dist/client-components.d.ts +3 -0
  20. package/dist/client-components.js +4 -0
  21. package/dist/client-file-key.d.ts +5 -0
  22. package/dist/client-file-key.js +5 -0
  23. package/dist/client-files.d.ts +83 -0
  24. package/dist/client-files.js +186 -0
  25. package/dist/client-graph.d.ts +94 -0
  26. package/dist/client-graph.js +266 -0
  27. package/dist/client-modules.d.ts +10 -0
  28. package/dist/client-modules.js +43 -0
  29. package/dist/client.d.ts +42 -0
  30. package/dist/client.js +263 -0
  31. package/dist/commonjs.d.ts +44 -0
  32. package/dist/commonjs.js +111 -0
  33. package/dist/compat/browser/client.d.ts +19 -0
  34. package/dist/compat/browser/client.js +13 -0
  35. package/dist/compat/build.d.ts +145 -0
  36. package/dist/compat/build.js +149 -0
  37. package/dist/compat/checks.d.ts +16 -0
  38. package/dist/compat/checks.js +148 -0
  39. package/dist/compat/patches.d.ts +13 -0
  40. package/dist/compat/patches.js +30 -0
  41. package/dist/compat/paths.d.ts +74 -0
  42. package/dist/compat/paths.js +160 -0
  43. package/dist/compat/rsc/handlers.d.ts +2 -0
  44. package/dist/compat/rsc/handlers.js +2 -0
  45. package/dist/compat/rsc/prerender.d.ts +10 -0
  46. package/dist/compat/rsc/prerender.js +9 -0
  47. package/dist/compat/server/headers.d.ts +3 -0
  48. package/dist/compat/server/headers.js +3 -0
  49. package/dist/compat/ssr/build-output.d.ts +4 -0
  50. package/dist/compat/ssr/build-output.js +3 -0
  51. package/dist/compat/ssr/cache.d.ts +6 -0
  52. package/dist/compat/ssr/cache.js +6 -0
  53. package/dist/compat/ssr/handler.d.ts +8 -0
  54. package/dist/compat/ssr/handler.js +8 -0
  55. package/dist/compat/ssr/node-server.d.ts +5 -0
  56. package/dist/compat/ssr/node-server.js +4 -0
  57. package/dist/compat/ssr/render-errors.d.ts +4 -0
  58. package/dist/compat/ssr/render-errors.js +4 -0
  59. package/dist/compat/ssr/senders.d.ts +6 -0
  60. package/dist/compat/ssr/senders.js +6 -0
  61. package/dist/compat/types.d.ts +8 -0
  62. package/dist/compat/types.js +1 -0
  63. package/dist/compile.d.ts +31 -0
  64. package/dist/compile.js +140 -0
  65. package/dist/disk.d.ts +16 -0
  66. package/dist/disk.js +13 -0
  67. package/dist/document-loads.d.ts +15 -0
  68. package/dist/document-loads.js +53 -0
  69. package/dist/document.d.ts +79 -0
  70. package/dist/document.js +328 -0
  71. package/dist/downloads.d.ts +15 -0
  72. package/dist/downloads.js +71 -0
  73. package/dist/esm-require.d.ts +11 -0
  74. package/dist/esm-require.js +32 -0
  75. package/dist/fast-crypto/index.js +1093 -0
  76. package/dist/fast-crypto.d.ts +20 -0
  77. package/dist/fast-crypto.js +151 -0
  78. package/dist/flight.d.ts +19 -0
  79. package/dist/flight.js +42 -0
  80. package/dist/form-submission.d.ts +15 -0
  81. package/dist/form-submission.js +27 -0
  82. package/dist/from-page.d.ts +5 -0
  83. package/dist/from-page.js +44 -0
  84. package/dist/globals.d.ts +1 -0
  85. package/dist/globals.js +197 -0
  86. package/dist/host-document.d.ts +26 -0
  87. package/dist/host-document.js +34 -0
  88. package/dist/index.d.ts +280 -0
  89. package/dist/index.js +281 -0
  90. package/dist/internal.d.ts +2 -0
  91. package/dist/internal.js +3 -0
  92. package/dist/leftovers.d.ts +11 -0
  93. package/dist/leftovers.js +55 -0
  94. package/dist/mode.d.ts +169 -0
  95. package/dist/mode.js +31 -0
  96. package/dist/node/LICENSES.md +3540 -0
  97. package/dist/node/assert/strict.js +29 -0
  98. package/dist/node/assert.js +3044 -0
  99. package/dist/node/buffer.js +1499 -0
  100. package/dist/node/child_process.js +45 -0
  101. package/dist/node/cluster.js +85 -0
  102. package/dist/node/console.js +96 -0
  103. package/dist/node/constants.js +495 -0
  104. package/dist/node/crypto.js +1388 -0
  105. package/dist/node/dgram.js +78 -0
  106. package/dist/node/diagnostics_channel.js +122 -0
  107. package/dist/node/dns/promises.js +129 -0
  108. package/dist/node/dns.js +137 -0
  109. package/dist/node/domain.js +43 -0
  110. package/dist/node/events.js +1155 -0
  111. package/dist/node/fs/promises.js +40 -0
  112. package/dist/node/fs.js +10375 -0
  113. package/dist/node/http.js +326 -0
  114. package/dist/node/http2.js +305 -0
  115. package/dist/node/https.js +57 -0
  116. package/dist/node/inspector/promises.js +66 -0
  117. package/dist/node/inspector.js +76 -0
  118. package/dist/node/module.js +205 -0
  119. package/dist/node/net.js +392 -0
  120. package/dist/node/os.js +259 -0
  121. package/dist/node/path/posix.js +25 -0
  122. package/dist/node/path/win32.js +25 -0
  123. package/dist/node/path.js +384 -0
  124. package/dist/node/perf_hooks.js +313 -0
  125. package/dist/node/process.js +452 -0
  126. package/dist/node/punycode.js +178 -0
  127. package/dist/node/querystring.js +934 -0
  128. package/dist/node/readline/promises.js +71 -0
  129. package/dist/node/readline.js +56 -0
  130. package/dist/node/repl.js +44 -0
  131. package/dist/node/sqlite.js +22 -0
  132. package/dist/node/stream/consumers.js +47 -0
  133. package/dist/node/stream/promises.js +6 -0
  134. package/dist/node/stream/web.js +52 -0
  135. package/dist/node/stream.js +4323 -0
  136. package/dist/node/string_decoder.js +276 -0
  137. package/dist/node/sys.js +6 -0
  138. package/dist/node/timers/promises.js +71 -0
  139. package/dist/node/timers.js +133 -0
  140. package/dist/node/tls.js +122 -0
  141. package/dist/node/trace_events.js +23 -0
  142. package/dist/node/tty.js +69 -0
  143. package/dist/node/url.js +1426 -0
  144. package/dist/node/util/types.js +1456 -0
  145. package/dist/node/util.js +4807 -0
  146. package/dist/node/v8.js +160 -0
  147. package/dist/node/vm.js +88 -0
  148. package/dist/node/wasi.js +16 -0
  149. package/dist/node/worker_threads.js +123 -0
  150. package/dist/node/zlib.js +1396 -0
  151. package/dist/node-builtins.d.ts +40 -0
  152. package/dist/node-builtins.js +74 -0
  153. package/dist/node-on-page.d.ts +46 -0
  154. package/dist/node-on-page.js +101 -0
  155. package/dist/node-platform.d.ts +36 -0
  156. package/dist/node-platform.js +152 -0
  157. package/dist/node-rendered.d.ts +21 -0
  158. package/dist/node-rendered.js +26 -0
  159. package/dist/node-server.d.ts +46 -0
  160. package/dist/node-server.js +193 -0
  161. package/dist/optimizer-cache-key.d.ts +26 -0
  162. package/dist/optimizer-cache-key.js +73 -0
  163. package/dist/own-package.d.ts +1 -0
  164. package/dist/own-package.js +6 -0
  165. package/dist/page-store.d.ts +33 -0
  166. package/dist/page-store.js +80 -0
  167. package/dist/page-timers.d.ts +22 -0
  168. package/dist/page-timers.js +47 -0
  169. package/dist/page.d.ts +112 -0
  170. package/dist/page.js +549 -0
  171. package/dist/paths.d.ts +13 -0
  172. package/dist/paths.js +47 -0
  173. package/dist/plugin.d.ts +22 -0
  174. package/dist/plugin.js +995 -0
  175. package/dist/prerender-verdict.d.ts +8 -0
  176. package/dist/prerender-verdict.js +67 -0
  177. package/dist/project/context.d.ts +546 -0
  178. package/dist/project/context.js +111 -0
  179. package/dist/project/entries.d.ts +42 -0
  180. package/dist/project/entries.js +189 -0
  181. package/dist/project/env-worker.d.ts +1 -0
  182. package/dist/project/env-worker.js +9 -0
  183. package/dist/project/env.d.ts +36 -0
  184. package/dist/project/env.js +82 -0
  185. package/dist/project/layers.d.ts +31 -0
  186. package/dist/project/layers.js +150 -0
  187. package/dist/project/loaders.d.ts +71 -0
  188. package/dist/project/loaders.js +300 -0
  189. package/dist/project/metadata.d.ts +8 -0
  190. package/dist/project/metadata.js +34 -0
  191. package/dist/project/module-exports.d.ts +29 -0
  192. package/dist/project/module-exports.js +77 -0
  193. package/dist/project/routes.d.ts +19 -0
  194. package/dist/project/routes.js +92 -0
  195. package/dist/project/routing.d.ts +46 -0
  196. package/dist/project/routing.js +280 -0
  197. package/dist/project/transform.d.ts +8 -0
  198. package/dist/project/transform.js +110 -0
  199. package/dist/project/webpack.d.ts +46 -0
  200. package/dist/project/webpack.js +160 -0
  201. package/dist/project.d.ts +264 -0
  202. package/dist/project.js +58 -0
  203. package/dist/registry-global.d.ts +5 -0
  204. package/dist/registry-global.js +5 -0
  205. package/dist/registry.d.ts +241 -0
  206. package/dist/registry.js +30 -0
  207. package/dist/route-chunks.d.ts +13 -0
  208. package/dist/route-chunks.js +32 -0
  209. package/dist/route-lookup.d.ts +34 -0
  210. package/dist/route-lookup.js +207 -0
  211. package/dist/routes-ahead-shared.d.ts +17 -0
  212. package/dist/routes-ahead-shared.js +9 -0
  213. package/dist/routes-ahead.d.ts +10 -0
  214. package/dist/routes-ahead.js +54 -0
  215. package/dist/rsc.d.ts +19 -0
  216. package/dist/rsc.js +171 -0
  217. package/dist/server-action.d.ts +9 -0
  218. package/dist/server-action.js +15 -0
  219. package/dist/server-code.d.ts +176 -0
  220. package/dist/server-code.js +357 -0
  221. package/dist/server-in-front.d.ts +37 -0
  222. package/dist/server-in-front.js +90 -0
  223. package/dist/server-layers.d.ts +22 -0
  224. package/dist/server-layers.js +33 -0
  225. package/dist/setup-browser.d.ts +1 -0
  226. package/dist/setup-browser.js +8 -0
  227. package/dist/setup-node.d.ts +1 -0
  228. package/dist/setup-node.js +6 -0
  229. package/dist/setup.d.ts +8 -0
  230. package/dist/setup.js +62 -0
  231. package/dist/speed-features.d.ts +13 -0
  232. package/dist/speed-features.js +95 -0
  233. package/dist/ssr.d.ts +70 -0
  234. package/dist/ssr.js +480 -0
  235. package/dist/static-build.d.ts +36 -0
  236. package/dist/static-build.js +92 -0
  237. package/dist/storage.d.ts +31 -0
  238. package/dist/storage.js +94 -0
  239. package/dist/styles-shared.d.ts +137 -0
  240. package/dist/styles-shared.js +124 -0
  241. package/dist/styles.d.ts +102 -0
  242. package/dist/styles.js +730 -0
  243. package/dist/stylesheet-versions.d.ts +17 -0
  244. package/dist/stylesheet-versions.js +43 -0
  245. package/dist/tester.html +10 -0
  246. package/dist/use-cache.d.ts +15 -0
  247. package/dist/use-cache.js +93 -0
  248. package/dist/vitest-version.d.ts +6 -0
  249. package/dist/vitest-version.js +12 -0
  250. package/package.json +125 -3
@@ -0,0 +1,40 @@
1
+ import { esmExternalRequirePlugin } from "vite";
2
+
3
+ //#region src/node-builtins.d.ts
4
+ /**
5
+ * What the server layers import for a module of Node.js: the package's
6
+ * `stand-ins`, for a page in a browser, or Node's own, `native`, for a page in
7
+ * a worker of Node.js. A native module is no file: the layer leaves it to
8
+ * the runner to import, and so does a pre-bundle that imports it.
9
+ */
10
+ type NodeModules = "stand-ins" | "native";
11
+ /**
12
+ * What a server layer imports for `source`, a module of Node.js with or
13
+ * without `node:`, if it imports another module for it: the file of the
14
+ * package's module, `.../node/fs.js` for `node:fs`, or, `native`, the module
15
+ * of Node.js by its `node:` name.
16
+ */
17
+ declare function nodeModuleOf(source: string, modules: NodeModules): string | undefined;
18
+ /** Whether `id` is a file of the package's modules of Node.js. */
19
+ declare const isNodeModule: (id: string) => boolean;
20
+ /** Whether `id` is a module of Node.js itself, which `nodeModuleOf()` gives for `native`. */
21
+ declare const isNativeNodeModule: (id: string) => boolean;
22
+ /**
23
+ * The plugin of a server layer's optimizer for `native` modules: in a
24
+ * pre-bundle, a `require()` of a module of Node.js is an import of it, which
25
+ * the runner imports, and `module.exports` its default export, as Node.js
26
+ * gives it. Rolldown's runtime for a browser has no `require` to call. Also
27
+ * `async_hooks`, which the layer imports as the package's: the import is the
28
+ * layer's to resolve, to Node's own here (../async-hooks-node.ts), like the
29
+ * one of `@sentry/nextjs` for Node.js.
30
+ */
31
+ declare function nativeRequirePlugin(): ReturnType<typeof esmExternalRequirePlugin>;
32
+ /**
33
+ * What the package of `importer`, a dependency, says it uses for `source` in
34
+ * a browser, by its `browser` field: `false` for nothing, a file of its own
35
+ * as a string, or `undefined` where it says nothing. By the specifier as
36
+ * written: Vite maps `fs` and `node:fs` apart too.
37
+ */
38
+ declare function browserMapping(source: string, importer: string | undefined): false | string | undefined;
39
+ //#endregion
40
+ export { NodeModules, browserMapping, isNativeNodeModule, isNodeModule, nativeRequirePlugin, nodeModuleOf };
@@ -0,0 +1,74 @@
1
+ import { builtinModules, isBuiltin } from "node:module";
2
+ import { esmExternalRequirePlugin, normalizePath } from "vite";
3
+ import path from "node:path";
4
+ import fs from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ //#region src/node-builtins.ts
7
+ const ownFile = fileURLToPath(import.meta.url);
8
+ const nodeDir = normalizePath(path.join(path.dirname(ownFile), path.extname(ownFile) === ".ts" ? "../dist/node" : "./node")) + "/";
9
+ const extension = ".js";
10
+ const notHere = /* @__PURE__ */ new Set(["async_hooks"]);
11
+ const files = /* @__PURE__ */ new Map();
12
+ /**
13
+ * What a server layer imports for `source`, a module of Node.js with or
14
+ * without `node:`, if it imports another module for it: the file of the
15
+ * package's module, `.../node/fs.js` for `node:fs`, or, `native`, the module
16
+ * of Node.js by its `node:` name.
17
+ */
18
+ function nodeModuleOf(source, modules) {
19
+ if (!isBuiltin(source)) return;
20
+ const name = source.replace(/^node:/, "");
21
+ if (notHere.has(name)) return;
22
+ if (modules === "native") return `node:${name}`;
23
+ if (!files.has(name)) {
24
+ if (!fs.existsSync(nodeDir)) throw new Error(`vitest-plugin-rsc: no ${nodeDir}, the package is not built: run \`pnpm build\``);
25
+ const file = `${nodeDir}${name}${extension}`;
26
+ files.set(name, fs.existsSync(file) ? file : void 0);
27
+ }
28
+ return files.get(name);
29
+ }
30
+ /** Whether `id` is a file of the package's modules of Node.js. */
31
+ const isNodeModule = (id) => id.startsWith(nodeDir);
32
+ /** Whether `id` is a module of Node.js itself, which `nodeModuleOf()` gives for `native`. */
33
+ const isNativeNodeModule = (id) => id.startsWith("node:");
34
+ /**
35
+ * The plugin of a server layer's optimizer for `native` modules: in a
36
+ * pre-bundle, a `require()` of a module of Node.js is an import of it, which
37
+ * the runner imports, and `module.exports` its default export, as Node.js
38
+ * gives it. Rolldown's runtime for a browser has no `require` to call. Also
39
+ * `async_hooks`, which the layer imports as the package's: the import is the
40
+ * layer's to resolve, to Node's own here (../async-hooks-node.ts), like the
41
+ * one of `@sentry/nextjs` for Node.js.
42
+ */
43
+ function nativeRequirePlugin() {
44
+ const names = builtinModules.filter((name) => !name.startsWith("_") && (notHere.has(name) || nodeModuleOf(name, "native")));
45
+ const external = [.../* @__PURE__ */ new Set([...names, ...names.map((name) => name.replace(/^(?!node:)/, "node:"))])];
46
+ return esmExternalRequirePlugin({ external });
47
+ }
48
+ const browserFields = /* @__PURE__ */ new Map();
49
+ function browserFieldOf(dir) {
50
+ if (browserFields.has(dir)) return browserFields.get(dir);
51
+ let field;
52
+ const file = path.join(dir, "package.json");
53
+ const parent = path.dirname(dir);
54
+ if (fs.existsSync(file)) {
55
+ const { browser } = JSON.parse(fs.readFileSync(file, "utf8"));
56
+ field = typeof browser === "object" && browser ? browser : {};
57
+ } else if (parent !== dir) field = browserFieldOf(parent);
58
+ browserFields.set(dir, field);
59
+ return field;
60
+ }
61
+ /**
62
+ * What the package of `importer`, a dependency, says it uses for `source` in
63
+ * a browser, by its `browser` field: `false` for nothing, a file of its own
64
+ * as a string, or `undefined` where it says nothing. By the specifier as
65
+ * written: Vite maps `fs` and `node:fs` apart too.
66
+ */
67
+ function browserMapping(source, importer) {
68
+ const file = importer?.split("?")[0];
69
+ if (!file || !path.isAbsolute(file) || !/[\\/]node_modules[\\/]/.test(file)) return;
70
+ const mapping = browserFieldOf(path.dirname(file))?.[source];
71
+ return mapping === false || typeof mapping === "string" ? mapping : void 0;
72
+ }
73
+ //#endregion
74
+ export { browserMapping, isNativeNodeModule, isNodeModule, nativeRequirePlugin, nodeModuleOf };
@@ -0,0 +1,46 @@
1
+ //#region src/node-on-page.d.ts
2
+ /**
3
+ * What `NodeRendered` tells the node of its page. A shape, not the class:
4
+ * node-rendered.tsx is an entry of its own in the package, whose types have
5
+ * a copy of the class, and a class with private fields is only itself.
6
+ */
7
+ type NodeReports = Pick<NodeOnPage, "mounted" | "shown" | "hidden">;
8
+ declare class NodeOnPage {
9
+ #private;
10
+ constructor(pathname: string);
11
+ /**
12
+ * Renders the node again: `swap` puts the node with the next version where
13
+ * the server reads it, and then Next's router asks the server for the page
14
+ * again, one request for every call. Resolves once the page has committed
15
+ * that version or a later one, and run its effects. Rejects at once, and
16
+ * later, when the page no longer has the node.
17
+ */
18
+ rerender(swap: (version: number) => void): Promise<void>;
19
+ /** The page is at `pathname` now. At another than the node's, the node is not there. */
20
+ at(pathname: string): void;
21
+ /** From the page, in the commit that mounts the node: its router. */
22
+ mounted(refresh: () => void): void;
23
+ /**
24
+ * From the page, from a passive effect, after the effects of the node: it
25
+ * shows the node at `version`.
26
+ */
27
+ shown(version: number): void;
28
+ /** From the page: the node is no longer shown. Something else may be in its place. */
29
+ hidden(): void;
30
+ /**
31
+ * From the root of the page: React reported an error. For a node that is
32
+ * mounted, a boundary in it shows the error, or one around it does and the
33
+ * node is no longer shown. One that is not mounted by the end of the commit
34
+ * never will be: an error took its place before it hydrated.
35
+ */
36
+ errored(error: unknown): void;
37
+ /** Something else is in the node's place: a page it redirected to, an error page. */
38
+ replaced(): void;
39
+ /**
40
+ * The page was left: by `cleanup()`, `unmount()`, another `renderServer()`,
41
+ * the app or the dev server.
42
+ */
43
+ left(by: string): void;
44
+ }
45
+ //#endregion
46
+ export { NodeOnPage, NodeReports };
@@ -0,0 +1,101 @@
1
+ //#region src/node-on-page.ts
2
+ var NodeOnPage = class {
3
+ #pathname;
4
+ #version = 0;
5
+ #waiting = /* @__PURE__ */ new Set();
6
+ #shown = 0;
7
+ #refresh;
8
+ #error;
9
+ #gone;
10
+ constructor(pathname) {
11
+ this.#pathname = pathname;
12
+ }
13
+ /**
14
+ * Renders the node again: `swap` puts the node with the next version where
15
+ * the server reads it, and then Next's router asks the server for the page
16
+ * again, one request for every call. Resolves once the page has committed
17
+ * that version or a later one, and run its effects. Rejects at once, and
18
+ * later, when the page no longer has the node.
19
+ */
20
+ rerender(swap) {
21
+ if (this.#gone) return Promise.reject(this.#gone());
22
+ this.#error = void 0;
23
+ const version = ++this.#version;
24
+ swap(version);
25
+ const committed = new Promise((resolve, reject) => {
26
+ this.#waiting.add({
27
+ version,
28
+ resolve,
29
+ reject
30
+ });
31
+ });
32
+ this.#refresh?.();
33
+ return committed;
34
+ }
35
+ /** The page is at `pathname` now. At another than the node's, the node is not there. */
36
+ at(pathname) {
37
+ if (pathname !== this.#pathname) this.replaced();
38
+ }
39
+ /** From the page, in the commit that mounts the node: its router. */
40
+ mounted(refresh) {
41
+ if (this.#gone) return;
42
+ const first = !this.#refresh;
43
+ this.#refresh = refresh;
44
+ if (first && this.#waiting.size > 0) refresh();
45
+ }
46
+ /**
47
+ * From the page, from a passive effect, after the effects of the node: it
48
+ * shows the node at `version`.
49
+ */
50
+ shown(version) {
51
+ this.#shown++;
52
+ if (this.#gone) return;
53
+ this.#error = void 0;
54
+ for (const waiting of this.#waiting) {
55
+ if (waiting.version > version) continue;
56
+ this.#waiting.delete(waiting);
57
+ waiting.resolve();
58
+ }
59
+ }
60
+ /** From the page: the node is no longer shown. Something else may be in its place. */
61
+ hidden() {
62
+ this.#shown--;
63
+ Promise.resolve().then(() => {
64
+ if (this.#shown === 0) this.replaced();
65
+ });
66
+ }
67
+ /**
68
+ * From the root of the page: React reported an error. For a node that is
69
+ * mounted, a boundary in it shows the error, or one around it does and the
70
+ * node is no longer shown. One that is not mounted by the end of the commit
71
+ * never will be: an error took its place before it hydrated.
72
+ */
73
+ errored(error) {
74
+ this.#error = error;
75
+ Promise.resolve().then(() => {
76
+ if (!this.#refresh) this.replaced();
77
+ });
78
+ }
79
+ /** Something else is in the node's place: a page it redirected to, an error page. */
80
+ replaced() {
81
+ if (this.#gone) return;
82
+ const cause = this.#error;
83
+ const error = () => Object.assign(new Error("vitest-plugin-rsc: rerender() renders the node again in its place, and the page has something else there: an error or a not-found page, a page the node redirected to, or a route the app navigated to. Render the node with renderServer() instead.", cause === void 0 ? void 0 : { cause }), { name: "NodeReplacedError" });
84
+ this.#leave(error, error());
85
+ }
86
+ /**
87
+ * The page was left: by `cleanup()`, `unmount()`, another `renderServer()`,
88
+ * the app or the dev server.
89
+ */
90
+ left(by) {
91
+ if (this.#gone) return;
92
+ this.#leave(() => /* @__PURE__ */ new Error(`vitest-plugin-rsc: rerender() renders the node again on its page, which ${by} has left. Render the node with renderServer() instead.`), new DOMException(`The page was left before the node had rendered again: by ${by}.`, "AbortError"));
93
+ }
94
+ #leave(gone, reason) {
95
+ this.#gone = gone;
96
+ for (const waiting of this.#waiting) waiting.reject(reason);
97
+ this.#waiting.clear();
98
+ }
99
+ };
100
+ //#endregion
101
+ export { NodeOnPage };
@@ -0,0 +1,36 @@
1
+ import { Plugin } from "vite";
2
+ import MagicString from "magic-string";
3
+
4
+ //#region src/node-platform.d.ts
5
+ /** An export of a module of Next that its stand-in does not have. */
6
+ type NewExport = {
7
+ name: string;
8
+ module: string;
9
+ };
10
+ /**
11
+ * The stand-ins, for a `registry` in the browser that some of them call and a
12
+ * `prefix` that their module ids start with.
13
+ */
14
+ declare function createNodePlatform(registry: string, prefix: string): {
15
+ /** The id of the stand-in for a specifier of a server layer, if it has one. */moduleOf(source: string): string | undefined;
16
+ /**
17
+ * The code of a stand-in, by its id without the prefix, with a stub for
18
+ * each export of Next's module that it has not, of the installed `version`.
19
+ */
20
+ load(name: string, newExports?: NewExport[], version?: string): string | undefined;
21
+ };
22
+ /**
23
+ * The code of the module of Next that loads `instrumentation.ts`, with a
24
+ * `require` that finds no file. Or why it cannot have one: its one use of
25
+ * `require` has to be a call that loads the file, or this is a Next that
26
+ * loads it otherwise.
27
+ */
28
+ declare function instrumentationRequire(code: string): MagicString | string;
29
+ /**
30
+ * Next's module that loads `instrumentation.ts`, with a `require` that finds
31
+ * no file: for the dependency optimizer of a server layer, and for a static
32
+ * build, which has no optimizer.
33
+ */
34
+ declare function instrumentationPlugin(): Plugin;
35
+ //#endregion
36
+ export { NewExport, createNodePlatform, instrumentationPlugin, instrumentationRequire };
@@ -0,0 +1,152 @@
1
+ import { missingHelper, walk } from "./commonjs.js";
2
+ import { instrumentationModule, nodePlatformModuleOf, nodePlatformModules } from "./compat/paths.js";
3
+ import { parseAst } from "vite";
4
+ import MagicString from "magic-string";
5
+ //#region src/node-platform.ts
6
+ const newExportHelper = `const $$newExport = (message) => {
7
+ const fail = () => { throw new Error(message); };
8
+ return new Proxy(function () {}, {
9
+ apply: fail,
10
+ construct: fail,
11
+ get: (_, key) =>
12
+ typeof key === "symbol" || key === "__esModule" || key === "then" ? undefined : fail(),
13
+ });
14
+ };
15
+ `;
16
+ function newExportStubs(newExports, version) {
17
+ if (newExports.length === 0) return "";
18
+ return newExportHelper + newExports.map(({ name, module }, index) => {
19
+ const message = `vitest-plugin-rsc: next@${version} has \`${name}\` in ${module}, which the plugin's stand-in for that module does not have. Use a version of @kasperpeulen/vitest-plugin-nextjs that supports next@${version}.`;
20
+ return `const $$new${index} = /* @__PURE__ */ $$newExport(${JSON.stringify(message)});\nexport { $$new${index} as ${JSON.stringify(name)} };\n`;
21
+ }).join("");
22
+ }
23
+ /**
24
+ * The stand-ins, for a `registry` in the browser that some of them call and a
25
+ * `prefix` that their module ids start with.
26
+ */
27
+ function createNodePlatform(registry, prefix) {
28
+ const forward = (owner, names) => names.map((name) => `export const ${name} = (...args) => ${registry}.${owner}.${name}(...args);`).join("\n");
29
+ const stagedRendering = `throw new Error(${JSON.stringify("vitest-plugin-rsc: Next's staged rendering, for Cache Components, is not supported.")});`;
30
+ const modules = {
31
+ "react-server-node": forward("flightServer", [
32
+ "createTemporaryReferenceSet",
33
+ "decodeReply",
34
+ "decodeReplyFromBusboy",
35
+ "decodeAction",
36
+ "decodeFormState"
37
+ ]),
38
+ "load-manifest": forward("node", [
39
+ "loadManifest",
40
+ "evalManifest",
41
+ "loadManifestFromRelativePath",
42
+ "evalManifestFromRelativePath"
43
+ ]) + `\nexport const clearManifestCache = () => false;`,
44
+ "node-environment": `
45
+ export const installProcessErrorHandlers = () => {};
46
+ export const isUnhandledRejectionListenerRegistered = () => false;
47
+ export const registerUnhandledRejectionListener = () => {};
48
+ export const setAbortedLogsStyle = () => {};
49
+ `,
50
+ "vendored-react": `
51
+ export const React = undefined;
52
+ export const ReactDOM = undefined;
53
+ export const ReactDOMServer = undefined;
54
+ export const ReactJsxDevRuntime = undefined;
55
+ export const ReactJsxRuntime = undefined;
56
+ export const ReactCompilerRuntime = undefined;
57
+ export const ReactServerDOMTurbopackClient = undefined;
58
+ export const ReactServerDOMTurbopackServer = undefined;
59
+ export const ReactServerDOMTurbopackStatic = undefined;
60
+ export const ReactServerDOMWebpackClient = undefined;
61
+ export const ReactServerDOMWebpackServer = undefined;
62
+ export const ReactServerDOMWebpackStatic = undefined;
63
+ `,
64
+ "gzip-size": `
65
+ export const sync = () => 0;
66
+ export default { sync };
67
+ `,
68
+ "fast-set-immediate": `
69
+ export const unpatchedSetImmediate = (...args) => ${registry}.setImmediate(...args);
70
+ export function DANGEROUSLY_runPendingImmediatesAfterCurrentTask() {
71
+ ${stagedRendering}
72
+ }
73
+ export function expectNoPendingImmediates() {}
74
+ export class ImmediateTracker {
75
+ constructor() {
76
+ ${stagedRendering}
77
+ }
78
+ }
79
+ export function runWithNativeImmediateTracking() {
80
+ ${stagedRendering}
81
+ }
82
+ `,
83
+ "ssr-app-page-module": `
84
+ export const AppPageRouteModule = new Proxy(class {}, {
85
+ construct: (_, args) => new ${registry}.ssr.AppPageRouteModule(...args),
86
+ });
87
+ export default AppPageRouteModule;
88
+ export const vendored = new Proxy({}, {
89
+ get: (_, key) => ${registry}.ssr.vendored[key],
90
+ });
91
+ ${forward("ssr", ["renderToHTMLOrFlight", "prerenderToHTMLOrFlight"])}
92
+ `
93
+ };
94
+ const names = new Map(Object.entries(nodePlatformModules).flatMap(([name, nextModules]) => nextModules.map((nextModule) => [nextModule, name])));
95
+ return {
96
+ /** The id of the stand-in for a specifier of a server layer, if it has one. */
97
+ moduleOf(source) {
98
+ const name = names.get(nodePlatformModuleOf(source) ?? "");
99
+ return name && prefix + name;
100
+ },
101
+ /**
102
+ * The code of a stand-in, by its id without the prefix, with a stub for
103
+ * each export of Next's module that it has not, of the installed `version`.
104
+ */
105
+ load(name, newExports = [], version = "") {
106
+ const code = modules[name];
107
+ return code === void 0 ? void 0 : code + newExportStubs(newExports, version);
108
+ }
109
+ };
110
+ }
111
+ const missingRequire = "$$cjsMissing";
112
+ const hookFilename = "INSTRUMENTATION_HOOK_FILENAME";
113
+ /** The files of the module of Next that loads `instrumentation.ts`, of either build. */
114
+ const instrumentationFile = new RegExp(`/next/dist/(?:esm/)?${instrumentationModule.replaceAll(".", "\\.")}\\.js$`);
115
+ /**
116
+ * The code of the module of Next that loads `instrumentation.ts`, with a
117
+ * `require` that finds no file. Or why it cannot have one: its one use of
118
+ * `require` has to be a call that loads the file, or this is a Next that
119
+ * loads it otherwise.
120
+ */
121
+ function instrumentationRequire(code) {
122
+ const uses = [];
123
+ for (const [node, parent] of walk(parseAst(code))) if (node.type === "Identifier" && node.name === "require") uses.push([node, parent]);
124
+ const [use, call] = uses[0] ?? [];
125
+ if (!(uses.length === 1 && call?.type === "CallExpression" && call.callee === use && [...walk(call)].some(([node]) => node.type === "Identifier" && node.name === hookFilename))) return `\`require\` ${uses.length === 1 ? "once" : `${uses.length} times`}, and not as the one call that loads \`${hookFilename}\``;
126
+ const replaced = new MagicString(code);
127
+ replaced.overwrite(use.start, use.end, missingRequire);
128
+ return replaced.prepend(missingHelper);
129
+ }
130
+ /**
131
+ * Next's module that loads `instrumentation.ts`, with a `require` that finds
132
+ * no file: for the dependency optimizer of a server layer, and for a static
133
+ * build, which has no optimizer.
134
+ */
135
+ function instrumentationPlugin() {
136
+ return {
137
+ name: "vitest-plugin-rsc:next-instrumentation",
138
+ transform: {
139
+ filter: { id: instrumentationFile },
140
+ handler(code, id) {
141
+ const replaced = instrumentationRequire(code);
142
+ if (typeof replaced === "string") throw new Error(`vitest-plugin-rsc: ${id} has ${replaced}.`);
143
+ return {
144
+ code: replaced.toString(),
145
+ map: replaced.generateMap({ hires: "boundary" })
146
+ };
147
+ }
148
+ }
149
+ };
150
+ }
151
+ //#endregion
152
+ export { createNodePlatform, instrumentationPlugin, instrumentationRequire };
@@ -0,0 +1,21 @@
1
+ import { NodeReports } from "./node-on-page.js";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/node-rendered.d.ts
5
+ /** @internal For client.tsx, as it starts the page. */
6
+ declare function setNodeOnPage(node: NodeReports | undefined): void;
7
+ /**
8
+ * @internal What the server renders around the node of `renderServer()`, from
9
+ * its first render: it tells `rerender()` the page's router once the node is
10
+ * mounted, which render of the node the page shows, and when the node has
11
+ * left the page. It renders the node and nothing else.
12
+ */
13
+ declare function NodeRendered({
14
+ version,
15
+ children
16
+ }: {
17
+ version: number;
18
+ children?: ReactNode;
19
+ }): ReactNode;
20
+ //#endregion
21
+ export { NodeRendered, setNodeOnPage };
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { useRouter } from "next/navigation.js";
3
+ import { useEffect, useLayoutEffect } from "react";
4
+ //#region src/node-rendered.tsx
5
+ let nodeOnPage;
6
+ /** @internal For client.tsx, as it starts the page. */
7
+ function setNodeOnPage(node) {
8
+ nodeOnPage = node;
9
+ }
10
+ /**
11
+ * @internal What the server renders around the node of `renderServer()`, from
12
+ * its first render: it tells `rerender()` the page's router once the node is
13
+ * mounted, which render of the node the page shows, and when the node has
14
+ * left the page. It renders the node and nothing else.
15
+ */
16
+ function NodeRendered({ version, children }) {
17
+ const { refresh } = useRouter();
18
+ useLayoutEffect(() => nodeOnPage?.mounted(refresh), [refresh]);
19
+ useEffect(() => {
20
+ nodeOnPage?.shown(version);
21
+ return () => nodeOnPage?.hidden();
22
+ }, [version]);
23
+ return children;
24
+ }
25
+ //#endregion
26
+ export { NodeRendered, setNodeOnPage };
@@ -0,0 +1,46 @@
1
+ import { RequestHandler, ServerRequest } from "./registry.js";
2
+ import { RequestMeta } from "./compat/ssr/node-server.js";
3
+
4
+ //#region src/node-server.d.ts
5
+ /**
6
+ * How the body of a response of `handleRequest()` is written: `written`
7
+ * resolves once it ends, whole or not, and `stop` ends it as a page that is
8
+ * left does. The server writes on whether it is read or not: nothing waits
9
+ * for a reader.
10
+ */
11
+ type Writing = {
12
+ written: Promise<void>;
13
+ stop: () => void;
14
+ };
15
+ /** The `Writing` of a response of `handleRequest()` with a body. */
16
+ declare const writingOf: (response: Response) => Writing | undefined;
17
+ declare const isPrerenderBailout: (error: unknown) => boolean;
18
+ /**
19
+ * Counts the bail-outs that Next's handler reports for the prerender that
20
+ * starts now: also those it answers with its error page itself, where its
21
+ * render of a page recovers from the error (`app-page-runtime.js:1133-1224`).
22
+ * The function it returns ends the count and answers it, once: a count that
23
+ * stays would get the bail-outs of the prerenders after it.
24
+ */
25
+ declare function countBailouts(): () => number;
26
+ /**
27
+ * What the server in front of a route knows of a request that it routed: see
28
+ * `handle()` in ssr.ts.
29
+ */
30
+ type RoutedRequestMeta = Pick<RequestMeta, "params" | "query">;
31
+ /**
32
+ * One request, by the request handler Next's build makes for its route:
33
+ * `templates/app-page-runtime` for a page and `templates/app-route` for a
34
+ * route handler, as `next start` calls them.
35
+ */
36
+ declare function handleRequest(request: ServerRequest, context: {
37
+ waitUntil?: (promise: Promise<unknown>) => void;
38
+ }, handler: RequestHandler, routed?: RoutedRequestMeta, {
39
+ statusCode,
40
+ headers
41
+ }?: {
42
+ statusCode?: number;
43
+ headers?: Headers;
44
+ }): Promise<Response>;
45
+ //#endregion
46
+ export { RoutedRequestMeta, Writing, countBailouts, handleRequest, isPrerenderBailout, writingOf };