@modern-js/plugin-data-loader 2.69.5 → 3.0.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.
- package/dist/cjs/cli/createRequest.js +122 -141
- package/dist/cjs/cli/data.js +129 -148
- package/dist/cjs/cli/generateClient.js +52 -52
- package/dist/cjs/cli/loader.js +63 -62
- package/dist/cjs/common/constants.js +41 -31
- package/dist/cjs/runtime/errors.js +84 -89
- package/dist/cjs/runtime/index.js +143 -155
- package/dist/cjs/runtime/response.js +66 -77
- package/dist/esm/cli/createRequest.mjs +93 -0
- package/dist/esm/cli/data.mjs +111 -0
- package/dist/esm/cli/generateClient.mjs +22 -0
- package/dist/esm/cli/loader.mjs +34 -0
- package/dist/esm/common/constants.mjs +4 -0
- package/dist/esm/runtime/errors.mjs +52 -0
- package/dist/esm/runtime/index.mjs +114 -0
- package/dist/esm/runtime/response.mjs +42 -0
- package/dist/esm-node/cli/createRequest.mjs +93 -0
- package/dist/esm-node/cli/data.mjs +111 -0
- package/dist/esm-node/cli/generateClient.mjs +22 -0
- package/dist/esm-node/cli/loader.mjs +34 -0
- package/dist/esm-node/common/constants.mjs +4 -0
- package/dist/esm-node/runtime/errors.mjs +52 -0
- package/dist/esm-node/runtime/index.mjs +114 -0
- package/dist/esm-node/runtime/response.mjs +42 -0
- package/dist/types/cli/createRequest.d.ts +1 -2
- package/dist/types/cli/loader.d.ts +2 -2
- package/dist/types/runtime/errors.d.ts +1 -1
- package/dist/types/runtime/response.d.ts +1 -1
- package/package.json +22 -26
- package/rslib.config.mts +4 -0
- package/rstest.config.ts +18 -0
- package/dist/esm/cli/createRequest.js +0 -297
- package/dist/esm/cli/data.js +0 -491
- package/dist/esm/cli/generateClient.js +0 -21
- package/dist/esm/cli/loader.js +0 -93
- package/dist/esm/common/constants.js +0 -8
- package/dist/esm/runtime/errors.js +0 -90
- package/dist/esm/runtime/index.js +0 -191
- package/dist/esm/runtime/response.js +0 -107
- package/dist/esm-node/cli/createRequest.js +0 -126
- package/dist/esm-node/cli/data.js +0 -140
- package/dist/esm-node/cli/generateClient.js +0 -32
- package/dist/esm-node/cli/loader.js +0 -47
- package/dist/esm-node/common/constants.js +0 -8
- package/dist/esm-node/runtime/errors.js +0 -75
- package/dist/esm-node/runtime/index.js +0 -142
- package/dist/esm-node/runtime/response.js +0 -63
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { promisify } from "util";
|
|
2
|
-
import { logger } from "@modern-js/utils/logger";
|
|
3
|
-
import { generateClient } from "./generateClient";
|
|
4
|
-
async function loader(source) {
|
|
5
|
-
var _this__compiler;
|
|
6
|
-
this.cacheable();
|
|
7
|
-
const target = (_this__compiler = this._compiler) === null || _this__compiler === void 0 ? void 0 : _this__compiler.options.target;
|
|
8
|
-
const shouldSkip = (compileTarget) => {
|
|
9
|
-
return target === compileTarget || Array.isArray(target) && target.includes(compileTarget);
|
|
10
|
-
};
|
|
11
|
-
if (shouldSkip("node") || shouldSkip("webworker") || shouldSkip("async-node")) {
|
|
12
|
-
return source;
|
|
13
|
-
}
|
|
14
|
-
const { resourceQuery } = this;
|
|
15
|
-
const options = resourceQuery.slice(1).split("&").reduce((pre, cur) => {
|
|
16
|
-
const [key, value] = cur.split("=");
|
|
17
|
-
if (key && value) {
|
|
18
|
-
pre[key] = value === "true" ? true : value === "false" ? false : value;
|
|
19
|
-
}
|
|
20
|
-
return pre;
|
|
21
|
-
}, {});
|
|
22
|
-
if (!options.loaderId || options.retain) {
|
|
23
|
-
return source;
|
|
24
|
-
}
|
|
25
|
-
if (options.clientData) {
|
|
26
|
-
const readFile = promisify(this.fs.readFile);
|
|
27
|
-
try {
|
|
28
|
-
const clientDataPath = this.resourcePath.includes(".loader.") ? this.resourcePath.replace(".loader.", ".data.client.") : this.resourcePath.replace(".data.", ".data.client.");
|
|
29
|
-
this.addDependency(clientDataPath);
|
|
30
|
-
const clientDataContent = await readFile(clientDataPath);
|
|
31
|
-
return clientDataContent;
|
|
32
|
-
} catch (error) {
|
|
33
|
-
if (process.env.NODE_ENV === "development") {
|
|
34
|
-
logger.error(`Failed to read the clientData file ${options.clientData}`);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
const code = generateClient({
|
|
39
|
-
inline: options.inline,
|
|
40
|
-
action: options.action,
|
|
41
|
-
routeId: options.routeId
|
|
42
|
-
});
|
|
43
|
-
return code;
|
|
44
|
-
}
|
|
45
|
-
export {
|
|
46
|
-
loader as default
|
|
47
|
-
};
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { isRouteErrorResponse } from "@modern-js/runtime-utils/remix-router";
|
|
2
|
-
function sanitizeError(error) {
|
|
3
|
-
if (error instanceof Error && process.env.NODE_ENV !== "development" && process.env.NODE_ENV !== "test") {
|
|
4
|
-
const sanitized = new Error(error.message || "Unexpected Server Error");
|
|
5
|
-
sanitized.stack = void 0;
|
|
6
|
-
return sanitized;
|
|
7
|
-
}
|
|
8
|
-
return error;
|
|
9
|
-
}
|
|
10
|
-
function sanitizeErrors(errors) {
|
|
11
|
-
return Object.entries(errors).reduce((acc, [routeId, error]) => {
|
|
12
|
-
return Object.assign(acc, {
|
|
13
|
-
[routeId]: sanitizeError(error)
|
|
14
|
-
});
|
|
15
|
-
}, {});
|
|
16
|
-
}
|
|
17
|
-
function serializeError(error) {
|
|
18
|
-
const sanitized = sanitizeError(error);
|
|
19
|
-
return {
|
|
20
|
-
message: sanitized.message,
|
|
21
|
-
stack: sanitized.stack
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function serializeErrors(errors) {
|
|
25
|
-
if (!errors) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
const entries = Object.entries(errors);
|
|
29
|
-
const serialized = {};
|
|
30
|
-
for (const [key, val] of entries) {
|
|
31
|
-
if (isRouteErrorResponse(val)) {
|
|
32
|
-
serialized[key] = {
|
|
33
|
-
...val,
|
|
34
|
-
__type: "RouteErrorResponse"
|
|
35
|
-
};
|
|
36
|
-
} else if (val instanceof Error) {
|
|
37
|
-
const sanitized = sanitizeError(val);
|
|
38
|
-
serialized[key] = {
|
|
39
|
-
message: sanitized.message,
|
|
40
|
-
stack: sanitized.stack,
|
|
41
|
-
__type: "Error",
|
|
42
|
-
// If this is a subclass (i.e., ReferenceError), send up the type so we
|
|
43
|
-
// can re-create the same type during hydration. This will only apply
|
|
44
|
-
// in dev mode since all production errors are sanitized to normal
|
|
45
|
-
// Error instances
|
|
46
|
-
...sanitized.name !== "Error" ? {
|
|
47
|
-
__subType: sanitized.name
|
|
48
|
-
} : {}
|
|
49
|
-
};
|
|
50
|
-
} else {
|
|
51
|
-
serialized[key] = val;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
return serialized;
|
|
55
|
-
}
|
|
56
|
-
function errorResponseToJson(errorResponse) {
|
|
57
|
-
return Response.json(
|
|
58
|
-
// @ts-expect-error This is "private" from users but intended for internal use
|
|
59
|
-
serializeError(errorResponse.error || new Error("Unexpected Server Error")),
|
|
60
|
-
{
|
|
61
|
-
status: errorResponse.status,
|
|
62
|
-
statusText: errorResponse.statusText,
|
|
63
|
-
headers: {
|
|
64
|
-
"X-Modernjs-Error": "yes"
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
export {
|
|
70
|
-
errorResponseToJson,
|
|
71
|
-
sanitizeError,
|
|
72
|
-
sanitizeErrors,
|
|
73
|
-
serializeError,
|
|
74
|
-
serializeErrors
|
|
75
|
-
};
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import { transformNestedRoutes } from "@modern-js/runtime-utils/browser";
|
|
2
|
-
import { createRequestContext, reporterCtx } from "@modern-js/runtime-utils/node";
|
|
3
|
-
import { storage } from "@modern-js/runtime-utils/node";
|
|
4
|
-
import { DEFERRED_SYMBOL, createStaticHandler, isRouteErrorResponse } from "@modern-js/runtime-utils/remix-router";
|
|
5
|
-
import { matchEntry } from "@modern-js/runtime-utils/server";
|
|
6
|
-
import { time } from "@modern-js/runtime-utils/time";
|
|
7
|
-
import { parseHeaders } from "@modern-js/runtime-utils/universal/request";
|
|
8
|
-
import { isPlainObject } from "@modern-js/utils/lodash";
|
|
9
|
-
import { LOADER_REPORTER_NAME } from "@modern-js/utils/universal/constants";
|
|
10
|
-
import { CONTENT_TYPE_DEFERRED, LOADER_ID_PARAM } from "../common/constants";
|
|
11
|
-
import { errorResponseToJson, serializeError } from "./errors";
|
|
12
|
-
import { createDeferredReadableStream } from "./response";
|
|
13
|
-
const redirectStatusCodes = /* @__PURE__ */ new Set([
|
|
14
|
-
301,
|
|
15
|
-
302,
|
|
16
|
-
303,
|
|
17
|
-
307,
|
|
18
|
-
308
|
|
19
|
-
]);
|
|
20
|
-
function isRedirectResponse(status) {
|
|
21
|
-
return redirectStatusCodes.has(status);
|
|
22
|
-
}
|
|
23
|
-
function isResponse(value) {
|
|
24
|
-
return value != null && typeof value.status === "number" && typeof value.statusText === "string" && typeof value.headers === "object" && typeof value.body !== "undefined";
|
|
25
|
-
}
|
|
26
|
-
function convertModernRedirectResponse(headers, basename) {
|
|
27
|
-
const newHeaders = new Headers(headers);
|
|
28
|
-
let redirectUrl = headers.get("Location");
|
|
29
|
-
if (basename !== "/") {
|
|
30
|
-
redirectUrl = redirectUrl.replace(basename, "");
|
|
31
|
-
}
|
|
32
|
-
newHeaders.set("X-Modernjs-Redirect", redirectUrl);
|
|
33
|
-
newHeaders.delete("Location");
|
|
34
|
-
return new Response(null, {
|
|
35
|
-
status: 204,
|
|
36
|
-
headers: newHeaders
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
function hasFileExtension(pathname) {
|
|
40
|
-
const lastSegment = pathname.split("/").pop() || "";
|
|
41
|
-
const dotIndex = lastSegment.lastIndexOf(".");
|
|
42
|
-
if (dotIndex === -1) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
const extension = lastSegment.substring(dotIndex).toLowerCase();
|
|
46
|
-
return extension !== ".html";
|
|
47
|
-
}
|
|
48
|
-
const handleRequest = async ({ request, serverRoutes, routes: routesConfig, context, onTiming }) => {
|
|
49
|
-
const url = new URL(request.url);
|
|
50
|
-
const routeId = url.searchParams.get(LOADER_ID_PARAM);
|
|
51
|
-
if (hasFileExtension(url.pathname)) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const entry = matchEntry(url.pathname, serverRoutes);
|
|
55
|
-
if (!routeId || !entry) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
const basename = entry.urlPath;
|
|
59
|
-
const end = time();
|
|
60
|
-
const { reporter, loaderContext, monitors } = context;
|
|
61
|
-
const headersData = parseHeaders(request);
|
|
62
|
-
const activeDeferreds = /* @__PURE__ */ new Map();
|
|
63
|
-
return storage.run({
|
|
64
|
-
headers: headersData,
|
|
65
|
-
monitors,
|
|
66
|
-
request,
|
|
67
|
-
activeDeferreds
|
|
68
|
-
}, async () => {
|
|
69
|
-
const routes = transformNestedRoutes(routesConfig);
|
|
70
|
-
const { queryRoute } = createStaticHandler(routes, {
|
|
71
|
-
basename
|
|
72
|
-
});
|
|
73
|
-
const requestContext = createRequestContext(loaderContext);
|
|
74
|
-
requestContext.set(reporterCtx, reporter);
|
|
75
|
-
let response;
|
|
76
|
-
try {
|
|
77
|
-
response = await queryRoute(request, {
|
|
78
|
-
routeId,
|
|
79
|
-
requestContext
|
|
80
|
-
});
|
|
81
|
-
if (isResponse(response) && isRedirectResponse(response.status)) {
|
|
82
|
-
response = convertModernRedirectResponse(response.headers, basename);
|
|
83
|
-
} else if (isPlainObject(response) && (DEFERRED_SYMBOL in response || activeDeferreds.get(routeId))) {
|
|
84
|
-
let deferredData;
|
|
85
|
-
if (DEFERRED_SYMBOL in response) {
|
|
86
|
-
deferredData = response[DEFERRED_SYMBOL];
|
|
87
|
-
} else {
|
|
88
|
-
deferredData = activeDeferreds.get(routeId);
|
|
89
|
-
}
|
|
90
|
-
const body = createDeferredReadableStream(
|
|
91
|
-
// @ts-ignore
|
|
92
|
-
deferredData,
|
|
93
|
-
request.signal
|
|
94
|
-
);
|
|
95
|
-
const init = deferredData.init || {};
|
|
96
|
-
if (init.status && isRedirectResponse(init.status)) {
|
|
97
|
-
if (!init.headers) {
|
|
98
|
-
throw new Error("redirect response includes no headers");
|
|
99
|
-
}
|
|
100
|
-
response = convertModernRedirectResponse(new Headers(init.headers), basename);
|
|
101
|
-
} else {
|
|
102
|
-
const headers = new Headers(init.headers);
|
|
103
|
-
headers.set("Content-Type", `${CONTENT_TYPE_DEFERRED}; charset=UTF-8`);
|
|
104
|
-
init.headers = headers;
|
|
105
|
-
response = new Response(body, init);
|
|
106
|
-
}
|
|
107
|
-
} else {
|
|
108
|
-
response = isResponse(response) ? response : new Response(JSON.stringify(response), {
|
|
109
|
-
headers: {
|
|
110
|
-
"Content-Type": "application/json; charset=utf-8"
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
const cost = end();
|
|
115
|
-
response.headers.set("X-Modernjs-Response", "yes");
|
|
116
|
-
onTiming === null || onTiming === void 0 ? void 0 : onTiming(`${LOADER_REPORTER_NAME}-navigation`, cost);
|
|
117
|
-
} catch (error) {
|
|
118
|
-
if (isResponse(error)) {
|
|
119
|
-
error.headers.set("X-Modernjs-Catch", "yes");
|
|
120
|
-
response = error;
|
|
121
|
-
} else if (isRouteErrorResponse(error)) {
|
|
122
|
-
response = errorResponseToJson(error);
|
|
123
|
-
} else {
|
|
124
|
-
const errorInstance = error instanceof Error || error instanceof DOMException ? error : new Error("Unexpected Server Error");
|
|
125
|
-
response = new Response(JSON.stringify(serializeError(errorInstance)), {
|
|
126
|
-
status: 500,
|
|
127
|
-
headers: {
|
|
128
|
-
"X-Modernjs-Error": "yes",
|
|
129
|
-
"Content-Type": "application/json"
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return response;
|
|
135
|
-
});
|
|
136
|
-
};
|
|
137
|
-
export {
|
|
138
|
-
handleRequest,
|
|
139
|
-
hasFileExtension,
|
|
140
|
-
isRedirectResponse,
|
|
141
|
-
isResponse
|
|
142
|
-
};
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { TextEncoder } from "util";
|
|
2
|
-
import { serializeJson } from "@modern-js/runtime-utils/node";
|
|
3
|
-
function isTrackedPromise(value) {
|
|
4
|
-
return value != null && typeof value.then === "function" && value._tracked === true;
|
|
5
|
-
}
|
|
6
|
-
const DEFERRED_VALUE_PLACEHOLDER_PREFIX = "__deferred_promise:";
|
|
7
|
-
function createDeferredReadableStream(deferredData, signal) {
|
|
8
|
-
const encoder = new TextEncoder();
|
|
9
|
-
const stream = new ReadableStream({
|
|
10
|
-
async start(controller) {
|
|
11
|
-
const criticalData = {};
|
|
12
|
-
const preresolvedKeys = [];
|
|
13
|
-
for (const [key, value] of Object.entries(deferredData.data)) {
|
|
14
|
-
if (isTrackedPromise(value)) {
|
|
15
|
-
criticalData[key] = `${DEFERRED_VALUE_PLACEHOLDER_PREFIX}${key}`;
|
|
16
|
-
if (typeof value._data !== "undefined" || typeof value._error !== "undefined") {
|
|
17
|
-
preresolvedKeys.push(key);
|
|
18
|
-
}
|
|
19
|
-
} else {
|
|
20
|
-
criticalData[key] = value;
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
controller.enqueue(encoder.encode(`${JSON.stringify(criticalData)}
|
|
24
|
-
|
|
25
|
-
`));
|
|
26
|
-
for (const preresolvedKey of preresolvedKeys) {
|
|
27
|
-
enqueueTrackedPromise(controller, encoder, preresolvedKey, deferredData.data[preresolvedKey]);
|
|
28
|
-
}
|
|
29
|
-
const unsubscribe = deferredData.subscribe((aborted, settledKey) => {
|
|
30
|
-
if (settledKey) {
|
|
31
|
-
enqueueTrackedPromise(controller, encoder, settledKey, deferredData.data[settledKey]);
|
|
32
|
-
}
|
|
33
|
-
});
|
|
34
|
-
await deferredData.resolveData(signal);
|
|
35
|
-
unsubscribe();
|
|
36
|
-
controller.close();
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
return stream;
|
|
40
|
-
}
|
|
41
|
-
function enqueueTrackedPromise(controller, encoder, settledKey, promise) {
|
|
42
|
-
if ("_error" in promise) {
|
|
43
|
-
const { _error } = promise;
|
|
44
|
-
controller.enqueue(encoder.encode(`error:${serializeJson({
|
|
45
|
-
[settledKey]: {
|
|
46
|
-
message: _error.message,
|
|
47
|
-
stack: _error.stack
|
|
48
|
-
}
|
|
49
|
-
})}
|
|
50
|
-
|
|
51
|
-
`));
|
|
52
|
-
} else {
|
|
53
|
-
var _promise__data;
|
|
54
|
-
controller.enqueue(encoder.encode(`data:${JSON.stringify({
|
|
55
|
-
[settledKey]: (_promise__data = promise._data) !== null && _promise__data !== void 0 ? _promise__data : null
|
|
56
|
-
})}
|
|
57
|
-
|
|
58
|
-
`));
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
export {
|
|
62
|
-
createDeferredReadableStream
|
|
63
|
-
};
|