@lazarv/react-server 0.0.0-experimental-43e79e6-20230928
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 +5 -0
- package/bin/cli.mjs +93 -0
- package/bin/commands/build.mjs +19 -0
- package/bin/commands/dev.mjs +23 -0
- package/bin/commands/start.mjs +16 -0
- package/bin/loader.mjs +38 -0
- package/client/ActionState.mjs +16 -0
- package/client/ClientOnly.jsx +14 -0
- package/client/ClientProvider.jsx +243 -0
- package/client/ErrorBoundary.jsx +45 -0
- package/client/FlightContext.mjs +3 -0
- package/client/Link.jsx +59 -0
- package/client/Params.mjs +15 -0
- package/client/ReactServerComponent.jsx +77 -0
- package/client/Refresh.jsx +52 -0
- package/client/components.mjs +28 -0
- package/client/context.mjs +6 -0
- package/client/entry.client.jsx +146 -0
- package/client/index.jsx +6 -0
- package/client/navigation.jsx +4 -0
- package/config/context.mjs +37 -0
- package/config/index.mjs +114 -0
- package/lib/build/action.mjs +57 -0
- package/lib/build/banner.mjs +13 -0
- package/lib/build/chunks.mjs +26 -0
- package/lib/build/client.mjs +114 -0
- package/lib/build/custom-logger.mjs +13 -0
- package/lib/build/dependencies.mjs +54 -0
- package/lib/build/resolve.mjs +101 -0
- package/lib/build/server.mjs +142 -0
- package/lib/build/static.mjs +89 -0
- package/lib/dev/action.mjs +63 -0
- package/lib/dev/create-logger.mjs +52 -0
- package/lib/dev/create-server.mjs +208 -0
- package/lib/dev/modules.mjs +20 -0
- package/lib/dev/ssr-handler.mjs +135 -0
- package/lib/handlers/error.mjs +153 -0
- package/lib/handlers/not-found.mjs +5 -0
- package/lib/handlers/redirect.mjs +1 -0
- package/lib/handlers/rewrite.mjs +1 -0
- package/lib/handlers/static.mjs +120 -0
- package/lib/handlers/trailing-slash.mjs +12 -0
- package/lib/plugins/react-server.mjs +73 -0
- package/lib/plugins/use-client.mjs +135 -0
- package/lib/plugins/use-server.mjs +175 -0
- package/lib/start/action.mjs +110 -0
- package/lib/start/create-server.mjs +111 -0
- package/lib/start/manifest.mjs +104 -0
- package/lib/start/ssr-handler.mjs +134 -0
- package/lib/sys.mjs +49 -0
- package/lib/utils/merge.mjs +31 -0
- package/lib/utils/server-address.mjs +14 -0
- package/memory-cache/index.mjs +125 -0
- package/package.json +81 -0
- package/react-server.d.ts +209 -0
- package/server/ErrorBoundary.jsx +14 -0
- package/server/RemoteComponent.jsx +210 -0
- package/server/Route.jsx +108 -0
- package/server/actions.mjs +72 -0
- package/server/cache.mjs +19 -0
- package/server/client-component.mjs +62 -0
- package/server/context.mjs +32 -0
- package/server/cookies.mjs +14 -0
- package/server/entry.server.jsx +972 -0
- package/server/error-boundary.jsx +2 -0
- package/server/http-headers.mjs +8 -0
- package/server/http-status.mjs +6 -0
- package/server/index.mjs +14 -0
- package/server/logger.mjs +15 -0
- package/server/module-loader.mjs +20 -0
- package/server/redirects.mjs +45 -0
- package/server/remote-component.jsx +2 -0
- package/server/request.mjs +37 -0
- package/server/revalidate.mjs +22 -0
- package/server/rewrites.mjs +0 -0
- package/server/router.jsx +6 -0
- package/server/runtime.mjs +32 -0
- package/server/symbols.mjs +24 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import { createMiddleware } from "@hattip/adapter-node";
|
|
5
|
+
import { compose } from "@hattip/compose";
|
|
6
|
+
import { cookie } from "@hattip/cookie";
|
|
7
|
+
import { cors } from "@hattip/cors";
|
|
8
|
+
import { parseMultipartFormData } from "@hattip/multipart";
|
|
9
|
+
import react from "@vitejs/plugin-react";
|
|
10
|
+
import { createServer as createViteDevServer } from "vite";
|
|
11
|
+
|
|
12
|
+
import { MemoryCache } from "../../memory-cache/index.mjs";
|
|
13
|
+
import packageJson from "../../package.json" assert { type: "json" };
|
|
14
|
+
import { getRuntime, runtime$ } from "../../server/runtime.mjs";
|
|
15
|
+
import {
|
|
16
|
+
COLLECT_STYLESHEETS,
|
|
17
|
+
CONFIG_CONTEXT,
|
|
18
|
+
CONFIG_ROOT,
|
|
19
|
+
FORM_DATA_PARSER,
|
|
20
|
+
LOGGER_CONTEXT,
|
|
21
|
+
MEMORY_CACHE_CONTEXT,
|
|
22
|
+
MODULE_LOADER,
|
|
23
|
+
SERVER_CONTEXT,
|
|
24
|
+
} from "../../server/symbols.mjs";
|
|
25
|
+
import { clientAlias } from "../build/resolve.mjs";
|
|
26
|
+
import notFoundHandler from "../handlers/not-found.mjs";
|
|
27
|
+
import staticHandler from "../handlers/static.mjs";
|
|
28
|
+
import trailingSlashHandler from "../handlers/trailing-slash.mjs";
|
|
29
|
+
import reactServer from "../plugins/react-server.mjs";
|
|
30
|
+
import useClient from "../plugins/use-client.mjs";
|
|
31
|
+
import useServer from "../plugins/use-server.mjs";
|
|
32
|
+
import * as sys from "../sys.mjs";
|
|
33
|
+
import merge from "../utils/merge.mjs";
|
|
34
|
+
import createLogger from "./create-logger.mjs";
|
|
35
|
+
import ssrHandler from "./ssr-handler.mjs";
|
|
36
|
+
|
|
37
|
+
const __require = createRequire(import.meta.url);
|
|
38
|
+
const packageName = packageJson.name;
|
|
39
|
+
const cwd = sys.cwd();
|
|
40
|
+
|
|
41
|
+
export default async function createServer(root, options) {
|
|
42
|
+
const config = getRuntime(CONFIG_CONTEXT)?.[CONFIG_ROOT];
|
|
43
|
+
let reactServerRouterModule;
|
|
44
|
+
try {
|
|
45
|
+
reactServerRouterModule = __require.resolve("@lazarv/react-server-router", {
|
|
46
|
+
paths: [cwd],
|
|
47
|
+
});
|
|
48
|
+
} catch (e) {
|
|
49
|
+
// ignore
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const devServerConfig = {
|
|
53
|
+
...config,
|
|
54
|
+
server: {
|
|
55
|
+
...config.server,
|
|
56
|
+
middlewareMode: true,
|
|
57
|
+
cors: options.cors ?? config.server?.cors,
|
|
58
|
+
hmr: {
|
|
59
|
+
port: 21678 + parseInt(options.port ?? config.server?.port ?? 0),
|
|
60
|
+
...config.server?.hmr,
|
|
61
|
+
},
|
|
62
|
+
https: options.https ?? config.server?.https,
|
|
63
|
+
fs: {
|
|
64
|
+
...config.server?.fs,
|
|
65
|
+
allow: [cwd, ...(config.server?.fs?.allow ?? [])],
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
publicDir: false,
|
|
69
|
+
root: __require.resolve(`${packageName}`),
|
|
70
|
+
appType: "ssr",
|
|
71
|
+
clearScreen: options.clearScreen,
|
|
72
|
+
configFile: false,
|
|
73
|
+
plugins: [
|
|
74
|
+
reactServer(),
|
|
75
|
+
...(reactServerRouterModule &&
|
|
76
|
+
(!root || root === "@lazarv/react-server-router")
|
|
77
|
+
? [
|
|
78
|
+
(async () =>
|
|
79
|
+
(
|
|
80
|
+
await import(
|
|
81
|
+
__require.resolve("@lazarv/react-server-router/plugin", {
|
|
82
|
+
paths: [cwd],
|
|
83
|
+
})
|
|
84
|
+
)
|
|
85
|
+
).default())(),
|
|
86
|
+
]
|
|
87
|
+
: []),
|
|
88
|
+
useClient(),
|
|
89
|
+
useServer(),
|
|
90
|
+
react(),
|
|
91
|
+
...(config.plugins ?? []),
|
|
92
|
+
],
|
|
93
|
+
resolve: {
|
|
94
|
+
...config.resolve,
|
|
95
|
+
alias: [...clientAlias(true), ...(config.resolve?.alias ?? [])],
|
|
96
|
+
},
|
|
97
|
+
optimizeDeps: {
|
|
98
|
+
...config.optimizeDeps,
|
|
99
|
+
include: [
|
|
100
|
+
"react",
|
|
101
|
+
"react-dom",
|
|
102
|
+
"react-dom/client",
|
|
103
|
+
"react-server-dom-webpack/client.browser",
|
|
104
|
+
"react-error-boundary",
|
|
105
|
+
...(config.optimizeDeps?.include ?? []).map((m) =>
|
|
106
|
+
__require.resolve(m, { paths: [cwd] })
|
|
107
|
+
),
|
|
108
|
+
],
|
|
109
|
+
exclude: [
|
|
110
|
+
...(config.optimizeDeps?.exclude ?? []).map((m) =>
|
|
111
|
+
__require.resolve(m, { paths: [cwd] })
|
|
112
|
+
),
|
|
113
|
+
],
|
|
114
|
+
force: options.force ?? config.optimizeDeps?.force,
|
|
115
|
+
},
|
|
116
|
+
css: {
|
|
117
|
+
...config.css,
|
|
118
|
+
postcss: cwd,
|
|
119
|
+
},
|
|
120
|
+
customLogger: createLogger(),
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const viteDevServer = await createViteDevServer(
|
|
124
|
+
typeof config.vite === "function"
|
|
125
|
+
? config.vite(devServerConfig) ?? devServerConfig
|
|
126
|
+
: merge(devServerConfig, config.vite)
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
const initialRuntime = {
|
|
130
|
+
[SERVER_CONTEXT]: viteDevServer,
|
|
131
|
+
[LOGGER_CONTEXT]: viteDevServer.config.logger,
|
|
132
|
+
[MODULE_LOADER]: (id) => viteDevServer.ssrLoadModule(id.split("::")[0]),
|
|
133
|
+
[FORM_DATA_PARSER]: parseMultipartFormData,
|
|
134
|
+
[MEMORY_CACHE_CONTEXT]: new MemoryCache(),
|
|
135
|
+
[COLLECT_STYLESHEETS]: function collectCss(rootModule) {
|
|
136
|
+
const styles = [];
|
|
137
|
+
const visited = new Set();
|
|
138
|
+
function collectCss(moduleId) {
|
|
139
|
+
if (
|
|
140
|
+
moduleId &&
|
|
141
|
+
!visited.has(moduleId) &&
|
|
142
|
+
!moduleId.startsWith("virtual:")
|
|
143
|
+
) {
|
|
144
|
+
visited.add(moduleId);
|
|
145
|
+
const mod = viteDevServer.moduleGraph.getModuleById(moduleId);
|
|
146
|
+
const values = Array.from(mod.importedModules.values());
|
|
147
|
+
const importedStyles = values.filter(
|
|
148
|
+
(mod) => /\.(css|scss|less)/.test(mod.id) && !styles.includes(mod)
|
|
149
|
+
);
|
|
150
|
+
const imports = values.filter(
|
|
151
|
+
(mod) => !/\.(css|scss|less)/.test(mod.id)
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
styles.push(...importedStyles.map((mod) => mod.url));
|
|
155
|
+
imports.forEach((mod) => mod.id && collectCss(mod.id));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
collectCss(rootModule);
|
|
159
|
+
return styles;
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
runtime$(
|
|
164
|
+
typeof config.runtime === "function"
|
|
165
|
+
? config.runtime(initialRuntime) ?? initialRuntime
|
|
166
|
+
: {
|
|
167
|
+
...initialRuntime,
|
|
168
|
+
...config.runtime,
|
|
169
|
+
}
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
const publicDir =
|
|
173
|
+
typeof config.publicDir === "string" ? config.publicDir : "public";
|
|
174
|
+
const initialHandlers = [
|
|
175
|
+
...(config.publicDir !== false
|
|
176
|
+
? [
|
|
177
|
+
await staticHandler(join(cwd, publicDir), {
|
|
178
|
+
cwd: publicDir,
|
|
179
|
+
}),
|
|
180
|
+
]
|
|
181
|
+
: []),
|
|
182
|
+
await trailingSlashHandler(),
|
|
183
|
+
cookie(config.cookies),
|
|
184
|
+
...(config.handlers?.pre ?? []),
|
|
185
|
+
await ssrHandler(root),
|
|
186
|
+
...(config.handlers?.post ?? []),
|
|
187
|
+
await notFoundHandler(),
|
|
188
|
+
];
|
|
189
|
+
if (options.cors) {
|
|
190
|
+
initialHandlers.unshift(cors());
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
viteDevServer.middlewares.use(
|
|
194
|
+
createMiddleware(
|
|
195
|
+
compose(
|
|
196
|
+
typeof config.handlers === "function"
|
|
197
|
+
? config.handlers(initialHandlers) ?? initialHandlers
|
|
198
|
+
: [...initialHandlers, ...(config.handlers ?? [])]
|
|
199
|
+
)
|
|
200
|
+
)
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
return {
|
|
204
|
+
listen: (...args) => viteDevServer.middlewares.listen(...args),
|
|
205
|
+
close: () => viteDevServer.close(),
|
|
206
|
+
ws: viteDevServer.ws,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
import packageJson from "../../package.json" assert { type: "json" };
|
|
4
|
+
import { cwd } from "../sys.mjs";
|
|
5
|
+
|
|
6
|
+
const __require = createRequire(import.meta.url);
|
|
7
|
+
|
|
8
|
+
export default function getModules(root) {
|
|
9
|
+
const entryModule = __require.resolve(
|
|
10
|
+
`${packageJson.name}/server/entry.server.jsx`
|
|
11
|
+
);
|
|
12
|
+
const rootModule = __require.resolve(root ?? "@lazarv/react-server-router", {
|
|
13
|
+
paths: [cwd()],
|
|
14
|
+
});
|
|
15
|
+
const memoryCacheModule = __require.resolve(
|
|
16
|
+
`${packageJson.name}/memory-cache`
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
return { entryModule, rootModule, memoryCacheModule };
|
|
20
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
|
|
3
|
+
import { forChild } from "../../config/index.mjs";
|
|
4
|
+
import packageJson from "../../package.json" assert { type: "json" };
|
|
5
|
+
import { context$, ContextStorage, getContext } from "../../server/context.mjs";
|
|
6
|
+
import { init$ as module_loader_init$ } from "../../server/module-loader.mjs";
|
|
7
|
+
import { getRuntime } from "../../server/runtime.mjs";
|
|
8
|
+
import {
|
|
9
|
+
COLLECT_STYLESHEETS,
|
|
10
|
+
CONFIG_CONTEXT,
|
|
11
|
+
ERROR_CONTEXT,
|
|
12
|
+
FORM_DATA_PARSER,
|
|
13
|
+
HTTP_CONTEXT,
|
|
14
|
+
LOGGER_CONTEXT,
|
|
15
|
+
MAIN_MODULE,
|
|
16
|
+
MEMORY_CACHE_CONTEXT,
|
|
17
|
+
MODULE_LOADER,
|
|
18
|
+
REDIRECT_CONTEXT,
|
|
19
|
+
SERVER_CONTEXT,
|
|
20
|
+
STYLES_CONTEXT,
|
|
21
|
+
} from "../../server/symbols.mjs";
|
|
22
|
+
import errorHandler from "../handlers/error.mjs";
|
|
23
|
+
import getModules from "./modules.mjs";
|
|
24
|
+
|
|
25
|
+
const __require = createRequire(import.meta.url);
|
|
26
|
+
|
|
27
|
+
export default async function ssrHandler(root) {
|
|
28
|
+
const { entryModule, rootModule, memoryCacheModule } = getModules(root);
|
|
29
|
+
const viteDevServer = getRuntime(SERVER_CONTEXT);
|
|
30
|
+
const ssrLoadModule = getRuntime(MODULE_LOADER);
|
|
31
|
+
const { default: React } = await import("react");
|
|
32
|
+
const logger = getRuntime(LOGGER_CONTEXT);
|
|
33
|
+
const config = getRuntime(CONFIG_CONTEXT);
|
|
34
|
+
|
|
35
|
+
return async (httpContext) => {
|
|
36
|
+
return new Promise((resolve) => {
|
|
37
|
+
try {
|
|
38
|
+
ContextStorage.run(
|
|
39
|
+
{
|
|
40
|
+
[SERVER_CONTEXT]: viteDevServer,
|
|
41
|
+
[HTTP_CONTEXT]: httpContext,
|
|
42
|
+
[CONFIG_CONTEXT]: config,
|
|
43
|
+
[ERROR_CONTEXT]: errorHandler,
|
|
44
|
+
[MODULE_LOADER]: ssrLoadModule,
|
|
45
|
+
[LOGGER_CONTEXT]: logger,
|
|
46
|
+
[MAIN_MODULE]: [
|
|
47
|
+
"/@vite/client",
|
|
48
|
+
`/${packageJson.name}/client/hmr.mjs`,
|
|
49
|
+
],
|
|
50
|
+
[FORM_DATA_PARSER]: getRuntime(FORM_DATA_PARSER),
|
|
51
|
+
[MEMORY_CACHE_CONTEXT]: getRuntime(MEMORY_CACHE_CONTEXT),
|
|
52
|
+
[REDIRECT_CONTEXT]: {},
|
|
53
|
+
[COLLECT_STYLESHEETS]: getRuntime(COLLECT_STYLESHEETS),
|
|
54
|
+
},
|
|
55
|
+
async () => {
|
|
56
|
+
try {
|
|
57
|
+
// clear up server context registry object
|
|
58
|
+
Reflect.ownKeys(
|
|
59
|
+
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
60
|
+
.ContextRegistry
|
|
61
|
+
).forEach((key) =>
|
|
62
|
+
Reflect.deleteProperty(
|
|
63
|
+
React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED
|
|
64
|
+
.ContextRegistry,
|
|
65
|
+
key
|
|
66
|
+
)
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const cacheModule = forChild(httpContext.url)?.cache?.module;
|
|
70
|
+
|
|
71
|
+
const [
|
|
72
|
+
{ render },
|
|
73
|
+
{ default: Component, init$: root_init$ },
|
|
74
|
+
{ init$: cache_init$ },
|
|
75
|
+
] = await Promise.all([
|
|
76
|
+
ssrLoadModule(entryModule),
|
|
77
|
+
ssrLoadModule(rootModule),
|
|
78
|
+
import(
|
|
79
|
+
cacheModule
|
|
80
|
+
? __require.resolve(cacheModule, {
|
|
81
|
+
paths: [process.cwd()],
|
|
82
|
+
})
|
|
83
|
+
: memoryCacheModule
|
|
84
|
+
),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
await cache_init$?.();
|
|
88
|
+
try {
|
|
89
|
+
const middlewares = await root_init$?.();
|
|
90
|
+
if (middlewares) {
|
|
91
|
+
const response = await middlewares(httpContext);
|
|
92
|
+
if (response) {
|
|
93
|
+
return resolve(response);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
} catch (e) {
|
|
97
|
+
const redirect = getContext(REDIRECT_CONTEXT);
|
|
98
|
+
if (redirect?.response) {
|
|
99
|
+
return resolve(redirect.response);
|
|
100
|
+
} else {
|
|
101
|
+
throw e;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const accept = httpContext.request.headers.get("accept");
|
|
106
|
+
if (
|
|
107
|
+
!accept ||
|
|
108
|
+
!(
|
|
109
|
+
accept.includes("text/html") ||
|
|
110
|
+
accept.includes("text/x-component") ||
|
|
111
|
+
accept.includes("application/json")
|
|
112
|
+
)
|
|
113
|
+
) {
|
|
114
|
+
return resolve();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const styles =
|
|
118
|
+
getRuntime(COLLECT_STYLESHEETS)?.(rootModule) ?? [];
|
|
119
|
+
context$(STYLES_CONTEXT, styles);
|
|
120
|
+
|
|
121
|
+
await module_loader_init$?.(ssrLoadModule);
|
|
122
|
+
return resolve(render(Component));
|
|
123
|
+
} catch (e) {
|
|
124
|
+
logger.error(e);
|
|
125
|
+
return resolve(await getContext(ERROR_CONTEXT)?.(e));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
} catch (e) {
|
|
130
|
+
logger.error(e);
|
|
131
|
+
return resolve(errorHandler(e));
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
};
|
|
135
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import strip from "strip-ansi";
|
|
2
|
+
|
|
3
|
+
import packageJson from "../../package.json" assert { type: "json" };
|
|
4
|
+
import { getContext } from "../../server/context.mjs";
|
|
5
|
+
import {
|
|
6
|
+
HTTP_CONTEXT,
|
|
7
|
+
HTTP_HEADERS,
|
|
8
|
+
HTTP_STATUS,
|
|
9
|
+
SERVER_CONTEXT,
|
|
10
|
+
} from "../../server/symbols.mjs";
|
|
11
|
+
|
|
12
|
+
function cleanStack(stack) {
|
|
13
|
+
return stack
|
|
14
|
+
.split(/\n/g)
|
|
15
|
+
.filter((l) => /^\s*at/.test(l))
|
|
16
|
+
.map((l) => l.trim())
|
|
17
|
+
.join("\n");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function prepareError(err) {
|
|
21
|
+
try {
|
|
22
|
+
if (!err.id) {
|
|
23
|
+
const viteDevServer = getContext(SERVER_CONTEXT);
|
|
24
|
+
viteDevServer.ssrFixStacktrace(err);
|
|
25
|
+
const [id, line, column] =
|
|
26
|
+
err.stack
|
|
27
|
+
.split("\n")[1]
|
|
28
|
+
.match(/\((.*:[0-9]+:[0-9]+)\)/)?.[1]
|
|
29
|
+
.split(":") ?? [];
|
|
30
|
+
|
|
31
|
+
if (viteDevServer.moduleGraph.idToModuleMap.has(id)) {
|
|
32
|
+
const {
|
|
33
|
+
ssrTransformResult: { map },
|
|
34
|
+
} = viteDevServer.moduleGraph.getModuleById(id);
|
|
35
|
+
|
|
36
|
+
err.id = id;
|
|
37
|
+
if (!err.loc) {
|
|
38
|
+
err.loc = {
|
|
39
|
+
file: id,
|
|
40
|
+
column: parseInt(column, 10),
|
|
41
|
+
line: parseInt(line, 10),
|
|
42
|
+
length: 0,
|
|
43
|
+
lineText: "",
|
|
44
|
+
namespace: "",
|
|
45
|
+
suggestion: "",
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!err.frame) {
|
|
50
|
+
const lines = map.sourcesContent[0].split("\n");
|
|
51
|
+
const start = Math.max(0, err.loc.line - 3);
|
|
52
|
+
const end = Math.min(lines.length, err.loc.line + 3);
|
|
53
|
+
const frame = lines
|
|
54
|
+
.slice(start, end)
|
|
55
|
+
.flatMap((l, i) => {
|
|
56
|
+
const curr = i + start;
|
|
57
|
+
const indent = " ".repeat(
|
|
58
|
+
Math.max(start, end).toString().length - curr.toString().length
|
|
59
|
+
);
|
|
60
|
+
return [
|
|
61
|
+
`${indent}${curr} | ${l}`,
|
|
62
|
+
...(i === 2
|
|
63
|
+
? [
|
|
64
|
+
`${indent}${curr
|
|
65
|
+
.toString()
|
|
66
|
+
.replaceAll(/./g, " ")} |${" ".repeat(
|
|
67
|
+
err.loc.column
|
|
68
|
+
)}^`,
|
|
69
|
+
]
|
|
70
|
+
: []),
|
|
71
|
+
];
|
|
72
|
+
})
|
|
73
|
+
.join("\n");
|
|
74
|
+
err.frame = `${err.message}\n${frame}\n`;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
err.plugin = err.plugin || packageJson.name;
|
|
79
|
+
}
|
|
80
|
+
} catch (e) {
|
|
81
|
+
console.error(e);
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
message: strip(err.message),
|
|
85
|
+
stack: strip(cleanStack(err.stack || "")),
|
|
86
|
+
id: err.id,
|
|
87
|
+
frame: strip(err.frame || ""),
|
|
88
|
+
plugin: err.plugin,
|
|
89
|
+
pluginCode: err.pluginCode?.toString(),
|
|
90
|
+
loc: err.loc,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function plainResponse(e) {
|
|
95
|
+
const httpStatus = getContext(HTTP_STATUS) ?? {
|
|
96
|
+
status: 500,
|
|
97
|
+
statusText: "Internal Server Error",
|
|
98
|
+
};
|
|
99
|
+
return new Response(e?.stack ?? null, {
|
|
100
|
+
...httpStatus,
|
|
101
|
+
headers: {
|
|
102
|
+
"Content-Type": "text/plain",
|
|
103
|
+
...(getContext(HTTP_HEADERS) ?? {}),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export default async function errorHandler(err) {
|
|
109
|
+
try {
|
|
110
|
+
const server = getContext(SERVER_CONTEXT);
|
|
111
|
+
// TODO: is there a better way to check if this is a vite dev server?
|
|
112
|
+
if (typeof server?.ssrFixStacktrace !== "function") {
|
|
113
|
+
return plainResponse(err);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const accept = getContext(HTTP_CONTEXT)?.request?.headers?.get?.("accept");
|
|
117
|
+
if (accept?.includes?.(";standalone")) {
|
|
118
|
+
return plainResponse(err);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const httpStatus = getContext(HTTP_STATUS) ?? {
|
|
122
|
+
status: 500,
|
|
123
|
+
statusText: "Internal Server Error",
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return new Response(
|
|
127
|
+
`<!DOCTYPE html>
|
|
128
|
+
<html lang="en">
|
|
129
|
+
<head>
|
|
130
|
+
<meta charset="UTF-8" />
|
|
131
|
+
<title>Error</title>
|
|
132
|
+
<script type="module">
|
|
133
|
+
import { ErrorOverlay } from '/@vite/client'
|
|
134
|
+
document.body.appendChild(new ErrorOverlay(${JSON.stringify(
|
|
135
|
+
await prepareError(err)
|
|
136
|
+
).replace(/</g, "\\u003c")}))
|
|
137
|
+
</script>
|
|
138
|
+
</head>
|
|
139
|
+
<body>
|
|
140
|
+
</body>
|
|
141
|
+
</html>`,
|
|
142
|
+
{
|
|
143
|
+
...httpStatus,
|
|
144
|
+
headers: {
|
|
145
|
+
"Content-Type": "text/html",
|
|
146
|
+
...(getContext(HTTP_HEADERS) ?? {}),
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
} catch (e) {
|
|
151
|
+
return plainResponse(e);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default () => {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default () => {};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { open, readFile } from "node:fs/promises";
|
|
2
|
+
import { join, relative } from "node:path";
|
|
3
|
+
|
|
4
|
+
import glob from "fast-glob";
|
|
5
|
+
import mime from "mime";
|
|
6
|
+
|
|
7
|
+
export default async function staticHandler(dir, options = {}) {
|
|
8
|
+
const files = (
|
|
9
|
+
await glob(`${dir}/**/*`, {
|
|
10
|
+
cwd: options.cwd,
|
|
11
|
+
stats: true,
|
|
12
|
+
absolute: true,
|
|
13
|
+
})
|
|
14
|
+
).reduce((files, file) => {
|
|
15
|
+
files.set(
|
|
16
|
+
`/${relative(join(process.cwd(), options.cwd ?? "."), file.path)}`,
|
|
17
|
+
{
|
|
18
|
+
...file,
|
|
19
|
+
etag: `W/"${file.stats.size}-${file.stats.mtime.getTime()}"`,
|
|
20
|
+
mime:
|
|
21
|
+
mime.getType(file.path.replace(/\.(br|gz)$/, "")) ||
|
|
22
|
+
"application/octet-stream",
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
return files;
|
|
26
|
+
}, new Map());
|
|
27
|
+
const fileCache = new Map();
|
|
28
|
+
|
|
29
|
+
return async (context) => {
|
|
30
|
+
let { pathname } = context.url;
|
|
31
|
+
|
|
32
|
+
if (pathname.startsWith("/@source")) {
|
|
33
|
+
return new Response(await readFile(pathname.slice(8), "utf8"), {
|
|
34
|
+
headers: {
|
|
35
|
+
"content-type": "text/plain",
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const accept = context.request.headers.get("accept");
|
|
41
|
+
const isHTML = accept?.includes("text/html");
|
|
42
|
+
const isRSC = accept?.includes("text/x-component");
|
|
43
|
+
let contentEncoding = undefined;
|
|
44
|
+
|
|
45
|
+
if (isHTML) {
|
|
46
|
+
const acceptEncoding = context.request.headers.get("accept-encoding");
|
|
47
|
+
const isBrotli = acceptEncoding?.includes("br");
|
|
48
|
+
const isGzip = acceptEncoding?.includes("gzip");
|
|
49
|
+
|
|
50
|
+
if (isBrotli && files.has(`${pathname}/index.html.br`)) {
|
|
51
|
+
pathname = `${pathname}/index.html.br`;
|
|
52
|
+
contentEncoding = "br";
|
|
53
|
+
} else if (isGzip && files.has(`${pathname}/index.html.gz`)) {
|
|
54
|
+
pathname = `${pathname}/index.html.gz`;
|
|
55
|
+
contentEncoding = "gzip";
|
|
56
|
+
} else if (files.has(`${pathname}/index.html`)) {
|
|
57
|
+
pathname = `${pathname}/index.html`;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (pathname !== "/" && files.has(pathname)) {
|
|
62
|
+
try {
|
|
63
|
+
const file = files.get(pathname);
|
|
64
|
+
if (
|
|
65
|
+
context.request.headers.get("if-none-match") === file.etag &&
|
|
66
|
+
!isRSC
|
|
67
|
+
) {
|
|
68
|
+
return new Response(null, {
|
|
69
|
+
status: 304,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
let res = null;
|
|
73
|
+
if (!fileCache.has(pathname)) {
|
|
74
|
+
const fd = await open(file.path, "r");
|
|
75
|
+
try {
|
|
76
|
+
const fs = fd.createReadStream();
|
|
77
|
+
res = new ReadableStream({
|
|
78
|
+
type: "bytes",
|
|
79
|
+
async start(controller) {
|
|
80
|
+
const payload = [];
|
|
81
|
+
for await (const chunk of fs) {
|
|
82
|
+
payload.push(Buffer.copyBytesFrom(chunk));
|
|
83
|
+
controller.enqueue(chunk);
|
|
84
|
+
}
|
|
85
|
+
fileCache.set(pathname, Buffer.concat(payload));
|
|
86
|
+
controller.close();
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
} catch (e) {
|
|
90
|
+
fd.close();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
} else {
|
|
94
|
+
res = fileCache.get(pathname);
|
|
95
|
+
}
|
|
96
|
+
if (res) {
|
|
97
|
+
return new Response(res, {
|
|
98
|
+
headers: {
|
|
99
|
+
"content-type": file.mime,
|
|
100
|
+
"content-length": file.stats.size,
|
|
101
|
+
etag: file.etag,
|
|
102
|
+
"cache-control":
|
|
103
|
+
context.request.headers.get("cache-control") === "no-cache"
|
|
104
|
+
? "no-cache"
|
|
105
|
+
: isHTML
|
|
106
|
+
? "must-revalidate"
|
|
107
|
+
: "public,max-age=600",
|
|
108
|
+
"last-modified": file.stats.mtime.toUTCString(),
|
|
109
|
+
"content-encoding": contentEncoding,
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error.code !== "ENOENT") {
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export default async function trailingSlash() {
|
|
2
|
+
return async ({ url: { pathname } }) => {
|
|
3
|
+
if (pathname !== "/" && pathname.endsWith("/")) {
|
|
4
|
+
return new Response(null, {
|
|
5
|
+
status: 301,
|
|
6
|
+
headers: {
|
|
7
|
+
Location: pathname.replace(/\/+$/g, "") || "/",
|
|
8
|
+
},
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
}
|