vite-plugin-react-server 0.1.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.
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/dist/build/createBuildConfig.d.ts +12 -0
- package/dist/build/createBuildConfig.d.ts.map +1 -0
- package/dist/build/createBuildConfig.js +55 -0
- package/dist/build/createBuildConfig.js.map +1 -0
- package/dist/checkFilesExist.d.ts +8 -0
- package/dist/checkFilesExist.d.ts.map +1 -0
- package/dist/checkFilesExist.js +61 -0
- package/dist/checkFilesExist.js.map +1 -0
- package/dist/collect-css-manifest.d.ts +4 -0
- package/dist/collect-css-manifest.d.ts.map +1 -0
- package/dist/collect-css-manifest.js +57 -0
- package/dist/collect-css-manifest.js.map +1 -0
- package/dist/components.d.ts +13 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +13 -0
- package/dist/components.js.map +1 -0
- package/dist/copy-dir.d.ts +4 -0
- package/dist/copy-dir.d.ts.map +1 -0
- package/dist/getEnv.d.ts +19 -0
- package/dist/getEnv.d.ts.map +1 -0
- package/dist/getEnv.js +76 -0
- package/dist/getEnv.js.map +1 -0
- package/dist/helpers/normalizedRelativePath.d.ts +9 -0
- package/dist/helpers/normalizedRelativePath.d.ts.map +1 -0
- package/dist/helpers/normalizedRelativePath.js +31 -0
- package/dist/helpers/normalizedRelativePath.js.map +1 -0
- package/dist/helpers/tryManifest.d.ts +8 -0
- package/dist/helpers/tryManifest.d.ts.map +1 -0
- package/dist/html/createPageLoader.d.ts +26 -0
- package/dist/html/createPageLoader.d.ts.map +1 -0
- package/dist/html/createPageLoader.js +70 -0
- package/dist/html/createPageLoader.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +6 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/module-graph.d.ts +10 -0
- package/dist/module-graph.d.ts.map +1 -0
- package/dist/options.d.ts +86 -0
- package/dist/options.d.ts.map +1 -0
- package/dist/options.js +251 -0
- package/dist/options.js.map +1 -0
- package/dist/plugin.d.ts +8 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +31 -0
- package/dist/plugin.js.map +1 -0
- package/dist/react-client/plugin.d.ts +4 -0
- package/dist/react-client/plugin.d.ts.map +1 -0
- package/dist/react-client/plugin.js +28 -0
- package/dist/react-client/plugin.js.map +1 -0
- package/dist/react-server/createDevMiddleware.d.ts +8 -0
- package/dist/react-server/createDevMiddleware.d.ts.map +1 -0
- package/dist/react-server/createDevServer.d.ts +4 -0
- package/dist/react-server/createDevServer.d.ts.map +1 -0
- package/dist/react-server/createHandler.d.ts +23 -0
- package/dist/react-server/createHandler.d.ts.map +1 -0
- package/dist/react-server/createHandler.js +110 -0
- package/dist/react-server/createHandler.js.map +1 -0
- package/dist/react-server/createReactNodeStreamer.d.ts +10 -0
- package/dist/react-server/createReactNodeStreamer.d.ts.map +1 -0
- package/dist/react-server/createRscStream.d.ts +4 -0
- package/dist/react-server/createRscStream.d.ts.map +1 -0
- package/dist/react-server/createRscStream.js +47 -0
- package/dist/react-server/createRscStream.js.map +1 -0
- package/dist/react-server/createSsrHandler.d.ts +4 -0
- package/dist/react-server/createSsrHandler.d.ts.map +1 -0
- package/dist/react-server/plugin.d.ts +8 -0
- package/dist/react-server/plugin.d.ts.map +1 -0
- package/dist/react-server/plugin.js +298 -0
- package/dist/react-server/plugin.js.map +1 -0
- package/dist/resolvePage.d.ts +19 -0
- package/dist/resolvePage.d.ts.map +1 -0
- package/dist/resolvePage.js +44 -0
- package/dist/resolvePage.js.map +1 -0
- package/dist/resolveProps.d.ts +19 -0
- package/dist/resolveProps.d.ts.map +1 -0
- package/dist/resolveProps.js +90 -0
- package/dist/resolveProps.js.map +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/transformer/index.d.ts +28 -0
- package/dist/transformer/index.d.ts.map +1 -0
- package/dist/transformer/index.js +54 -0
- package/dist/transformer/index.js.map +1 -0
- package/dist/transformer/preserveDirectives.d.ts +4 -0
- package/dist/transformer/preserveDirectives.d.ts.map +1 -0
- package/dist/transformer/preserveDirectives.js +72 -0
- package/dist/transformer/preserveDirectives.js.map +1 -0
- package/dist/transformer/preserver.d.ts +2 -0
- package/dist/transformer/preserver.d.ts.map +1 -0
- package/dist/transformer/transformer.d.ts +30 -0
- package/dist/transformer/transformer.d.ts.map +1 -0
- package/dist/transformer/transformer.js +80 -0
- package/dist/transformer/transformer.js.map +1 -0
- package/dist/transformer/types.d.ts +15 -0
- package/dist/transformer/types.d.ts.map +1 -0
- package/dist/types.d.ts +197 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/worker/createHtmlStream.d.ts +7 -0
- package/dist/worker/createHtmlStream.d.ts.map +1 -0
- package/dist/worker/createWorker.d.ts +3 -0
- package/dist/worker/createWorker.d.ts.map +1 -0
- package/dist/worker/createWorker.js +33 -0
- package/dist/worker/createWorker.js.map +1 -0
- package/dist/worker/loader.d.ts +15 -0
- package/dist/worker/loader.d.ts.map +1 -0
- package/dist/worker/renderPages.d.ts +18 -0
- package/dist/worker/renderPages.d.ts.map +1 -0
- package/dist/worker/renderPages.js +99 -0
- package/dist/worker/renderPages.js.map +1 -0
- package/dist/worker/types.d.ts +31 -0
- package/dist/worker/types.d.ts.map +1 -0
- package/dist/worker/worker.d.ts +7 -0
- package/dist/worker/worker.d.ts.map +1 -0
- package/package.json +116 -0
- package/src/build/createBuildConfig.ts +74 -0
- package/src/checkFilesExist.ts +67 -0
- package/src/collect-css-manifest.ts +76 -0
- package/src/components.tsx +14 -0
- package/src/copy-dir.ts +27 -0
- package/src/getEnv.ts +135 -0
- package/src/helpers/normalizedRelativePath.ts +59 -0
- package/src/helpers/tryManifest.ts +23 -0
- package/src/html/createPageLoader.ts +99 -0
- package/src/index.ts +4 -0
- package/src/manifest.ts +24 -0
- package/src/module-graph.ts +48 -0
- package/src/options.ts +351 -0
- package/src/plugin.ts +31 -0
- package/src/react-client/plugin.ts +34 -0
- package/src/react-server/createDevMiddleware.ts +75 -0
- package/src/react-server/createDevServer.ts +10 -0
- package/src/react-server/createHandler.ts +144 -0
- package/src/react-server/createReactNodeStreamer.ts +25 -0
- package/src/react-server/createRscStream.ts +52 -0
- package/src/react-server/createSsrHandler.ts +147 -0
- package/src/react-server/plugin.ts +349 -0
- package/src/resolvePage.ts +65 -0
- package/src/resolveProps.ts +122 -0
- package/src/server.tsx +0 -0
- package/src/transformer/README.md +44 -0
- package/src/transformer/index.ts +112 -0
- package/src/transformer/preserveDirectives.ts +100 -0
- package/src/transformer/preserver.ts +47 -0
- package/src/transformer/transformer.ts +123 -0
- package/src/transformer/types.ts +15 -0
- package/src/types.ts +245 -0
- package/src/worker/createHtmlStream.ts +76 -0
- package/src/worker/createWorker.ts +39 -0
- package/src/worker/loader.ts +16 -0
- package/src/worker/renderPages.ts +144 -0
- package/src/worker/types.ts +38 -0
- package/src/worker/worker.tsx +136 -0
- package/tsconfig.json +79 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { normalizePath } from "vite";
|
|
2
|
+
|
|
3
|
+
type NormalizedRelativePathOptions = {
|
|
4
|
+
// will automatically remove this part
|
|
5
|
+
root: string;
|
|
6
|
+
// will automatically see this as a optional extra part of the rootDir that will be removed
|
|
7
|
+
outDir: string | string[];
|
|
8
|
+
// will ensure it always starts with this path, if it does not it will be added
|
|
9
|
+
moduleBase: string;
|
|
10
|
+
// will ensure it never starts with a leading /, which in some cases is needed (vite entry), other cases it is not for example from project root /
|
|
11
|
+
noLeadingSlash: boolean;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export const createNormalizedRelativePath = (
|
|
15
|
+
options: NormalizedRelativePathOptions = {
|
|
16
|
+
root: process.cwd(),
|
|
17
|
+
outDir: ["dist", "build"],
|
|
18
|
+
moduleBase: "src",
|
|
19
|
+
noLeadingSlash: false,
|
|
20
|
+
}
|
|
21
|
+
) => {
|
|
22
|
+
const base =
|
|
23
|
+
options.noLeadingSlash && options.moduleBase.startsWith("/")
|
|
24
|
+
? options.moduleBase.slice(1)
|
|
25
|
+
: options.moduleBase;
|
|
26
|
+
const removeOutDir = Array.isArray(options.outDir)
|
|
27
|
+
? (path: string) =>
|
|
28
|
+
(options.outDir as string[])
|
|
29
|
+
.map((dir) => path.startsWith(dir))
|
|
30
|
+
.some((v) => v)
|
|
31
|
+
? path.slice(options.outDir[0].length)
|
|
32
|
+
: path
|
|
33
|
+
: (path: string) =>
|
|
34
|
+
(options.outDir as string) === path
|
|
35
|
+
? path.slice(options.outDir.length)
|
|
36
|
+
: path;
|
|
37
|
+
|
|
38
|
+
const removeRoot = (path: string) => {
|
|
39
|
+
const normalized = normalizePath(path);
|
|
40
|
+
const relative = normalized.startsWith(options.root)
|
|
41
|
+
? normalized.slice(options.root.length)
|
|
42
|
+
: normalized;
|
|
43
|
+
return relative;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const ensureModuleBase = (path: string) => {
|
|
47
|
+
if (options.noLeadingSlash && path.startsWith("/")) {
|
|
48
|
+
return path.slice(1);
|
|
49
|
+
}
|
|
50
|
+
if (!path.startsWith(base)) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`Path ${path} does not start with module base ${base}, this will not work down the line.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
return path;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
return (path: string) => ensureModuleBase(removeOutDir(removeRoot(path)));
|
|
59
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
|
|
4
|
+
type TryManifestOptions = {
|
|
5
|
+
root: string;
|
|
6
|
+
outDir: string;
|
|
7
|
+
ssrManifest: boolean;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function tryManifest(options: TryManifestOptions) {
|
|
11
|
+
const manifestPath = resolve(
|
|
12
|
+
options.root,
|
|
13
|
+
options.outDir,
|
|
14
|
+
".vite",
|
|
15
|
+
options.ssrManifest ? "ssr-manifest.json" : "manifest.json"
|
|
16
|
+
);
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(readFileSync(manifestPath, "utf-8"));
|
|
19
|
+
} catch (e) {
|
|
20
|
+
console.log("No manifest found", manifestPath);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { resolve as resolvePath } from "node:path";
|
|
2
|
+
import { load } from "react-server-dom-esm/node-loader";
|
|
3
|
+
import {
|
|
4
|
+
registerClientReference,
|
|
5
|
+
registerServerReference,
|
|
6
|
+
} from "react-server-dom-esm/server.node";
|
|
7
|
+
import { createNormalizedRelativePath } from "../helpers/normalizedRelativePath.js";
|
|
8
|
+
|
|
9
|
+
type CreatePageLoaderOptions = {
|
|
10
|
+
manifest: Record<string, { file: string }>;
|
|
11
|
+
root: string;
|
|
12
|
+
outDir: string;
|
|
13
|
+
moduleBase: string;
|
|
14
|
+
registerServer?: string[];
|
|
15
|
+
registerClient?: string[];
|
|
16
|
+
alwaysRegisterServer?: boolean;
|
|
17
|
+
alwaysRegisterClient?: boolean;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
type CreateDefaultLoaderOptions = {
|
|
21
|
+
id: string;
|
|
22
|
+
registerServer?: string[];
|
|
23
|
+
registerClient?: string[];
|
|
24
|
+
alwaysRegisterServer?: boolean;
|
|
25
|
+
alwaysRegisterClient?: boolean;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export const createDefaultLoader = ({
|
|
29
|
+
id,
|
|
30
|
+
registerServer,
|
|
31
|
+
registerClient,
|
|
32
|
+
alwaysRegisterServer = false,
|
|
33
|
+
alwaysRegisterClient = false,
|
|
34
|
+
}: CreateDefaultLoaderOptions) => {
|
|
35
|
+
const mapper = ([key, value]: [string, any]) => {
|
|
36
|
+
try {
|
|
37
|
+
if (
|
|
38
|
+
registerClient?.includes(key) ||
|
|
39
|
+
(alwaysRegisterClient && typeof value === "function")
|
|
40
|
+
) {
|
|
41
|
+
return [key, registerClientReference(value, id, key)];
|
|
42
|
+
}
|
|
43
|
+
if (
|
|
44
|
+
registerServer?.includes(key) ||
|
|
45
|
+
(alwaysRegisterServer && typeof value === "function")
|
|
46
|
+
) {
|
|
47
|
+
return [key, registerServerReference(value, id, key)];
|
|
48
|
+
}
|
|
49
|
+
return [key, value];
|
|
50
|
+
} catch (e) {
|
|
51
|
+
console.error("[RSC] Error registering reference:", key, value, e);
|
|
52
|
+
return [key, value];
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return async (url: string) =>
|
|
56
|
+
Object.fromEntries(Object.entries(await import(url)).map(mapper));
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const createPageLoader = ({
|
|
60
|
+
manifest,
|
|
61
|
+
root,
|
|
62
|
+
outDir,
|
|
63
|
+
moduleBase,
|
|
64
|
+
registerServer,
|
|
65
|
+
registerClient,
|
|
66
|
+
alwaysRegisterServer,
|
|
67
|
+
alwaysRegisterClient,
|
|
68
|
+
}: CreatePageLoaderOptions) => {
|
|
69
|
+
const pathNormalizer = createNormalizedRelativePath({
|
|
70
|
+
root,
|
|
71
|
+
outDir,
|
|
72
|
+
moduleBase,
|
|
73
|
+
noLeadingSlash: true,
|
|
74
|
+
});
|
|
75
|
+
return async (id: string) => {
|
|
76
|
+
const normalizedId = pathNormalizer(id);
|
|
77
|
+
const entry =
|
|
78
|
+
normalizedId in manifest
|
|
79
|
+
? manifest[normalizedId]
|
|
80
|
+
: Object.values(manifest).find((entry) => entry.file === normalizedId);
|
|
81
|
+
if (!entry) {
|
|
82
|
+
throw new Error(
|
|
83
|
+
`Could not find manifest entry for ${id}, ${normalizedId} from ${root}`
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const loaderResult = await load(
|
|
87
|
+
resolvePath(root, outDir, entry.file),
|
|
88
|
+
{ format: "module" },
|
|
89
|
+
createDefaultLoader({
|
|
90
|
+
id,
|
|
91
|
+
registerServer,
|
|
92
|
+
registerClient,
|
|
93
|
+
alwaysRegisterServer,
|
|
94
|
+
alwaysRegisterClient,
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
return loaderResult;
|
|
98
|
+
};
|
|
99
|
+
};
|
package/src/index.ts
ADDED
package/src/manifest.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Manifest } from "vite";
|
|
2
|
+
import { normalizePath } from "vite";
|
|
3
|
+
|
|
4
|
+
export interface RscManifest {
|
|
5
|
+
clientComponents: Record<string, string>;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function resolveManifestEntry(
|
|
9
|
+
id: string,
|
|
10
|
+
manifest: Manifest
|
|
11
|
+
): string | undefined {
|
|
12
|
+
// Try exact match
|
|
13
|
+
if (manifest[id]) {
|
|
14
|
+
return manifest[id].file;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Try normalized path
|
|
18
|
+
const normalizedId = normalizePath(id);
|
|
19
|
+
if (manifest[normalizedId]) {
|
|
20
|
+
return manifest[normalizedId].file;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ModuleNode, ViteDevServer } from "vite";
|
|
2
|
+
|
|
3
|
+
export interface ModuleWithDeps {
|
|
4
|
+
id: string;
|
|
5
|
+
deps: Set<string>;
|
|
6
|
+
css: Set<string>;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getModuleGraph(server: ViteDevServer) {
|
|
10
|
+
return {
|
|
11
|
+
async getModuleWithDeps(id: string): Promise<ModuleWithDeps> {
|
|
12
|
+
// Load module first to ensure it's in the module graph
|
|
13
|
+
await server.ssrLoadModule(id);
|
|
14
|
+
|
|
15
|
+
const resolvedId = await server.pluginContainer.resolveId(id, undefined, {
|
|
16
|
+
// Add ssr and react-server conditions
|
|
17
|
+
ssr: true,
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
if (!resolvedId) throw new Error(`Module not found: ${id}`);
|
|
21
|
+
|
|
22
|
+
const moduleNode = server.moduleGraph.getModuleById(resolvedId.id);
|
|
23
|
+
if (!moduleNode) throw new Error(`Module node not found: ${id}`);
|
|
24
|
+
|
|
25
|
+
const deps = new Set<string>();
|
|
26
|
+
const css = new Set<string>();
|
|
27
|
+
|
|
28
|
+
// Recursively collect dependencies
|
|
29
|
+
const collectDeps = (node: ModuleNode) => {
|
|
30
|
+
// Track CSS imports
|
|
31
|
+
if (node.id?.endsWith(".css") && node.id) {
|
|
32
|
+
css.add(node.id);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Track all dependencies
|
|
36
|
+
for (const dep of node.importedModules) {
|
|
37
|
+
if (dep.id && !deps.has(dep.id)) {
|
|
38
|
+
deps.add(dep.id);
|
|
39
|
+
collectDeps(dep);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
collectDeps(moduleNode);
|
|
45
|
+
return { id: moduleNode.id ?? "", deps, css };
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
package/src/options.ts
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import type { ConfigEnv, ResolvedConfig, UserConfig } from "vite";
|
|
3
|
+
import type { ResolvedUserOptions, StreamPluginOptions } from "./types.js";
|
|
4
|
+
// Default configuration values
|
|
5
|
+
export const DEFAULT_CONFIG = {
|
|
6
|
+
FILE_REGEX: /\.(m|c)?(j|t)sx?$/,
|
|
7
|
+
CLIENT_ASSETS_DIR: "assets",
|
|
8
|
+
RSC_DIR: "rsc",
|
|
9
|
+
MODULE_BASE: "src",
|
|
10
|
+
MODULE_BASE_PATH: "/src",
|
|
11
|
+
MODULE_BASE_URL: "/src",
|
|
12
|
+
PAGE: "/src/page/page.tsx",
|
|
13
|
+
PROPS: "/src/page/props.ts",
|
|
14
|
+
CLIENT_ENTRY: "/src/client.tsx",
|
|
15
|
+
PAGE_EXPORT: "Page",
|
|
16
|
+
PROPS_EXPORT: "props",
|
|
17
|
+
// relative from plugin root
|
|
18
|
+
WORKER_PATH: "worker/worker.tsx",
|
|
19
|
+
LOADER_PATH: "worker/loader.ts",
|
|
20
|
+
RSC_EXTENSION: ".rsc",
|
|
21
|
+
HTML: ({ children }: { children: any }) => children,
|
|
22
|
+
COLLECT_CSS: true,
|
|
23
|
+
COLLECT_ASSETS: true,
|
|
24
|
+
PAGE_PATTERN: "/src/page/**/*.page.tsx",
|
|
25
|
+
PROPS_PATTERN: "/src/page/**/*.props.ts",
|
|
26
|
+
DEV_PORT: 5173,
|
|
27
|
+
PREVIEW_PORT: 4173,
|
|
28
|
+
DEV_HOST: "localhost",
|
|
29
|
+
PREVIEW_HOST: "localhost",
|
|
30
|
+
ENV_PREFIX: "VITE_",
|
|
31
|
+
BUILD: {
|
|
32
|
+
pages: () => ["/"],
|
|
33
|
+
client: "dist/client",
|
|
34
|
+
server: "dist/server",
|
|
35
|
+
},
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
export const resolveConfig = <T extends ResolvedConfig>(
|
|
39
|
+
config: T,
|
|
40
|
+
resolvedUserConfig: UserConfig,
|
|
41
|
+
userOptions: ResolvedUserOptions
|
|
42
|
+
) => {
|
|
43
|
+
return {
|
|
44
|
+
...config,
|
|
45
|
+
build: {
|
|
46
|
+
...config.build,
|
|
47
|
+
assetsDir: config.build?.assetsDir ?? DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export const resolveUserConfig = (
|
|
53
|
+
condition: "react-client" | "react-server",
|
|
54
|
+
input: string[],
|
|
55
|
+
config: UserConfig,
|
|
56
|
+
configEnv: ConfigEnv,
|
|
57
|
+
userOptions: ResolvedUserOptions
|
|
58
|
+
):
|
|
59
|
+
| { type: "error"; error: Error }
|
|
60
|
+
| {
|
|
61
|
+
type: "success";
|
|
62
|
+
userConfig: Required<Pick<UserConfig, "root" | "build" | "mode">> &
|
|
63
|
+
Omit<UserConfig, "root" | "build" | "mode">;
|
|
64
|
+
} => {
|
|
65
|
+
const isReactServer = condition === "react-server";
|
|
66
|
+
const isViteServer = configEnv.command === "serve";
|
|
67
|
+
const isVitePreview = configEnv.isPreview;
|
|
68
|
+
|
|
69
|
+
if (isReactServer && configEnv.command === "build") {
|
|
70
|
+
if (!config.build?.rollupOptions?.input) {
|
|
71
|
+
config = {
|
|
72
|
+
...config,
|
|
73
|
+
build: {
|
|
74
|
+
...config.build,
|
|
75
|
+
rollupOptions: {
|
|
76
|
+
...config.build?.rollupOptions,
|
|
77
|
+
input: input
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (typeof config.build?.assetsDir === 'string' && userOptions.assetsDir !== config.build?.assetsDir) {
|
|
85
|
+
return {
|
|
86
|
+
type: "error",
|
|
87
|
+
error: new Error(
|
|
88
|
+
`assetsDir cannot be changed after the config has been resolved, before: ${userOptions.assetsDir}, after: ${config.build?.assetsDir}`
|
|
89
|
+
),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (isReactServer) {
|
|
94
|
+
if (configEnv.command === "build") {
|
|
95
|
+
if (!configEnv.isSsrBuild) {
|
|
96
|
+
return {
|
|
97
|
+
type: "error",
|
|
98
|
+
error: new Error(
|
|
99
|
+
"ssr must be true when using the server plugin, NODE_OPTIONS='--conditions react-server' vite build --ssr"
|
|
100
|
+
),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
} else if (!isViteServer) {
|
|
104
|
+
return {
|
|
105
|
+
type: "error",
|
|
106
|
+
error: new Error(
|
|
107
|
+
isViteServer
|
|
108
|
+
? `react-server condition was not set. Please use \`NODE_OPTIONS='--conditions react-server' vite${
|
|
109
|
+
isVitePreview ? " preview" : ""
|
|
110
|
+
}\``
|
|
111
|
+
: "react-server condition was not set. Please use `NODE_OPTIONS='--conditions react-server' vite build --ssr`"
|
|
112
|
+
),
|
|
113
|
+
};
|
|
114
|
+
} else if (!configEnv.isSsrBuild && configEnv.command !== 'serve') {
|
|
115
|
+
return {
|
|
116
|
+
type: "error",
|
|
117
|
+
error: new Error(
|
|
118
|
+
"Vite was run with the react-server condition, but is making a client build."
|
|
119
|
+
),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const { root: configRoot, mode: configMode, ...configRest } = config;
|
|
125
|
+
const { outDir: configOutDir, assetsDir: configAssetsDir, ssr: configSsr, manifest: configManifest, ssrManifest: configSsrManifest, target: configTarget, ...configBuildRest } = config.build ?? {};
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
type: "success",
|
|
129
|
+
userConfig: {
|
|
130
|
+
...configRest,
|
|
131
|
+
root: configRoot ?? userOptions.projectRoot ?? process.cwd(),
|
|
132
|
+
mode: configMode ?? process.env["NODE_ENV"] ?? "production",
|
|
133
|
+
build: {
|
|
134
|
+
...configBuildRest,
|
|
135
|
+
ssr: configSsr ?? isReactServer,
|
|
136
|
+
manifest: configManifest ?? true,
|
|
137
|
+
ssrManifest: configSsrManifest ?? true,
|
|
138
|
+
target: configTarget ?? "es2020",
|
|
139
|
+
outDir:
|
|
140
|
+
typeof configOutDir === "string"
|
|
141
|
+
? configOutDir
|
|
142
|
+
: isReactServer
|
|
143
|
+
? userOptions.build.server
|
|
144
|
+
: userOptions.build.client,
|
|
145
|
+
assetsDir:
|
|
146
|
+
typeof configAssetsDir === "string"
|
|
147
|
+
? configAssetsDir
|
|
148
|
+
: isReactServer
|
|
149
|
+
? ''
|
|
150
|
+
: DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
export const resolveOptions = (
|
|
157
|
+
options: StreamPluginOptions
|
|
158
|
+
):
|
|
159
|
+
| { type: "error"; error: Error }
|
|
160
|
+
| {
|
|
161
|
+
type: "success";
|
|
162
|
+
userOptions: ResolvedUserOptions;
|
|
163
|
+
} => {
|
|
164
|
+
const projectRoot = options.projectRoot ?? process.cwd();
|
|
165
|
+
/** the module base can be assumed to not have a leading slash */
|
|
166
|
+
const moduleBase =
|
|
167
|
+
typeof options.moduleBase === "string"
|
|
168
|
+
? options.moduleBase.startsWith(path.sep)
|
|
169
|
+
? options.moduleBase.slice(path.sep.length)
|
|
170
|
+
: options.moduleBase
|
|
171
|
+
: DEFAULT_CONFIG.MODULE_BASE;
|
|
172
|
+
|
|
173
|
+
if (
|
|
174
|
+
typeof options.moduleBase === "string" &&
|
|
175
|
+
options.moduleBase !== moduleBase
|
|
176
|
+
) {
|
|
177
|
+
return {
|
|
178
|
+
type: "error",
|
|
179
|
+
error: new Error(
|
|
180
|
+
`moduleBase ${options.moduleBase} is invalid, should be like ${moduleBase}`
|
|
181
|
+
),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const moduleBasePath =
|
|
186
|
+
typeof options.moduleBasePath === "string"
|
|
187
|
+
? !options.moduleBasePath.startsWith(path.sep)
|
|
188
|
+
? `${path.sep}${options.moduleBasePath}`
|
|
189
|
+
: options.moduleBasePath
|
|
190
|
+
: `${path.sep}${moduleBase}`;
|
|
191
|
+
|
|
192
|
+
if (!moduleBasePath.includes(moduleBase)) {
|
|
193
|
+
return {
|
|
194
|
+
type: "error",
|
|
195
|
+
error: new Error(
|
|
196
|
+
`moduleBasePath ${moduleBasePath} is invalid, should include moduleBase ${moduleBase}`
|
|
197
|
+
),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const moduleBaseURL =
|
|
202
|
+
typeof options.moduleBaseURL === "string"
|
|
203
|
+
? !options.moduleBaseURL.endsWith(moduleBasePath)
|
|
204
|
+
? path.join(options.moduleBaseURL, moduleBasePath)
|
|
205
|
+
: options.moduleBaseURL
|
|
206
|
+
: moduleBasePath;
|
|
207
|
+
|
|
208
|
+
if (!moduleBaseURL.includes(moduleBasePath)) {
|
|
209
|
+
return {
|
|
210
|
+
type: "error",
|
|
211
|
+
error: new Error(
|
|
212
|
+
`moduleBaseURL ${moduleBaseURL} is invalid, should include moduleBasePath ${moduleBasePath}`
|
|
213
|
+
),
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (
|
|
218
|
+
typeof options.moduleBaseURL === "string" &&
|
|
219
|
+
options.moduleBaseURL !== moduleBaseURL
|
|
220
|
+
) {
|
|
221
|
+
return {
|
|
222
|
+
type: "error",
|
|
223
|
+
error: new Error(
|
|
224
|
+
`moduleBaseURL ${options.moduleBaseURL} is invalid, should be like ${moduleBaseURL}`
|
|
225
|
+
),
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const build = options.build
|
|
230
|
+
? {
|
|
231
|
+
client: options.build.client ?? DEFAULT_CONFIG.BUILD.client,
|
|
232
|
+
pages: options.build.pages ?? DEFAULT_CONFIG.BUILD.pages,
|
|
233
|
+
server: options.build.server ?? DEFAULT_CONFIG.BUILD.server,
|
|
234
|
+
}
|
|
235
|
+
: DEFAULT_CONFIG.BUILD;
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
type: "success",
|
|
239
|
+
userOptions: {
|
|
240
|
+
moduleBase,
|
|
241
|
+
moduleBasePath,
|
|
242
|
+
moduleBaseURL,
|
|
243
|
+
build,
|
|
244
|
+
Page: options.Page ?? DEFAULT_CONFIG.PAGE,
|
|
245
|
+
props: options.props ?? DEFAULT_CONFIG.PROPS,
|
|
246
|
+
Html: options.Html ?? DEFAULT_CONFIG.HTML,
|
|
247
|
+
pageExportName: options.pageExportName ?? DEFAULT_CONFIG.PAGE_EXPORT,
|
|
248
|
+
propsExportName: options.propsExportName ?? DEFAULT_CONFIG.PROPS_EXPORT,
|
|
249
|
+
collectCss: options.collectCss ?? DEFAULT_CONFIG.COLLECT_CSS,
|
|
250
|
+
collectAssets: options.collectAssets ?? DEFAULT_CONFIG.COLLECT_ASSETS,
|
|
251
|
+
projectRoot: projectRoot,
|
|
252
|
+
assetsDir: options.assetsDir ?? DEFAULT_CONFIG.CLIENT_ASSETS_DIR,
|
|
253
|
+
} satisfies ResolvedUserOptions,
|
|
254
|
+
};
|
|
255
|
+
};
|
|
256
|
+
|
|
257
|
+
export async function resolvePages(
|
|
258
|
+
pages: ResolvedUserOptions["build"]["pages"]
|
|
259
|
+
): Promise<
|
|
260
|
+
| {
|
|
261
|
+
type: "success";
|
|
262
|
+
pages: string[];
|
|
263
|
+
}
|
|
264
|
+
| {
|
|
265
|
+
type: "error";
|
|
266
|
+
error: Error;
|
|
267
|
+
}
|
|
268
|
+
> {
|
|
269
|
+
if (!pages) {
|
|
270
|
+
return {
|
|
271
|
+
type: "success",
|
|
272
|
+
pages: [],
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
if (typeof pages === "function") {
|
|
276
|
+
try {
|
|
277
|
+
return resolvePages(await Promise.resolve(pages()));
|
|
278
|
+
} catch (error) {
|
|
279
|
+
return {
|
|
280
|
+
type: "error",
|
|
281
|
+
error:
|
|
282
|
+
error instanceof Error
|
|
283
|
+
? error
|
|
284
|
+
: new Error(
|
|
285
|
+
`build.pages must be a array of strings, or a (async) function that returns a string or an array of strings. Got "${JSON.stringify(
|
|
286
|
+
pages
|
|
287
|
+
)}"`,
|
|
288
|
+
{
|
|
289
|
+
cause: error,
|
|
290
|
+
}
|
|
291
|
+
),
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const result = pages;
|
|
297
|
+
const awaited = "then" in result ? await result : result;
|
|
298
|
+
if (typeof awaited === "string") {
|
|
299
|
+
return {
|
|
300
|
+
type: "success",
|
|
301
|
+
pages: [awaited],
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (Array.isArray(awaited)) {
|
|
305
|
+
if (awaited.every((page) => typeof page === "string")) {
|
|
306
|
+
return {
|
|
307
|
+
type: "success",
|
|
308
|
+
pages: awaited,
|
|
309
|
+
};
|
|
310
|
+
} else {
|
|
311
|
+
return {
|
|
312
|
+
type: "error",
|
|
313
|
+
error: new Error(
|
|
314
|
+
`build.pages must be a array of strings, or a (async) function that returns a string or an array of strings. Got "${JSON.stringify(
|
|
315
|
+
awaited.find((page) => typeof page !== "string")
|
|
316
|
+
)}"`,
|
|
317
|
+
{
|
|
318
|
+
cause: awaited,
|
|
319
|
+
}
|
|
320
|
+
),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return {
|
|
325
|
+
type: "error",
|
|
326
|
+
error: new Error(
|
|
327
|
+
`build.pages must be a array of strings, or a (async) function that returns a string or an array of strings. Got "${JSON.stringify(
|
|
328
|
+
pages
|
|
329
|
+
)}"`,
|
|
330
|
+
{
|
|
331
|
+
cause: pages,
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
};
|
|
335
|
+
} catch (error) {
|
|
336
|
+
return {
|
|
337
|
+
type: "error",
|
|
338
|
+
error:
|
|
339
|
+
error instanceof Error
|
|
340
|
+
? error
|
|
341
|
+
: new Error(
|
|
342
|
+
`build.pages must be a array of strings, or a (async) function that returns a string or an array of strings. Got "${JSON.stringify(
|
|
343
|
+
error
|
|
344
|
+
)}"`,
|
|
345
|
+
{
|
|
346
|
+
cause: error,
|
|
347
|
+
}
|
|
348
|
+
),
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
}
|
package/src/plugin.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { resolveOptions } from "./options.js";
|
|
2
|
+
import { viteReactClientTransformPlugin } from "./transformer/index.js";
|
|
3
|
+
import { preserveDirectives } from "./transformer/preserveDirectives.js";
|
|
4
|
+
import type { StreamPluginOptions } from "./types.js";
|
|
5
|
+
|
|
6
|
+
export const getCondition = (options: { env?: typeof process.env } = {}) => {
|
|
7
|
+
const nodeOptions = options?.env?.['NODE_OPTIONS'] ?? process.env['NODE_OPTIONS'];
|
|
8
|
+
return nodeOptions?.match(/--conditions=react-server/) ? "server" : "client";
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const reactStreamPlugin = async (options: StreamPluginOptions) => {
|
|
12
|
+
const condition = getCondition();
|
|
13
|
+
try {
|
|
14
|
+
const resolvedOptions = resolveOptions(options);
|
|
15
|
+
if (resolvedOptions.type === "error") {
|
|
16
|
+
throw resolvedOptions.error;
|
|
17
|
+
}
|
|
18
|
+
options = resolvedOptions.userOptions;
|
|
19
|
+
} catch (error) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`[vite:react-stream:${condition}] ${(error as Error).message}`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
return condition === "server"
|
|
25
|
+
? [
|
|
26
|
+
(await import(`./react-server/plugin.js`)).reactStreamPlugin(options),
|
|
27
|
+
viteReactClientTransformPlugin(),
|
|
28
|
+
preserveDirectives(),
|
|
29
|
+
]
|
|
30
|
+
: [(await import(`./react-client/plugin.js`)).reactStreamPlugin(options)];
|
|
31
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { Plugin } from "vite";
|
|
2
|
+
import {
|
|
3
|
+
resolveOptions,
|
|
4
|
+
resolvePages,
|
|
5
|
+
resolveUserConfig,
|
|
6
|
+
} from "../options.js";
|
|
7
|
+
import type { StreamPluginOptions } from "../types.js";
|
|
8
|
+
|
|
9
|
+
export async function reactStreamPlugin(
|
|
10
|
+
options: StreamPluginOptions
|
|
11
|
+
): Promise<Plugin> {
|
|
12
|
+
const resolvedOptions = resolveOptions(options);
|
|
13
|
+
if (resolvedOptions.type === "error") {
|
|
14
|
+
throw resolvedOptions.error;
|
|
15
|
+
}
|
|
16
|
+
const { userOptions } = resolvedOptions;
|
|
17
|
+
|
|
18
|
+
const resolvedPages = await resolvePages(userOptions.build.pages)
|
|
19
|
+
if(resolvedPages.type === "error") {
|
|
20
|
+
throw resolvedPages.error
|
|
21
|
+
}
|
|
22
|
+
const { pages } = resolvedPages
|
|
23
|
+
return {
|
|
24
|
+
name: "vite:react-stream",
|
|
25
|
+
config(config, configEnv) {
|
|
26
|
+
const resolvedConfig = resolveUserConfig("react-client", pages, config, configEnv, userOptions);
|
|
27
|
+
if (resolvedConfig.type === "error") {
|
|
28
|
+
throw resolvedConfig.error;
|
|
29
|
+
}
|
|
30
|
+
const { userConfig } = resolvedConfig;
|
|
31
|
+
return userConfig
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|