@modern-js/plugin-data-loader 0.0.0-next-20221104140607
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/CHANGELOG.md +19 -0
- package/LICENSE +21 -0
- package/README.md +30 -0
- package/dist/js/modern/cli/create-request.js +44 -0
- package/dist/js/modern/cli/generate-client.js +23 -0
- package/dist/js/modern/cli/loader.js +21 -0
- package/dist/js/modern/server/index.js +217 -0
- package/dist/js/node/cli/create-request.js +57 -0
- package/dist/js/node/cli/generate-client.js +39 -0
- package/dist/js/node/cli/loader.js +29 -0
- package/dist/js/node/server/index.js +241 -0
- package/dist/js/treeshaking/cli/create-request.js +67 -0
- package/dist/js/treeshaking/cli/generate-client.js +13 -0
- package/dist/js/treeshaking/cli/loader.js +46 -0
- package/dist/js/treeshaking/server/index.js +365 -0
- package/dist/types/cli/create-request.d.ts +16 -0
- package/dist/types/cli/generate-client.d.ts +7 -0
- package/dist/types/cli/loader.d.ts +4 -0
- package/dist/types/server/index.d.ts +20 -0
- package/package.json +103 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.handleRequest = exports.getPathWithoutEntry = exports.default = void 0;
|
|
7
|
+
exports.isRedirectResponse = isRedirectResponse;
|
|
8
|
+
exports.isResponse = isResponse;
|
|
9
|
+
|
|
10
|
+
var _node = require("@remix-run/node");
|
|
11
|
+
|
|
12
|
+
var _reactRouterDom = require("react-router-dom");
|
|
13
|
+
|
|
14
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
15
|
+
|
|
16
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
17
|
+
|
|
18
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
|
|
19
|
+
|
|
20
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
|
|
21
|
+
|
|
22
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
23
|
+
|
|
24
|
+
// Polyfill Web Fetch API
|
|
25
|
+
(0, _node.installGlobals)();
|
|
26
|
+
const LOADER_SEARCH_PARAM = '_loader';
|
|
27
|
+
const redirectStatusCodes = new Set([301, 302, 303, 307, 308]);
|
|
28
|
+
|
|
29
|
+
function isRedirectResponse(response) {
|
|
30
|
+
return redirectStatusCodes.has(response.status);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isResponse(value) {
|
|
34
|
+
return value != null && typeof value.status === 'number' && typeof value.statusText === 'string' && typeof value.headers === 'object' && typeof value.body !== 'undefined';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const json = (data, init = {}) => {
|
|
38
|
+
const responseInit = typeof init === 'number' ? {
|
|
39
|
+
status: init
|
|
40
|
+
} : init;
|
|
41
|
+
const headers = new Headers(responseInit.headers);
|
|
42
|
+
|
|
43
|
+
if (!headers.has('Content-Type')) {
|
|
44
|
+
headers.set('Content-Type', 'application/json; charset=utf-8');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return new _node.Response(JSON.stringify(data), _objectSpread(_objectSpread({}, responseInit), {}, {
|
|
48
|
+
headers
|
|
49
|
+
}));
|
|
50
|
+
}; // TODO: 添加 context
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
const callRouteLoader = async ({
|
|
54
|
+
routeId,
|
|
55
|
+
loader,
|
|
56
|
+
params,
|
|
57
|
+
request,
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
59
|
+
loadContext
|
|
60
|
+
}) => {
|
|
61
|
+
if (!loader) {
|
|
62
|
+
throw new Error(`You made a ${request.method} request to ${request.url} but did not provide ` + `a default component or \`loader\` for route "${routeId}", ` + `so there is no way to handle the request.`);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
let result;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
result = await loader({
|
|
69
|
+
request,
|
|
70
|
+
params
|
|
71
|
+
});
|
|
72
|
+
} catch (error) {
|
|
73
|
+
if (!isResponse(error)) {
|
|
74
|
+
throw error;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
result = error;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (result === undefined) {
|
|
81
|
+
throw new Error(`You defined a loader for route "${routeId}" but didn't return ` + `anything from your \`loader\` function. Please return a value or \`null\`.`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return isResponse(result) ? result : json(result);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const createLoaderHeaders = requestHeaders => {
|
|
88
|
+
const headers = new Headers();
|
|
89
|
+
|
|
90
|
+
for (const [key, values] of Object.entries(requestHeaders)) {
|
|
91
|
+
if (values) {
|
|
92
|
+
if (Array.isArray(values)) {
|
|
93
|
+
for (const value of values) {
|
|
94
|
+
headers.append(key, value);
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
headers.set(key, values);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return headers;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const createLoaderRequest = context => {
|
|
106
|
+
const origin = `${context.protocol}://${context.host}`; // eslint-disable-next-line node/no-unsupported-features/node-builtins, node/prefer-global/url
|
|
107
|
+
|
|
108
|
+
const url = new URL(context.url, origin);
|
|
109
|
+
const controller = new AbortController();
|
|
110
|
+
const init = {
|
|
111
|
+
method: context.method,
|
|
112
|
+
headers: createLoaderHeaders(context.headers),
|
|
113
|
+
signal: controller.signal
|
|
114
|
+
};
|
|
115
|
+
return new Request(url.href, init);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const sendLoaderResponse = async (res, nodeResponse) => {
|
|
119
|
+
res.statusMessage = nodeResponse.statusText;
|
|
120
|
+
res.statusCode = nodeResponse.status;
|
|
121
|
+
|
|
122
|
+
for (const [key, value] of nodeResponse.headers.entries()) {
|
|
123
|
+
res.setHeader(key, value);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (nodeResponse.body) {
|
|
127
|
+
await (0, _node.writeReadableStreamToWritable)(nodeResponse.body, res);
|
|
128
|
+
} else {
|
|
129
|
+
res.end();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const getPathWithoutEntry = (pathname, entryPath) => {
|
|
134
|
+
if (entryPath === '/') {
|
|
135
|
+
return pathname;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return pathname.replace(entryPath, '');
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
exports.getPathWithoutEntry = getPathWithoutEntry;
|
|
142
|
+
|
|
143
|
+
const matchEntry = (pathname, entries) => {
|
|
144
|
+
return entries.find(entry => pathname.startsWith(entry.urlPath));
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
const handleRequest = async ({
|
|
148
|
+
context,
|
|
149
|
+
serverRoutes,
|
|
150
|
+
distDir
|
|
151
|
+
}) => {
|
|
152
|
+
const {
|
|
153
|
+
method,
|
|
154
|
+
query
|
|
155
|
+
} = context;
|
|
156
|
+
const routeId = query[LOADER_SEARCH_PARAM];
|
|
157
|
+
|
|
158
|
+
if (!routeId || method.toLowerCase() !== 'get') {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const entry = matchEntry(context.path, serverRoutes);
|
|
163
|
+
|
|
164
|
+
if (!entry) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const {
|
|
169
|
+
routes
|
|
170
|
+
} = await Promise.resolve(`${distDir}/loader-routes/${entry.entryName}`).then(s => _interopRequireWildcard(require(s)));
|
|
171
|
+
|
|
172
|
+
if (!routes) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const {
|
|
177
|
+
res
|
|
178
|
+
} = context;
|
|
179
|
+
const pathname = getPathWithoutEntry(context.path, entry.urlPath);
|
|
180
|
+
const matches = (0, _reactRouterDom.matchRoutes)(routes, pathname);
|
|
181
|
+
|
|
182
|
+
if (!matches) {
|
|
183
|
+
res.statusCode = 403;
|
|
184
|
+
res.end(`Route ${pathname} was not matched`);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const match = matches === null || matches === void 0 ? void 0 : matches.find(match => match.route.id === routeId);
|
|
189
|
+
|
|
190
|
+
if (!match) {
|
|
191
|
+
res.statusCode = 403;
|
|
192
|
+
res.end(`Route ${routeId} does not match URL ${context.path}`);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const request = createLoaderRequest(context);
|
|
197
|
+
let response;
|
|
198
|
+
|
|
199
|
+
try {
|
|
200
|
+
response = await callRouteLoader({
|
|
201
|
+
loader: match.route.loader,
|
|
202
|
+
routeId: match.route.id,
|
|
203
|
+
params: match.params,
|
|
204
|
+
request,
|
|
205
|
+
loadContext: {}
|
|
206
|
+
}); // TODO: 处理 redirect
|
|
207
|
+
} catch (error) {
|
|
208
|
+
const message = String(error);
|
|
209
|
+
response = new _node.Response(message, {
|
|
210
|
+
status: 500,
|
|
211
|
+
headers: {
|
|
212
|
+
'Content-Type': 'text/plain'
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
sendLoaderResponse(res, response);
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
exports.handleRequest = handleRequest;
|
|
221
|
+
|
|
222
|
+
var _default = () => ({
|
|
223
|
+
name: '@modern-js/plugin-data-loader',
|
|
224
|
+
setup: () => ({
|
|
225
|
+
preparebeforeRouteHandler({
|
|
226
|
+
serverRoutes,
|
|
227
|
+
distDir
|
|
228
|
+
}) {
|
|
229
|
+
return async context => {
|
|
230
|
+
return handleRequest({
|
|
231
|
+
serverRoutes,
|
|
232
|
+
distDir,
|
|
233
|
+
context
|
|
234
|
+
});
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
})
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
exports.default = _default;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
|
|
2
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
3
|
+
// eslint-disable-next-line eslint-comments/disable-enable-pair
|
|
4
|
+
|
|
5
|
+
/* eslint-disable node/prefer-global/url */
|
|
6
|
+
// eslint-disable-next-line eslint-comments/disable-enable-pair
|
|
7
|
+
|
|
8
|
+
/* eslint-disable node/no-unsupported-features/node-builtins */
|
|
9
|
+
import { compile } from 'path-to-regexp';
|
|
10
|
+
export var getRequestUrl = function getRequestUrl(_ref) {
|
|
11
|
+
var params = _ref.params,
|
|
12
|
+
request = _ref.request,
|
|
13
|
+
routeId = _ref.routeId;
|
|
14
|
+
var url = new URL(request.url);
|
|
15
|
+
var toPath = compile(url.pathname, {
|
|
16
|
+
encode: encodeURIComponent
|
|
17
|
+
});
|
|
18
|
+
var newPathName = toPath(params);
|
|
19
|
+
url.pathname = newPathName;
|
|
20
|
+
url.searchParams.append('_loader', routeId);
|
|
21
|
+
return url;
|
|
22
|
+
};
|
|
23
|
+
export var createRequest = function createRequest(routeId) {
|
|
24
|
+
var method = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'get';
|
|
25
|
+
return /*#__PURE__*/function () {
|
|
26
|
+
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(_ref2) {
|
|
27
|
+
var params, request, url, res;
|
|
28
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
29
|
+
while (1) {
|
|
30
|
+
switch (_context.prev = _context.next) {
|
|
31
|
+
case 0:
|
|
32
|
+
params = _ref2.params, request = _ref2.request;
|
|
33
|
+
url = getRequestUrl({
|
|
34
|
+
params: params,
|
|
35
|
+
request: request,
|
|
36
|
+
routeId: routeId
|
|
37
|
+
});
|
|
38
|
+
_context.prev = 2;
|
|
39
|
+
_context.next = 5;
|
|
40
|
+
return fetch(url, {
|
|
41
|
+
method: method,
|
|
42
|
+
signal: request.signal
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
case 5:
|
|
46
|
+
res = _context.sent;
|
|
47
|
+
return _context.abrupt("return", res);
|
|
48
|
+
|
|
49
|
+
case 9:
|
|
50
|
+
_context.prev = 9;
|
|
51
|
+
_context.t0 = _context["catch"](2);
|
|
52
|
+
console.error(_context.t0);
|
|
53
|
+
throw _context.t0;
|
|
54
|
+
|
|
55
|
+
case 13:
|
|
56
|
+
case "end":
|
|
57
|
+
return _context.stop();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}, _callee, null, [[2, 9]]);
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
return function (_x) {
|
|
64
|
+
return _ref3.apply(this, arguments);
|
|
65
|
+
};
|
|
66
|
+
}();
|
|
67
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { getRouteId } from '@modern-js/utils';
|
|
3
|
+
export var generateClient = function generateClient(_ref) {
|
|
4
|
+
var basedir = _ref.basedir,
|
|
5
|
+
filename = _ref.filename;
|
|
6
|
+
// TODO: loader 的约定变更
|
|
7
|
+
var componentPath = path.join(path.dirname(filename), 'layout.ts');
|
|
8
|
+
var routeId = getRouteId(componentPath, basedir);
|
|
9
|
+
var requestCreatorPath = path.join(__dirname, './create-request').replace('node', 'treeshaking').replace(/\\/g, '/');
|
|
10
|
+
var importCode = "\n import { createRequest } from '".concat(requestCreatorPath, "';\n ");
|
|
11
|
+
var requestCode = "\n const loader = createRequest('".concat(routeId, "');\n export default loader;\n export { loader };\n ");
|
|
12
|
+
return "\n ".concat(importCode, "\n ").concat(requestCode, "\n ");
|
|
13
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import _regeneratorRuntime from "@babel/runtime/helpers/esm/regeneratorRuntime";
|
|
2
|
+
import _asyncToGenerator from "@babel/runtime/helpers/esm/asyncToGenerator";
|
|
3
|
+
// eslint-disable-next-line eslint-comments/disable-enable-pair
|
|
4
|
+
|
|
5
|
+
/* eslint-disable @babel/no-invalid-this */
|
|
6
|
+
import { generateClient } from "./generate-client";
|
|
7
|
+
export default function loader(_x) {
|
|
8
|
+
return _loader.apply(this, arguments);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function _loader() {
|
|
12
|
+
_loader = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee(source) {
|
|
13
|
+
var _this$_compiler;
|
|
14
|
+
|
|
15
|
+
var target, options, code;
|
|
16
|
+
return _regeneratorRuntime().wrap(function _callee$(_context) {
|
|
17
|
+
while (1) {
|
|
18
|
+
switch (_context.prev = _context.next) {
|
|
19
|
+
case 0:
|
|
20
|
+
this.cacheable();
|
|
21
|
+
target = (_this$_compiler = this._compiler) === null || _this$_compiler === void 0 ? void 0 : _this$_compiler.options.target;
|
|
22
|
+
|
|
23
|
+
if (!(target === 'node')) {
|
|
24
|
+
_context.next = 4;
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return _context.abrupt("return", source);
|
|
29
|
+
|
|
30
|
+
case 4:
|
|
31
|
+
options = this.getOptions();
|
|
32
|
+
code = generateClient({
|
|
33
|
+
basedir: options.routesDir,
|
|
34
|
+
filename: this.resourcePath
|
|
35
|
+
});
|
|
36
|
+
return _context.abrupt("return", code);
|
|
37
|
+
|
|
38
|
+
case 7:
|
|
39
|
+
case "end":
|
|
40
|
+
return _context.stop();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}, _callee, this);
|
|
44
|
+
}));
|
|
45
|
+
return _loader.apply(this, arguments);
|
|
46
|
+
}
|