~repos /edge-city
git clone https://pyrossh.dev/repos/edge-city.git
edge-city is a next level meta-framework for react that runs only on edge runtimes
0568068f
—
Peter John 2 years ago
add services
- packages/cli/index.js +33 -170
- packages/runtime/index.js +20 -0
packages/cli/index.js
CHANGED
|
@@ -44,12 +44,7 @@ const isProd = process.env.NODE_ENV === "production";
|
|
|
44
44
|
const routes = walkdir.sync(path.join(process.cwd(), "pages"))
|
|
45
45
|
.filter((p) => p.includes("page.jsx"));
|
|
46
46
|
const services = walkdir.sync(path.join(process.cwd(), "services"))
|
|
47
|
-
.map((s) => s.replace(process.cwd(), ""))
|
|
48
47
|
.filter((s) => s.includes(".service.js"))
|
|
49
|
-
.forEach((s) => {
|
|
50
|
-
const serviceName = s.replace(".service.js", "");
|
|
51
|
-
routes[serviceName + "/*"] = { key: serviceName, service: s };
|
|
52
|
-
});
|
|
53
48
|
|
|
54
49
|
const mapDeps = (dir) => {
|
|
55
50
|
return walkdir.sync(path.join(process.cwd(), dir))
|
|
@@ -121,20 +116,21 @@ const buildRouteMap = () => {
|
|
|
121
116
|
// });
|
|
122
117
|
|
|
123
118
|
|
|
124
|
-
const buildServer = async (
|
|
119
|
+
const buildServer = async (src, type) => {
|
|
125
120
|
const buildStart = Date.now();
|
|
126
|
-
const shortName =
|
|
121
|
+
const shortName = src.replace(process.cwd(), "");
|
|
122
|
+
const outName = type === "service" ? shortName.replace(".service.js", "") + "/index.js" : shortName.replace("/pages", "").replace("page.jsx", "index.js");
|
|
127
|
-
const outfile = `${process.cwd()}/build/functions${
|
|
123
|
+
const outfile = `${process.cwd()}/build/functions${outName}`;
|
|
128
124
|
const result = await esbuild.build({
|
|
129
125
|
bundle: true,
|
|
130
126
|
target: ['es2022'],
|
|
131
|
-
entryPoints: [
|
|
127
|
+
entryPoints: [src],
|
|
132
128
|
outfile: outfile,
|
|
133
129
|
format: 'esm',
|
|
134
130
|
keepNames: true,
|
|
135
131
|
external: ["node:*"],
|
|
136
132
|
color: true,
|
|
137
|
-
treeShaking:
|
|
133
|
+
treeShaking: true,
|
|
138
134
|
// metafile: true,
|
|
139
135
|
jsxDev: !isProd,
|
|
140
136
|
jsx: 'automatic',
|
|
@@ -156,91 +152,43 @@ const buildServer = async (r) => {
|
|
|
156
152
|
);
|
|
157
153
|
}
|
|
158
154
|
|
|
159
|
-
const bundleBun = async (r) => {
|
|
155
|
+
// const bundleBun = async (r, type) => {
|
|
160
|
-
|
|
156
|
+
// const buildStart = Date.now();
|
|
161
|
-
|
|
157
|
+
// const shortName = r.replace(process.cwd(), "").replace("/page.jsx", "");
|
|
162
|
-
|
|
158
|
+
// const result = await Bun.build({
|
|
163
|
-
|
|
159
|
+
// entrypoints: [r],
|
|
164
|
-
|
|
160
|
+
// outdir: `${process.cwd()}/bb/functions/${shortName}`,
|
|
165
|
-
|
|
161
|
+
// });
|
|
166
|
-
|
|
162
|
+
// if (!result.success) {
|
|
167
|
-
|
|
163
|
+
// console.error("Build failed");
|
|
168
|
-
|
|
164
|
+
// for (const message of result.logs) {
|
|
169
|
-
|
|
165
|
+
// // Bun will pretty print the message object
|
|
170
|
-
|
|
166
|
+
// console.error(message);
|
|
167
|
+
// }
|
|
171
|
-
|
|
168
|
+
// }
|
|
172
|
-
}
|
|
173
|
-
|
|
169
|
+
// for (const o of result.outputs) {
|
|
174
|
-
|
|
170
|
+
// const outLength = (await o.arrayBuffer()).byteLength;
|
|
175
|
-
|
|
171
|
+
// const builtTime = ms(Date.now() - buildStart);
|
|
176
|
-
|
|
172
|
+
// console.log(
|
|
177
|
-
|
|
173
|
+
// `✓ Bundled ${o.kind} ${o.path.replace(process.cwd() + "/bb", "")} ${pc.cyan(`(${bytes(outLength)})`)} ${pc.gray(`[${builtTime}]`)}`
|
|
178
|
-
|
|
174
|
+
// );
|
|
175
|
+
// }
|
|
179
|
-
|
|
176
|
+
// }
|
|
180
|
-
}
|
|
181
177
|
|
|
182
178
|
const main = async () => {
|
|
183
179
|
createDirs();
|
|
184
180
|
buildImportMap();
|
|
185
181
|
buildRouteMap();
|
|
186
182
|
for (const r of routes) {
|
|
187
|
-
buildServer(r);
|
|
183
|
+
await buildServer(r, "page");
|
|
184
|
+
}
|
|
185
|
+
for (const s of services) {
|
|
186
|
+
await buildServer(s, "service");
|
|
188
187
|
}
|
|
189
188
|
}
|
|
190
189
|
|
|
191
190
|
main();
|
|
192
191
|
|
|
193
|
-
// const createServerRouter = async () => {
|
|
194
|
-
// const routes = {};
|
|
195
|
-
// const dirs = walkdir.sync(path.join(process.cwd(), "pages"))
|
|
196
|
-
// .map((s) => s.replace(process.cwd(), "")
|
|
197
|
-
// .replace("/pages", "")
|
|
198
|
-
// // .replaceAll("[", ":")
|
|
199
|
-
// // .replaceAll("]", "")
|
|
200
|
-
// )
|
|
201
|
-
|
|
202
|
-
// dirs.filter((p) => p.includes('page.jsx'))
|
|
203
|
-
// .map((s) => ({ path: s, route: s.replace("/page.jsx", "") }))
|
|
204
|
-
// .forEach((page) => {
|
|
205
|
-
// const key = page.route || "/";
|
|
206
|
-
// routes[key] = { key: key, page: page.path };
|
|
207
|
-
// });
|
|
208
|
-
// walkdir.sync(path.join(process.cwd(), "static"))
|
|
209
|
-
// .map((s) => s.replace(process.cwd(), "").replace("/static", ""))
|
|
210
|
-
// .forEach((route) => {
|
|
211
|
-
// routes[route] = { key: route, file: route }
|
|
212
|
-
// });
|
|
213
|
-
|
|
214
|
-
// return createRouter({
|
|
215
|
-
// strictTrailingSlash: true,
|
|
216
|
-
// routes: routes,
|
|
217
|
-
// });
|
|
218
|
-
// }
|
|
219
|
-
|
|
220
|
-
// const createClientRouter = async () => {
|
|
221
|
-
// const routes = await walkdir.sync(path.join(process.cwd(), "pages"))
|
|
222
|
-
// .filter((p) => p.includes("page.jsx"))
|
|
223
|
-
// .filter((p) => !p.includes("/_"))
|
|
224
|
-
// .map((s) => s.replace(process.cwd(), ""))
|
|
225
|
-
// .map((s) => s.replace("/pages", ""))
|
|
226
|
-
// .map((s) => s.replace("/page.jsx", ""))
|
|
227
|
-
// .reduce(async (accp, r) => {
|
|
228
|
-
// const acc = await accp;
|
|
229
|
-
// const src = await import(`${process.cwd()}/pages${r}/page.jsx`);
|
|
230
|
-
// if (!result.success) {
|
|
231
|
-
// console.error("Build failed");
|
|
232
|
-
// for (const message of result.logs) {
|
|
233
|
-
// // Bun will pretty print the message object
|
|
234
|
-
// console.error(message);
|
|
235
|
-
// }
|
|
236
|
-
// }
|
|
237
|
-
// acc[r === "" ? "/" : r] = src.default;
|
|
238
|
-
// return acc
|
|
239
|
-
// }, Promise.resolve({}));
|
|
240
|
-
// // console.log(clientRoutes);
|
|
241
|
-
// };
|
|
242
|
-
|
|
243
|
-
|
|
244
192
|
// const serverRouter = await createServerRouter();
|
|
245
193
|
// const clientRouter = await createClientRouter();
|
|
246
194
|
// const transpiler = new Bun.Transpiler({
|
|
@@ -253,27 +201,6 @@ main();
|
|
|
253
201
|
// // jsxOptimizationInline: false,
|
|
254
202
|
// });
|
|
255
203
|
|
|
256
|
-
// const renderApi = async (key, filePath, req) => {
|
|
257
|
-
// const url = new URL(req.url);
|
|
258
|
-
// const params = req.method === "POST" ? await req.json() : Object.fromEntries(url.searchParams);
|
|
259
|
-
// const funcName = url.pathname.replace(`${key}/`, "");
|
|
260
|
-
// const js = await import(path.join(process.cwd(), filePath));
|
|
261
|
-
// try {
|
|
262
|
-
// const result = await js[funcName](params);
|
|
263
|
-
// return new Response(JSON.stringify(result), {
|
|
264
|
-
// headers: { 'Content-Type': 'application/json' },
|
|
265
|
-
// status: 200,
|
|
266
|
-
// });
|
|
267
|
-
// } catch (err) {
|
|
268
|
-
// const message = err.format ? err.format() : err;
|
|
269
|
-
// return new Response(JSON.stringify(message), {
|
|
270
|
-
// headers: { 'Content-Type': 'application/json' },
|
|
271
|
-
// status: 400,
|
|
272
|
-
// });
|
|
273
|
-
// }
|
|
274
|
-
|
|
275
|
-
// }
|
|
276
|
-
|
|
277
204
|
// const renderCss = async (src) => {
|
|
278
205
|
// try {
|
|
279
206
|
// const cssText = await Bun.file(src).text();
|
|
@@ -334,68 +261,4 @@ main();
|
|
|
334
261
|
// status: 404,
|
|
335
262
|
// });
|
|
336
263
|
// }
|
|
337
|
-
// }
|
|
264
|
+
// }
|
|
338
|
-
|
|
339
|
-
// const sendFile = async (src) => {
|
|
340
|
-
// try {
|
|
341
|
-
// const contentType = mimeTypes.lookup(src) || "application/octet-stream";
|
|
342
|
-
// const stream = await Bun.file(src).stream();
|
|
343
|
-
// return new Response(stream, {
|
|
344
|
-
// headers: { 'Content-Type': contentType },
|
|
345
|
-
// status: 200,
|
|
346
|
-
// });
|
|
347
|
-
// } catch (err) {
|
|
348
|
-
// return new Response(`Not Found`, {
|
|
349
|
-
// headers: { 'Content-Type': 'text/html' },
|
|
350
|
-
// status: 404,
|
|
351
|
-
// });
|
|
352
|
-
// }
|
|
353
|
-
// }
|
|
354
|
-
|
|
355
|
-
// // const mf = new Miniflare({
|
|
356
|
-
// // script: `
|
|
357
|
-
// // addEventListener("fetch", (event) => {
|
|
358
|
-
// // event.respondWith(new Response("Hello Miniflare!"));
|
|
359
|
-
// // });
|
|
360
|
-
// // `,
|
|
361
|
-
// // });
|
|
362
|
-
// // const res = await mf.dispatchFetch("http://localhost:3000/");
|
|
363
|
-
// // console.log(await res.text()); // Hello Miniflare!
|
|
364
|
-
|
|
365
|
-
// const server = async (req) => {
|
|
366
|
-
// const url = new URL(req.url);
|
|
367
|
-
// console.log(req.method, url.pathname);
|
|
368
|
-
// // maybe this is needed
|
|
369
|
-
// if (url.pathname.startsWith("/parotta/")) {
|
|
370
|
-
// return renderJs(path.join(import.meta.dir, url.pathname.replace("/parotta/", "")));
|
|
371
|
-
// }
|
|
372
|
-
// if (url.pathname.endsWith(".css")) {
|
|
373
|
-
// return renderCss(path.join(process.cwd(), url.pathname));
|
|
374
|
-
// }
|
|
375
|
-
// if (url.pathname.endsWith(".js") || url.pathname.endsWith(".jsx")) {
|
|
376
|
-
// return renderJs(path.join(process.cwd(), url.pathname));
|
|
377
|
-
// }
|
|
378
|
-
// const match = serverRouter.lookup(url.pathname);
|
|
379
|
-
// if (match && !match.key.includes("/_")) {
|
|
380
|
-
// if (match.file) {
|
|
381
|
-
// return sendFile(path.join(process.cwd(), `/static${match.file}`));
|
|
382
|
-
// }
|
|
383
|
-
// if (match.page && req.headers.get("Accept")?.includes('text/html')) {
|
|
384
|
-
// return renderPage(url);
|
|
385
|
-
// }
|
|
386
|
-
// if (match.service) {
|
|
387
|
-
// return renderApi(match.key, match.service, req);
|
|
388
|
-
// }
|
|
389
|
-
// }
|
|
390
|
-
// if (req.headers.get("Accept")?.includes('text/html')) {
|
|
391
|
-
// // not found html page
|
|
392
|
-
// return renderPage(new URL(`${url.protocol}//${url.host}/_404`));
|
|
393
|
-
// }
|
|
394
|
-
// // not found generic page
|
|
395
|
-
// return new Response(`{"message": "not found"}`, {
|
|
396
|
-
// headers: { 'Content-Type': 'application/json' },
|
|
397
|
-
// status: 404,
|
|
398
|
-
// });
|
|
399
|
-
// }
|
|
400
|
-
|
|
401
|
-
// export default server;
|
packages/runtime/index.js
CHANGED
|
@@ -330,4 +330,24 @@ export const renderPage = async (PageComponent, req) => {
|
|
|
330
330
|
headers: { 'Content-Type': 'text/html' },
|
|
331
331
|
status: 200,
|
|
332
332
|
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export const renderApi = async (key, filePath, req) => {
|
|
336
|
+
const url = new URL(req.url);
|
|
337
|
+
const params = req.method === "POST" ? await req.json() : Object.fromEntries(url.searchParams);
|
|
338
|
+
const funcName = url.pathname.replace(`${key}/`, "");
|
|
339
|
+
const js = await import(path.join(process.cwd(), filePath));
|
|
340
|
+
try {
|
|
341
|
+
const result = await js[funcName](params);
|
|
342
|
+
return new Response(JSON.stringify(result), {
|
|
343
|
+
headers: { 'Content-Type': 'application/json' },
|
|
344
|
+
status: 200,
|
|
345
|
+
});
|
|
346
|
+
} catch (err) {
|
|
347
|
+
const message = err.format ? err.format() : err;
|
|
348
|
+
return new Response(JSON.stringify(message), {
|
|
349
|
+
headers: { 'Content-Type': 'application/json' },
|
|
350
|
+
status: 400,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
333
353
|
}
|