@getcronit/pylon 3.0.0-canary-20250303143548.bb9615641321063a172cd6af0a5cd52e2a2bc0a1 → 3.0.0-canary-20250312165655.826d17474bf64dfdbd9e31dd76e4f3898d48a6d1
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/index.d.ts +1 -1
- package/dist/index.js +3 -780
- package/dist/index.js.map +4 -4
- package/dist/pages/index.d.ts +1 -3
- package/dist/pages/index.js +1 -62
- package/dist/pages/index.js.map +3 -3
- package/package.json +7 -32
- package/dist/pages/image.d.ts +0 -10
- package/dist/plugins/use-pages/build/app-utils.d.ts +0 -7
- package/dist/plugins/use-pages/build/index.d.ts +0 -2
- package/dist/plugins/use-pages/build/plugins/image-plugin.d.ts +0 -2
- package/dist/plugins/use-pages/build/plugins/inject-app-hydration.d.ts +0 -2
- package/dist/plugins/use-pages/build/plugins/postcss-plugin.d.ts +0 -2
- package/dist/plugins/use-pages/index.d.ts +0 -4
- package/dist/plugins/use-pages/setup/app-loader.d.ts +0 -14
- package/dist/plugins/use-pages/setup/index.d.ts +0 -10
package/dist/index.js
CHANGED
|
@@ -650,7 +650,7 @@ app.use("*", async (c, next) => {
|
|
|
650
650
|
});
|
|
651
651
|
});
|
|
652
652
|
});
|
|
653
|
-
app.use("*", except(["/__pylon
|
|
653
|
+
app.use("*", except(["/__pylon/*"], logger()));
|
|
654
654
|
app.use((c, next) => {
|
|
655
655
|
c.req.id = crypto.randomUUID();
|
|
656
656
|
return next();
|
|
@@ -1157,7 +1157,7 @@ var handler = (options) => {
|
|
|
1157
1157
|
graphqlEndpoint: "/graphql",
|
|
1158
1158
|
...config,
|
|
1159
1159
|
landingPage: false,
|
|
1160
|
-
graphiql:
|
|
1160
|
+
graphiql: config?.graphiql !== false ? (req) => {
|
|
1161
1161
|
return {
|
|
1162
1162
|
shouldPersistHeaders: true,
|
|
1163
1163
|
title: "Pylon Playground",
|
|
@@ -1207,784 +1207,7 @@ function getEnv() {
|
|
|
1207
1207
|
|
|
1208
1208
|
// src/index.ts
|
|
1209
1209
|
import { createPubSub } from "graphql-yoga";
|
|
1210
|
-
|
|
1211
|
-
// src/plugins/use-pages/setup/index.tsx
|
|
1212
|
-
import fs2 from "fs";
|
|
1213
|
-
import path3 from "path";
|
|
1214
|
-
import reactServer from "react-dom/server";
|
|
1215
|
-
import { PassThrough, Readable } from "stream";
|
|
1216
|
-
|
|
1217
|
-
// src/plugins/use-pages/setup/app-loader.tsx
|
|
1218
|
-
import { useMemo } from "react";
|
|
1219
|
-
import { jsx } from "react/jsx-runtime";
|
|
1220
|
-
var AppLoader = (props) => {
|
|
1221
|
-
props.client.useHydrateCache({ cacheSnapshot: props.pylonData.cacheSnapshot });
|
|
1222
|
-
const data = props.client.useQuery();
|
|
1223
|
-
const page = useMemo(() => {
|
|
1224
|
-
const page2 = /* @__PURE__ */ jsx(
|
|
1225
|
-
props.App,
|
|
1226
|
-
{
|
|
1227
|
-
pageProps: {
|
|
1228
|
-
...props.pylonData.pageProps,
|
|
1229
|
-
data
|
|
1230
|
-
}
|
|
1231
|
-
}
|
|
1232
|
-
);
|
|
1233
|
-
return page2;
|
|
1234
|
-
}, [props]);
|
|
1235
|
-
return /* @__PURE__ */ jsx(props.Router, { ...props.routerProps, children: page });
|
|
1236
|
-
};
|
|
1237
|
-
|
|
1238
|
-
// src/plugins/use-pages/setup/index.tsx
|
|
1239
|
-
import { trimTrailingSlash } from "hono/trailing-slash";
|
|
1240
|
-
import { StaticRouter } from "react-router";
|
|
1241
|
-
import { createHash } from "crypto";
|
|
1242
|
-
import { tmpdir } from "os";
|
|
1243
|
-
import { pipeline } from "stream/promises";
|
|
1244
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1245
|
-
var disableCacheMiddleware = async (c, next) => {
|
|
1246
|
-
const env3 = getEnv();
|
|
1247
|
-
if (env3.NODE_ENV === "development") {
|
|
1248
|
-
c.header(
|
|
1249
|
-
"Cache-Control",
|
|
1250
|
-
"no-store, no-cache, must-revalidate, proxy-revalidate"
|
|
1251
|
-
);
|
|
1252
|
-
c.header("Pragma", "no-cache");
|
|
1253
|
-
c.header("Expires", "0");
|
|
1254
|
-
c.header("Surrogate-Control", "no-store");
|
|
1255
|
-
}
|
|
1256
|
-
return next();
|
|
1257
|
-
};
|
|
1258
|
-
var setup = (app2) => {
|
|
1259
|
-
const pagesFilePath = path3.resolve(process.cwd(), ".pylon", "pages.json");
|
|
1260
|
-
let pageRoutes = [];
|
|
1261
|
-
try {
|
|
1262
|
-
pageRoutes = JSON.parse(fs2.readFileSync(pagesFilePath, "utf-8"));
|
|
1263
|
-
} catch (error) {
|
|
1264
|
-
console.error("Error reading pages.json", error);
|
|
1265
|
-
}
|
|
1266
|
-
app2.use(trimTrailingSlash());
|
|
1267
|
-
let App = void 0;
|
|
1268
|
-
let client = void 0;
|
|
1269
|
-
app2.on(
|
|
1270
|
-
"GET",
|
|
1271
|
-
pageRoutes.map((pageRoute) => pageRoute.slug),
|
|
1272
|
-
disableCacheMiddleware,
|
|
1273
|
-
async (c) => {
|
|
1274
|
-
if (!App) {
|
|
1275
|
-
const module = await import(`${process.cwd()}/.pylon/__pylon/pages/app.js`);
|
|
1276
|
-
App = module.default;
|
|
1277
|
-
}
|
|
1278
|
-
if (!client) {
|
|
1279
|
-
client = await import(`${process.cwd()}/.pylon/client/index.js`);
|
|
1280
|
-
}
|
|
1281
|
-
const pageProps = {
|
|
1282
|
-
params: c.req.param(),
|
|
1283
|
-
searchParams: c.req.query(),
|
|
1284
|
-
path: c.req.path
|
|
1285
|
-
};
|
|
1286
|
-
let cacheSnapshot = void 0;
|
|
1287
|
-
const prepared = await client.prepareReactRender(
|
|
1288
|
-
/* @__PURE__ */ jsx2(
|
|
1289
|
-
AppLoader,
|
|
1290
|
-
{
|
|
1291
|
-
Router: StaticRouter,
|
|
1292
|
-
routerProps: {
|
|
1293
|
-
location: c.req.path
|
|
1294
|
-
},
|
|
1295
|
-
App,
|
|
1296
|
-
client,
|
|
1297
|
-
pylonData: {
|
|
1298
|
-
pageProps,
|
|
1299
|
-
cacheSnapshot: void 0
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
)
|
|
1303
|
-
);
|
|
1304
|
-
cacheSnapshot = prepared.cacheSnapshot;
|
|
1305
|
-
if (reactServer.renderToReadableStream) {
|
|
1306
|
-
const stream = await reactServer.renderToReadableStream(
|
|
1307
|
-
/* @__PURE__ */ jsx2(
|
|
1308
|
-
AppLoader,
|
|
1309
|
-
{
|
|
1310
|
-
Router: StaticRouter,
|
|
1311
|
-
routerProps: {
|
|
1312
|
-
location: c.req.path
|
|
1313
|
-
},
|
|
1314
|
-
App,
|
|
1315
|
-
client,
|
|
1316
|
-
pylonData: {
|
|
1317
|
-
pageProps,
|
|
1318
|
-
cacheSnapshot: prepared.cacheSnapshot
|
|
1319
|
-
}
|
|
1320
|
-
}
|
|
1321
|
-
),
|
|
1322
|
-
{
|
|
1323
|
-
bootstrapModules: ["/__pylon/static/app.js"],
|
|
1324
|
-
bootstrapScriptContent: `window.__PYLON_DATA__ = ${JSON.stringify({
|
|
1325
|
-
pageProps,
|
|
1326
|
-
cacheSnapshot
|
|
1327
|
-
})}`
|
|
1328
|
-
}
|
|
1329
|
-
);
|
|
1330
|
-
return c.body(stream);
|
|
1331
|
-
} else if (reactServer.renderToPipeableStream) {
|
|
1332
|
-
let pipeableToReadable2 = function(pipeable) {
|
|
1333
|
-
const passThrough = new PassThrough();
|
|
1334
|
-
pipeable.pipe(passThrough);
|
|
1335
|
-
return Readable.toWeb(passThrough);
|
|
1336
|
-
};
|
|
1337
|
-
var pipeableToReadable = pipeableToReadable2;
|
|
1338
|
-
const pipableStream = reactServer.renderToPipeableStream(
|
|
1339
|
-
/* @__PURE__ */ jsx2(
|
|
1340
|
-
AppLoader,
|
|
1341
|
-
{
|
|
1342
|
-
Router: StaticRouter,
|
|
1343
|
-
routerProps: {
|
|
1344
|
-
location: c.req.path
|
|
1345
|
-
},
|
|
1346
|
-
App,
|
|
1347
|
-
client,
|
|
1348
|
-
pylonData: {
|
|
1349
|
-
pageProps,
|
|
1350
|
-
cacheSnapshot: prepared.cacheSnapshot
|
|
1351
|
-
}
|
|
1352
|
-
}
|
|
1353
|
-
),
|
|
1354
|
-
{
|
|
1355
|
-
bootstrapModules: ["/__pylon/static/app.js"],
|
|
1356
|
-
bootstrapScriptContent: `window.__PYLON_DATA__ = ${JSON.stringify({
|
|
1357
|
-
pageProps,
|
|
1358
|
-
cacheSnapshot
|
|
1359
|
-
})}`,
|
|
1360
|
-
onShellReady: () => {
|
|
1361
|
-
c.header("Content-Type", "text/html");
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
);
|
|
1365
|
-
const stream = pipeableToReadable2(pipableStream);
|
|
1366
|
-
return c.body(stream);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
);
|
|
1370
|
-
const publicFilesPath = path3.resolve(
|
|
1371
|
-
process.cwd(),
|
|
1372
|
-
".pylon",
|
|
1373
|
-
"__pylon",
|
|
1374
|
-
"public"
|
|
1375
|
-
);
|
|
1376
|
-
let publicFiles = [];
|
|
1377
|
-
try {
|
|
1378
|
-
publicFiles = fs2.readdirSync(publicFilesPath);
|
|
1379
|
-
} catch (error) {
|
|
1380
|
-
}
|
|
1381
|
-
app2.on(
|
|
1382
|
-
"GET",
|
|
1383
|
-
publicFiles.map((file) => `/${file}`),
|
|
1384
|
-
disableCacheMiddleware,
|
|
1385
|
-
async (c) => {
|
|
1386
|
-
const publicFilePath = path3.resolve(
|
|
1387
|
-
process.cwd(),
|
|
1388
|
-
".pylon",
|
|
1389
|
-
"__pylon",
|
|
1390
|
-
"public",
|
|
1391
|
-
c.req.path.replace("/", "")
|
|
1392
|
-
);
|
|
1393
|
-
try {
|
|
1394
|
-
await fs2.promises.access(publicFilePath);
|
|
1395
|
-
if (publicFilePath.endsWith(".js")) {
|
|
1396
|
-
c.res.headers.set("Content-Type", "text/javascript");
|
|
1397
|
-
} else if (publicFilePath.endsWith(".css")) {
|
|
1398
|
-
c.res.headers.set("Content-Type", "text/css");
|
|
1399
|
-
} else if (publicFilePath.endsWith(".html")) {
|
|
1400
|
-
c.res.headers.set("Content-Type", "text/html");
|
|
1401
|
-
} else if (publicFilePath.endsWith(".json")) {
|
|
1402
|
-
c.res.headers.set("Content-Type", "application/json");
|
|
1403
|
-
} else if (publicFilePath.endsWith(".png")) {
|
|
1404
|
-
c.res.headers.set("Content-Type", "image/png");
|
|
1405
|
-
} else if (publicFilePath.endsWith(".jpg") || publicFilePath.endsWith(".jpeg")) {
|
|
1406
|
-
c.res.headers.set("Content-Type", "image/jpeg");
|
|
1407
|
-
} else if (publicFilePath.endsWith(".gif")) {
|
|
1408
|
-
c.res.headers.set("Content-Type", "image/gif");
|
|
1409
|
-
} else if (publicFilePath.endsWith(".svg")) {
|
|
1410
|
-
c.res.headers.set("Content-Type", "image/svg+xml");
|
|
1411
|
-
} else if (publicFilePath.endsWith(".ico")) {
|
|
1412
|
-
c.res.headers.set("Content-Type", "image/x-icon");
|
|
1413
|
-
}
|
|
1414
|
-
const stream = fs2.createReadStream(publicFilePath);
|
|
1415
|
-
const a = Readable.toWeb(stream);
|
|
1416
|
-
return c.body(a);
|
|
1417
|
-
} catch {
|
|
1418
|
-
return c.status(404);
|
|
1419
|
-
}
|
|
1420
|
-
}
|
|
1421
|
-
);
|
|
1422
|
-
app2.get("/__pylon/static/*", disableCacheMiddleware, async (c) => {
|
|
1423
|
-
const filePath = path3.resolve(
|
|
1424
|
-
process.cwd(),
|
|
1425
|
-
".pylon",
|
|
1426
|
-
"__pylon",
|
|
1427
|
-
"static",
|
|
1428
|
-
c.req.path.replace("/__pylon/static/", "")
|
|
1429
|
-
);
|
|
1430
|
-
if (!fs2.existsSync(filePath)) {
|
|
1431
|
-
return c.status(404);
|
|
1432
|
-
}
|
|
1433
|
-
if (filePath.endsWith(".js")) {
|
|
1434
|
-
c.res.headers.set("Content-Type", "text/javascript");
|
|
1435
|
-
} else if (filePath.endsWith(".css")) {
|
|
1436
|
-
c.res.headers.set("Content-Type", "text/css");
|
|
1437
|
-
} else if (filePath.endsWith(".html")) {
|
|
1438
|
-
c.res.headers.set("Content-Type", "text/html");
|
|
1439
|
-
} else if (filePath.endsWith(".json")) {
|
|
1440
|
-
c.res.headers.set("Content-Type", "application/json");
|
|
1441
|
-
} else if (filePath.endsWith(".png")) {
|
|
1442
|
-
c.res.headers.set("Content-Type", "image/png");
|
|
1443
|
-
} else if (filePath.endsWith(".jpg") || filePath.endsWith(".jpeg")) {
|
|
1444
|
-
c.res.headers.set("Content-Type", "image/jpeg");
|
|
1445
|
-
} else if (filePath.endsWith(".gif")) {
|
|
1446
|
-
c.res.headers.set("Content-Type", "image/gif");
|
|
1447
|
-
} else if (filePath.endsWith(".svg")) {
|
|
1448
|
-
c.res.headers.set("Content-Type", "image/svg+xml");
|
|
1449
|
-
} else if (filePath.endsWith(".ico")) {
|
|
1450
|
-
c.res.headers.set("Content-Type", "image/x-icon");
|
|
1451
|
-
}
|
|
1452
|
-
const stream = fs2.createReadStream(filePath);
|
|
1453
|
-
const a = Readable.toWeb(stream);
|
|
1454
|
-
return c.body(a);
|
|
1455
|
-
});
|
|
1456
|
-
app2.get("/__pylon/image", async (c) => {
|
|
1457
|
-
try {
|
|
1458
|
-
let isSupportedFormat2 = function(format2) {
|
|
1459
|
-
const supportedFormats = sharp.format;
|
|
1460
|
-
return Object.keys(supportedFormats).includes(format2);
|
|
1461
|
-
};
|
|
1462
|
-
var isSupportedFormat = isSupportedFormat2;
|
|
1463
|
-
const sharp = (await import("sharp")).default;
|
|
1464
|
-
const { src, w, h, q = "75", format = "webp" } = c.req.query();
|
|
1465
|
-
const queryStringHash = createHash("sha256").update(JSON.stringify(c.req.query())).digest("hex");
|
|
1466
|
-
if (!src) {
|
|
1467
|
-
return c.json({ error: "Missing parameters." }, 400);
|
|
1468
|
-
}
|
|
1469
|
-
let imagePath = path3.join(process.cwd(), ".pylon", src);
|
|
1470
|
-
if (src.startsWith("http://") || src.startsWith("https://")) {
|
|
1471
|
-
imagePath = await downloadImage(src);
|
|
1472
|
-
}
|
|
1473
|
-
try {
|
|
1474
|
-
await fs2.promises.access(imagePath);
|
|
1475
|
-
} catch {
|
|
1476
|
-
return c.json({ error: "Image not found" }, 404);
|
|
1477
|
-
}
|
|
1478
|
-
const metadata = await sharp(imagePath).metadata();
|
|
1479
|
-
if (!metadata.width || !metadata.height) {
|
|
1480
|
-
return c.json(
|
|
1481
|
-
{
|
|
1482
|
-
error: "Invalid image metadata. Width and height are required for resizing."
|
|
1483
|
-
},
|
|
1484
|
-
400
|
|
1485
|
-
);
|
|
1486
|
-
}
|
|
1487
|
-
const { width: finalWidth, height: finalHeight } = calculateDimensions(
|
|
1488
|
-
metadata.width,
|
|
1489
|
-
metadata.height,
|
|
1490
|
-
w ? parseInt(w) : void 0,
|
|
1491
|
-
h ? parseInt(h) : void 0
|
|
1492
|
-
);
|
|
1493
|
-
const cachePath = path3.join(IMAGE_CACHE_DIR, queryStringHash);
|
|
1494
|
-
let imageFormat = format.toLowerCase();
|
|
1495
|
-
if (!isSupportedFormat2(imageFormat)) {
|
|
1496
|
-
throw new Error("Unsupported image format");
|
|
1497
|
-
}
|
|
1498
|
-
const quality = parseInt(q);
|
|
1499
|
-
if (IS_IMAGE_CACHE_POSSIBLE) {
|
|
1500
|
-
const image = await sharp(imagePath).resize(finalWidth, finalHeight).toFormat(imageFormat, {
|
|
1501
|
-
quality
|
|
1502
|
-
}).toFile(cachePath);
|
|
1503
|
-
c.res.headers.set("Content-Type", getContentType(image.format));
|
|
1504
|
-
return c.body(
|
|
1505
|
-
Readable.toWeb(
|
|
1506
|
-
fs2.createReadStream(cachePath)
|
|
1507
|
-
)
|
|
1508
|
-
);
|
|
1509
|
-
} else {
|
|
1510
|
-
const image = await sharp(imagePath).resize(finalWidth, finalHeight).toFormat(imageFormat, {
|
|
1511
|
-
quality
|
|
1512
|
-
}).toBuffer({ resolveWithObject: true });
|
|
1513
|
-
c.res.headers.set("Content-Type", getContentType(image.info.format));
|
|
1514
|
-
return c.body(image.data);
|
|
1515
|
-
}
|
|
1516
|
-
} catch (error) {
|
|
1517
|
-
console.error("Error processing the image:", error);
|
|
1518
|
-
return c.json({ error: "Error processing the image" }, 500);
|
|
1519
|
-
}
|
|
1520
|
-
});
|
|
1521
|
-
};
|
|
1522
|
-
var IMAGE_CACHE_DIR = path3.join(process.cwd(), ".cache/__pylon/images");
|
|
1523
|
-
var IS_IMAGE_CACHE_POSSIBLE = true;
|
|
1524
|
-
try {
|
|
1525
|
-
await fs2.promises.mkdir(IMAGE_CACHE_DIR, { recursive: true });
|
|
1526
|
-
} catch (error) {
|
|
1527
|
-
IS_IMAGE_CACHE_POSSIBLE = false;
|
|
1528
|
-
}
|
|
1529
|
-
var calculateDimensions = (originalWidth, originalHeight, width, height) => {
|
|
1530
|
-
if (!width && !height) {
|
|
1531
|
-
return { width: originalWidth, height: originalHeight };
|
|
1532
|
-
}
|
|
1533
|
-
if (width && !height) {
|
|
1534
|
-
height = Math.round(width * originalHeight / originalWidth);
|
|
1535
|
-
} else if (height && !width) {
|
|
1536
|
-
width = Math.round(height * originalWidth / originalHeight);
|
|
1537
|
-
}
|
|
1538
|
-
return { width, height };
|
|
1539
|
-
};
|
|
1540
|
-
var getContentType = (format) => {
|
|
1541
|
-
switch (format.toLowerCase()) {
|
|
1542
|
-
case "webp":
|
|
1543
|
-
return "image/webp";
|
|
1544
|
-
case "jpeg":
|
|
1545
|
-
case "jpg":
|
|
1546
|
-
return "image/jpeg";
|
|
1547
|
-
case "png":
|
|
1548
|
-
return "image/png";
|
|
1549
|
-
case "gif":
|
|
1550
|
-
return "image/gif";
|
|
1551
|
-
case "svg":
|
|
1552
|
-
return "image/svg+xml";
|
|
1553
|
-
default:
|
|
1554
|
-
return "application/octet-stream";
|
|
1555
|
-
}
|
|
1556
|
-
};
|
|
1557
|
-
var downloadImage = async (url) => {
|
|
1558
|
-
const response = await fetch(url);
|
|
1559
|
-
if (!response.ok)
|
|
1560
|
-
throw new Error(`Failed to download image: ${response.statusText}`);
|
|
1561
|
-
const ext = path3.extname(new URL(url).pathname) || ".jpg";
|
|
1562
|
-
const tempFilePath = path3.join(tmpdir(), `image-${Date.now()}${ext}`);
|
|
1563
|
-
const fileStream = fs2.createWriteStream(tempFilePath);
|
|
1564
|
-
await pipeline(response.body, fileStream);
|
|
1565
|
-
return tempFilePath;
|
|
1566
|
-
};
|
|
1567
|
-
|
|
1568
|
-
// src/plugins/use-pages/build/index.ts
|
|
1569
|
-
import path7 from "path";
|
|
1570
|
-
|
|
1571
|
-
// src/plugins/use-pages/build/app-utils.ts
|
|
1572
|
-
import path4 from "path";
|
|
1573
|
-
import glob from "tiny-glob";
|
|
1574
|
-
function fnv1aHash(str) {
|
|
1575
|
-
let hash = 2166136261;
|
|
1576
|
-
for (let i = 0; i < str.length; i++) {
|
|
1577
|
-
hash ^= str.charCodeAt(i);
|
|
1578
|
-
hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
|
|
1579
|
-
}
|
|
1580
|
-
return (hash >>> 0).toString(16);
|
|
1581
|
-
}
|
|
1582
|
-
var APP_DIR = path4.join(process.cwd(), "pages");
|
|
1583
|
-
async function getPageRoutes(dir = APP_DIR) {
|
|
1584
|
-
const routes = [];
|
|
1585
|
-
const pagePattern = path4.join(dir, "**/page.{ts,tsx,js}");
|
|
1586
|
-
const layoutPattern = path4.join(dir, "**/layout.tsx");
|
|
1587
|
-
const pageFiles = await glob(pagePattern);
|
|
1588
|
-
const layoutFiles = await glob(layoutPattern);
|
|
1589
|
-
for (const pagePath of pageFiles) {
|
|
1590
|
-
const relativePagePath = path4.relative(APP_DIR, pagePath);
|
|
1591
|
-
let slug = "/" + relativePagePath.replace(/page\.(ts|tsx|js)$/, "").replace(/\[([\w-]+)\]/g, ":$1");
|
|
1592
|
-
slug = slug.replace(/\/$/, "");
|
|
1593
|
-
const layouts = layoutFiles.filter((layout) => {
|
|
1594
|
-
return pagePath.startsWith(layout.replace("layout.tsx", ""));
|
|
1595
|
-
});
|
|
1596
|
-
const layoutsWithoutRootLayout = layouts.slice(1);
|
|
1597
|
-
routes.push({
|
|
1598
|
-
pagePath,
|
|
1599
|
-
slug: slug || "/",
|
|
1600
|
-
layouts: layoutsWithoutRootLayout
|
|
1601
|
-
});
|
|
1602
|
-
}
|
|
1603
|
-
return routes;
|
|
1604
|
-
}
|
|
1605
|
-
var generateAppFile = (pageRoutes) => {
|
|
1606
|
-
const makePageMap = (routes) => {
|
|
1607
|
-
const pageMap2 = {};
|
|
1608
|
-
for (const route of routes) {
|
|
1609
|
-
pageMap2[route.pagePath] = `Page${fnv1aHash(route.pagePath)}`;
|
|
1610
|
-
}
|
|
1611
|
-
return pageMap2;
|
|
1612
|
-
};
|
|
1613
|
-
const makeLayoutMap = (routes) => {
|
|
1614
|
-
const layoutMap2 = {};
|
|
1615
|
-
for (const route of routes) {
|
|
1616
|
-
for (const layout of route.layouts) {
|
|
1617
|
-
layoutMap2[layout] = `Layout${fnv1aHash(layout)}`;
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
return layoutMap2;
|
|
1621
|
-
};
|
|
1622
|
-
const pageMap = makePageMap(pageRoutes);
|
|
1623
|
-
const layoutMap = makeLayoutMap(pageRoutes);
|
|
1624
|
-
const importPages = Object.keys(pageMap).map((pagePath, index) => {
|
|
1625
|
-
const importLocation = `../${pagePath}`.replace(".tsx", ".js");
|
|
1626
|
-
const componentName = pageMap[pagePath];
|
|
1627
|
-
return `const ${componentName} = lazy(() => import('${importLocation}'))
|
|
1628
|
-
`;
|
|
1629
|
-
}).join("\n");
|
|
1630
|
-
const importLayouts = Object.keys(layoutMap).map((layoutPath, index) => {
|
|
1631
|
-
const importLocation = `../${layoutPath}`.replace(".tsx", ".js");
|
|
1632
|
-
const componentName = layoutMap[layoutPath];
|
|
1633
|
-
return `const ${componentName} = lazy(() => import('${importLocation}'))
|
|
1634
|
-
`;
|
|
1635
|
-
}).join("\n");
|
|
1636
|
-
const appComponent = `"use client";
|
|
1637
|
-
import {lazy, Suspense} from 'react'
|
|
1638
|
-
import { __PYLON_ROUTER_INTERNALS_DO_NOT_USE } from '@getcronit/pylon/pages';
|
|
1639
|
-
const {Routes, Route} = __PYLON_ROUTER_INTERNALS_DO_NOT_USE
|
|
1640
|
-
${importPages}
|
|
1641
|
-
const RootLayout = lazy(() => import('../pages/layout.js'))
|
|
1642
|
-
${importLayouts}
|
|
1643
|
-
|
|
1644
|
-
const App: React.FC<{pageProps: any}> = ({pageProps}) => (
|
|
1645
|
-
<RootLayout>
|
|
1646
|
-
<meta charSet="utf-8" />
|
|
1647
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
1648
|
-
<link rel="stylesheet" href="/__pylon/static/app.css" precedence="high" />
|
|
1649
|
-
<Routes>
|
|
1650
|
-
${pageRoutes.map((route, index) => {
|
|
1651
|
-
return `<Route key={${index}} index={${index === 0 ? "true" : "false"}} path="${route.slug}" element={
|
|
1652
|
-
<Suspense fallback={<div>...</div>}>
|
|
1653
|
-
${route.layouts.reduceRight((child, layoutPath, layoutIndex) => {
|
|
1654
|
-
const layoutName = layoutMap[layoutPath];
|
|
1655
|
-
return `<${layoutName}>${child}</${layoutName}>`;
|
|
1656
|
-
}, `<${pageMap[route.pagePath]} {...pageProps} />`)}
|
|
1657
|
-
|
|
1658
|
-
</Suspense>} />`;
|
|
1659
|
-
}).join("\n")}
|
|
1660
|
-
</Routes>
|
|
1661
|
-
</RootLayout>
|
|
1662
|
-
);
|
|
1663
|
-
|
|
1664
|
-
export default App;
|
|
1665
|
-
`;
|
|
1666
|
-
return appComponent;
|
|
1667
|
-
};
|
|
1668
|
-
|
|
1669
|
-
// src/plugins/use-pages/build/index.ts
|
|
1670
|
-
import chokidar from "chokidar";
|
|
1671
|
-
import fs6 from "fs/promises";
|
|
1672
|
-
import esbuild from "esbuild";
|
|
1673
|
-
|
|
1674
|
-
// src/plugins/use-pages/build/plugins/inject-app-hydration.ts
|
|
1675
|
-
import path5 from "path";
|
|
1676
|
-
import fs3 from "fs/promises";
|
|
1677
|
-
var injectAppHydrationPlugin = {
|
|
1678
|
-
name: "inject-hydration",
|
|
1679
|
-
setup(build2) {
|
|
1680
|
-
build2.onLoad({ filter: /.*/, namespace: "file" }, async (args) => {
|
|
1681
|
-
if (args.path === path5.resolve(process.cwd(), ".pylon", "app.tsx")) {
|
|
1682
|
-
let contents = await fs3.readFile(args.path, "utf-8");
|
|
1683
|
-
const clientPath = path5.resolve(process.cwd(), ".pylon/client");
|
|
1684
|
-
const pathToClient = path5.relative(path5.dirname(args.path), clientPath);
|
|
1685
|
-
contents += `
|
|
1686
|
-
import {hydrateRoot} from 'react-dom/client'
|
|
1687
|
-
import * as client from './${pathToClient}'
|
|
1688
|
-
import { __PYLON_ROUTER_INTERNALS_DO_NOT_USE } from '@getcronit/pylon/pages';
|
|
1689
|
-
const {BrowserRouter} = __PYLON_ROUTER_INTERNALS_DO_NOT_USE
|
|
1690
|
-
import React, {useMemo} from 'react'
|
|
1691
|
-
|
|
1692
|
-
const pylonData = window.__PYLON_DATA__
|
|
1693
|
-
|
|
1694
|
-
const AppLoader = (props: {
|
|
1695
|
-
client: any
|
|
1696
|
-
pylonData: {
|
|
1697
|
-
pageProps: Omit<PageProps, 'data'>
|
|
1698
|
-
cacheSnapshot?: any
|
|
1699
|
-
}
|
|
1700
|
-
App: React.FC<{
|
|
1701
|
-
pageProps: PageProps
|
|
1702
|
-
}>
|
|
1703
|
-
Router: React.FC<any>
|
|
1704
|
-
routerProps: any
|
|
1705
|
-
}) => {
|
|
1706
|
-
props.client.useHydrateCache({cacheSnapshot: props.pylonData.cacheSnapshot})
|
|
1707
|
-
|
|
1708
|
-
const data = props.client.useQuery()
|
|
1709
|
-
const page = useMemo(() => {
|
|
1710
|
-
const page = (
|
|
1711
|
-
<props.App
|
|
1712
|
-
pageProps={{
|
|
1713
|
-
...props.pylonData.pageProps,
|
|
1714
|
-
data
|
|
1715
|
-
}}
|
|
1716
|
-
/>
|
|
1717
|
-
)
|
|
1718
|
-
|
|
1719
|
-
return page
|
|
1720
|
-
}, [props])
|
|
1721
|
-
|
|
1722
|
-
return <props.Router {...props.routerProps}>{page}</props.Router>
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
hydrateRoot(
|
|
1727
|
-
document,
|
|
1728
|
-
<AppLoader Router={BrowserRouter} client={client} pylonData={pylonData} App={App} />
|
|
1729
|
-
)
|
|
1730
|
-
`;
|
|
1731
|
-
return {
|
|
1732
|
-
loader: "tsx",
|
|
1733
|
-
contents
|
|
1734
|
-
};
|
|
1735
|
-
}
|
|
1736
|
-
});
|
|
1737
|
-
}
|
|
1738
|
-
};
|
|
1739
|
-
|
|
1740
|
-
// src/plugins/use-pages/build/plugins/image-plugin.ts
|
|
1741
|
-
import { createHash as createHash2 } from "crypto";
|
|
1742
|
-
import path6 from "path";
|
|
1743
|
-
import fs4 from "fs/promises";
|
|
1744
|
-
var imagePlugin = {
|
|
1745
|
-
name: "image-plugin",
|
|
1746
|
-
setup(build2) {
|
|
1747
|
-
const outdir = build2.initialOptions.outdir;
|
|
1748
|
-
const publicPath = build2.initialOptions.publicPath;
|
|
1749
|
-
if (!outdir || !publicPath) {
|
|
1750
|
-
throw new Error("outdir and publicPath must be set in esbuild options");
|
|
1751
|
-
}
|
|
1752
|
-
build2.onResolve({ filter: /\.(png|jpe?g)$/ }, async (args) => {
|
|
1753
|
-
const filePath = path6.resolve(args.resolveDir, args.path);
|
|
1754
|
-
const fileName = path6.basename(filePath);
|
|
1755
|
-
const extname = path6.extname(filePath);
|
|
1756
|
-
const hash = createHash2("md5").update(filePath + await fs4.readFile(filePath)).digest("hex").slice(0, 8);
|
|
1757
|
-
const newFilename = `${fileName}-${hash}${extname}`;
|
|
1758
|
-
const newFilePath = path6.join(outdir, "media", newFilename);
|
|
1759
|
-
await fs4.mkdir(path6.dirname(newFilePath), { recursive: true });
|
|
1760
|
-
await fs4.copyFile(filePath, newFilePath);
|
|
1761
|
-
return {
|
|
1762
|
-
path: newFilePath,
|
|
1763
|
-
namespace: "image"
|
|
1764
|
-
};
|
|
1765
|
-
});
|
|
1766
|
-
build2.onLoad({ filter: /\.png$|\.jpg$/ }, async (args) => {
|
|
1767
|
-
const sharp = (await import("sharp")).default;
|
|
1768
|
-
const image = sharp(args.path);
|
|
1769
|
-
const metadata = await image.metadata();
|
|
1770
|
-
const url = `${publicPath}/media/${path6.basename(args.path)}`;
|
|
1771
|
-
const searchParams = new URLSearchParams({});
|
|
1772
|
-
if (metadata.width) {
|
|
1773
|
-
searchParams.set("w", metadata.width.toString());
|
|
1774
|
-
}
|
|
1775
|
-
if (metadata.height) {
|
|
1776
|
-
searchParams.set("h", metadata.height.toString());
|
|
1777
|
-
}
|
|
1778
|
-
const output = image.resize({
|
|
1779
|
-
width: Math.min(metadata.width ?? 16, 16),
|
|
1780
|
-
height: Math.min(metadata.height ?? 16, 16),
|
|
1781
|
-
fit: "inside"
|
|
1782
|
-
}).toFormat("webp", {
|
|
1783
|
-
quality: 20,
|
|
1784
|
-
alphaQuality: 20,
|
|
1785
|
-
smartSubsample: true
|
|
1786
|
-
});
|
|
1787
|
-
const { data, info } = await output.toBuffer({ resolveWithObject: true });
|
|
1788
|
-
const dataURIBase64 = `data:image/${info.format};base64,${data.toString(
|
|
1789
|
-
"base64"
|
|
1790
|
-
)}`;
|
|
1791
|
-
if (dataURIBase64) {
|
|
1792
|
-
searchParams.set("blurDataURL", dataURIBase64);
|
|
1793
|
-
}
|
|
1794
|
-
return {
|
|
1795
|
-
contents: `${url}?${searchParams.toString()}`,
|
|
1796
|
-
loader: "text"
|
|
1797
|
-
};
|
|
1798
|
-
});
|
|
1799
|
-
}
|
|
1800
|
-
};
|
|
1801
|
-
|
|
1802
|
-
// src/plugins/use-pages/build/plugins/postcss-plugin.ts
|
|
1803
|
-
import fs5 from "fs/promises";
|
|
1804
|
-
import loadConfig from "postcss-load-config";
|
|
1805
|
-
import postcss from "postcss";
|
|
1806
|
-
var postcssPlugin = {
|
|
1807
|
-
name: "postcss-plugin",
|
|
1808
|
-
setup(build2) {
|
|
1809
|
-
build2.onLoad({ filter: /.css$/, namespace: "file" }, async (args) => {
|
|
1810
|
-
const { plugins, options } = await loadConfig();
|
|
1811
|
-
const css = await fs5.readFile(args.path, "utf-8");
|
|
1812
|
-
const result = await postcss(plugins).process(css, {
|
|
1813
|
-
...options,
|
|
1814
|
-
from: args.path
|
|
1815
|
-
}).then((result2) => result2);
|
|
1816
|
-
return {
|
|
1817
|
-
contents: result.css,
|
|
1818
|
-
loader: "css"
|
|
1819
|
-
};
|
|
1820
|
-
});
|
|
1821
|
-
}
|
|
1822
|
-
};
|
|
1823
|
-
|
|
1824
|
-
// src/plugins/use-pages/build/index.ts
|
|
1825
|
-
var DIST_STATIC_DIR = path7.join(process.cwd(), ".pylon/__pylon/static");
|
|
1826
|
-
var DIST_PAGES_DIR = path7.join(process.cwd(), ".pylon/__pylon/pages");
|
|
1827
|
-
async function updateFileIfChanged(path8, newContent) {
|
|
1828
|
-
try {
|
|
1829
|
-
const currentContent = await fs6.readFile(path8, "utf8");
|
|
1830
|
-
if (currentContent === newContent) {
|
|
1831
|
-
return false;
|
|
1832
|
-
}
|
|
1833
|
-
} catch (err) {
|
|
1834
|
-
if (err.code !== "ENOENT") throw err;
|
|
1835
|
-
}
|
|
1836
|
-
await fs6.writeFile(path8, newContent, "utf8");
|
|
1837
|
-
return true;
|
|
1838
|
-
}
|
|
1839
|
-
var build = async () => {
|
|
1840
|
-
const buildAppFile = async () => {
|
|
1841
|
-
const pagesRoutes = await getPageRoutes();
|
|
1842
|
-
const appContent = generateAppFile(pagesRoutes);
|
|
1843
|
-
const pagesFile = path7.resolve(process.cwd(), ".pylon", "pages.json");
|
|
1844
|
-
await updateFileIfChanged(pagesFile, JSON.stringify(pagesRoutes, null, 2));
|
|
1845
|
-
const appFilePath = path7.resolve(process.cwd(), ".pylon", "app.tsx");
|
|
1846
|
-
const state = await updateFileIfChanged(appFilePath, appContent);
|
|
1847
|
-
if (state) {
|
|
1848
|
-
}
|
|
1849
|
-
};
|
|
1850
|
-
const copyPublicDir = async () => {
|
|
1851
|
-
const publicDir = path7.resolve(process.cwd(), "public");
|
|
1852
|
-
const pylonPublicDir = path7.resolve(
|
|
1853
|
-
process.cwd(),
|
|
1854
|
-
".pylon",
|
|
1855
|
-
"__pylon",
|
|
1856
|
-
"public"
|
|
1857
|
-
);
|
|
1858
|
-
try {
|
|
1859
|
-
await fs6.access(publicDir);
|
|
1860
|
-
await fs6.mkdir(pylonPublicDir, { recursive: true });
|
|
1861
|
-
await fs6.cp(publicDir, pylonPublicDir, { recursive: true });
|
|
1862
|
-
} catch (err) {
|
|
1863
|
-
if (err.code !== "ENOENT") throw err;
|
|
1864
|
-
}
|
|
1865
|
-
};
|
|
1866
|
-
const writeOnEndPlugin = {
|
|
1867
|
-
name: "write-on-end",
|
|
1868
|
-
setup(build2) {
|
|
1869
|
-
build2.onEnd(async (result) => {
|
|
1870
|
-
await Promise.all(
|
|
1871
|
-
result.outputFiles.map(async (file) => {
|
|
1872
|
-
await fs6.mkdir(path7.dirname(file.path), { recursive: true });
|
|
1873
|
-
await updateFileIfChanged(file.path, file.text);
|
|
1874
|
-
})
|
|
1875
|
-
);
|
|
1876
|
-
});
|
|
1877
|
-
}
|
|
1878
|
-
};
|
|
1879
|
-
const nodePaths = [
|
|
1880
|
-
path7.join(process.cwd(), "node_modules"),
|
|
1881
|
-
path7.join(process.cwd(), "node_modules", "@getcronit/pylon/node_modules")
|
|
1882
|
-
];
|
|
1883
|
-
let pagesWatcher = null;
|
|
1884
|
-
const clientCtx = await esbuild.context({
|
|
1885
|
-
sourcemap: "linked",
|
|
1886
|
-
write: false,
|
|
1887
|
-
metafile: true,
|
|
1888
|
-
nodePaths,
|
|
1889
|
-
absWorkingDir: process.cwd(),
|
|
1890
|
-
plugins: [
|
|
1891
|
-
injectAppHydrationPlugin,
|
|
1892
|
-
imagePlugin,
|
|
1893
|
-
postcssPlugin,
|
|
1894
|
-
writeOnEndPlugin
|
|
1895
|
-
],
|
|
1896
|
-
publicPath: "/__pylon/static",
|
|
1897
|
-
assetNames: "assets/[name]-[hash]",
|
|
1898
|
-
chunkNames: "chunks/[name]-[hash]",
|
|
1899
|
-
format: "esm",
|
|
1900
|
-
platform: "browser",
|
|
1901
|
-
entryPoints: [".pylon/app.tsx"],
|
|
1902
|
-
outdir: DIST_STATIC_DIR,
|
|
1903
|
-
bundle: true,
|
|
1904
|
-
splitting: true,
|
|
1905
|
-
minify: true,
|
|
1906
|
-
loader: {
|
|
1907
|
-
// Map file extensions to the file loader
|
|
1908
|
-
".svg": "file",
|
|
1909
|
-
".woff": "file",
|
|
1910
|
-
".woff2": "file"
|
|
1911
|
-
},
|
|
1912
|
-
define: {
|
|
1913
|
-
"process.env.NODE_ENV": JSON.stringify(
|
|
1914
|
-
process.env.NODE_ENV || "development"
|
|
1915
|
-
)
|
|
1916
|
-
},
|
|
1917
|
-
mainFields: ["browser", "module", "main"]
|
|
1918
|
-
});
|
|
1919
|
-
const serverCtx = await esbuild.context({
|
|
1920
|
-
sourcemap: "inline",
|
|
1921
|
-
write: false,
|
|
1922
|
-
absWorkingDir: process.cwd(),
|
|
1923
|
-
nodePaths,
|
|
1924
|
-
plugins: [imagePlugin, postcssPlugin, writeOnEndPlugin],
|
|
1925
|
-
publicPath: "/__pylon/static",
|
|
1926
|
-
assetNames: "assets/[name]-[hash]",
|
|
1927
|
-
chunkNames: "chunks/[name]-[hash]",
|
|
1928
|
-
format: "esm",
|
|
1929
|
-
platform: "node",
|
|
1930
|
-
entryPoints: [".pylon/app.tsx"],
|
|
1931
|
-
outdir: DIST_PAGES_DIR,
|
|
1932
|
-
bundle: true,
|
|
1933
|
-
splitting: false,
|
|
1934
|
-
external: ["@getcronit/pylon", "react", "react-dom", "gqty", "@gqty/react"],
|
|
1935
|
-
minify: true,
|
|
1936
|
-
loader: {
|
|
1937
|
-
// Map file extensions to the file loader
|
|
1938
|
-
".svg": "file",
|
|
1939
|
-
".woff": "file",
|
|
1940
|
-
".woff2": "file"
|
|
1941
|
-
},
|
|
1942
|
-
define: {
|
|
1943
|
-
"process.env.NODE_ENV": JSON.stringify(
|
|
1944
|
-
process.env.NODE_ENV || "development"
|
|
1945
|
-
)
|
|
1946
|
-
},
|
|
1947
|
-
mainFields: ["module", "main"]
|
|
1948
|
-
});
|
|
1949
|
-
return {
|
|
1950
|
-
watch: async () => {
|
|
1951
|
-
pagesWatcher = chokidar.watch("pages", { ignoreInitial: true });
|
|
1952
|
-
pagesWatcher.on("all", async (event, path8) => {
|
|
1953
|
-
if (["add", "change", "unlink"].includes(event)) {
|
|
1954
|
-
await buildAppFile();
|
|
1955
|
-
await copyPublicDir();
|
|
1956
|
-
}
|
|
1957
|
-
});
|
|
1958
|
-
await Promise.all([clientCtx.watch(), serverCtx.watch()]);
|
|
1959
|
-
},
|
|
1960
|
-
dispose: async () => {
|
|
1961
|
-
if (pagesWatcher) {
|
|
1962
|
-
pagesWatcher.close();
|
|
1963
|
-
}
|
|
1964
|
-
Promise.all([clientCtx.dispose(), serverCtx.dispose()]);
|
|
1965
|
-
},
|
|
1966
|
-
rebuild: async () => {
|
|
1967
|
-
await buildAppFile();
|
|
1968
|
-
await copyPublicDir();
|
|
1969
|
-
await Promise.all([clientCtx.rebuild(), serverCtx.rebuild()]);
|
|
1970
|
-
return {};
|
|
1971
|
-
},
|
|
1972
|
-
cancel: async () => {
|
|
1973
|
-
if (pagesWatcher) {
|
|
1974
|
-
await pagesWatcher.close();
|
|
1975
|
-
}
|
|
1976
|
-
await Promise.all([clientCtx.cancel(), serverCtx.cancel()]);
|
|
1977
|
-
}
|
|
1978
|
-
};
|
|
1979
|
-
};
|
|
1980
|
-
|
|
1981
|
-
// src/plugins/use-pages/index.ts
|
|
1982
|
-
function usePages() {
|
|
1983
|
-
return {
|
|
1984
|
-
setup,
|
|
1985
|
-
build
|
|
1986
|
-
};
|
|
1987
|
-
}
|
|
1210
|
+
import { usePages } from "@getcronit/pylon-pages";
|
|
1988
1211
|
export {
|
|
1989
1212
|
ServiceError,
|
|
1990
1213
|
app,
|