@torpor/build 0.4.13 → 0.4.14
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/bin/index.js +1 -1
- package/dist/index.mjs +6 -6
- package/dist/index.mjs.map +1 -1
- package/dist/{run-DiZgkMnG.mjs → run-BPFtSYA3.mjs} +32 -32
- package/dist/run-BPFtSYA3.mjs.map +1 -0
- package/dist/run.mjs +1 -1
- package/dist/test.mjs +4 -4
- package/dist/test.mjs.map +1 -1
- package/package.json +1 -1
- package/src/site/serverEntry.ts +11 -1
- package/dist/run-DiZgkMnG.mjs.map +0 -1
package/dist/bin/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import "../pathToRegex-TUAMc3zS.mjs";
|
|
3
3
|
import "../seeOther-B4Yhu9iq.mjs";
|
|
4
4
|
import "../response-C5TtAsh1.mjs";
|
|
5
|
-
import { t as run } from "../run-
|
|
5
|
+
import { t as run } from "../run-BPFtSYA3.mjs";
|
|
6
6
|
import "../ServerEvent-CxPwA4lH.mjs";
|
|
7
7
|
import "../connectMiddleware-D7nehjj3.mjs";
|
|
8
8
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./pathToRegex-TUAMc3zS.mjs";
|
|
2
2
|
import { a as LAYOUT_SERVER_ROUTE, c as SERVER_ROUTE, i as LAYOUT_ROUTE, l as Router, n as HOOK_ROUTE, o as PAGE_ROUTE, r as HOOK_SERVER_ROUTE, s as PAGE_SERVER_ROUTE, t as ERROR_ROUTE } from "./RouteType-B6BMOyYw.mjs";
|
|
3
3
|
import { promises } from "node:fs";
|
|
4
|
-
import
|
|
4
|
+
import fpath from "node:path";
|
|
5
5
|
import tsconfigPaths from "vite-tsconfig-paths";
|
|
6
6
|
|
|
7
7
|
//#region src/site/defaultAdapter.ts
|
|
@@ -46,14 +46,14 @@ var Site = class {
|
|
|
46
46
|
* set of routes with their own hook for authorization from various clients
|
|
47
47
|
*/
|
|
48
48
|
async addRouteFolder(folder, subFolder) {
|
|
49
|
-
const routeFolder =
|
|
49
|
+
const routeFolder = fpath.join(this.root, folder);
|
|
50
50
|
const routeFiles = await promises.readdir(routeFolder, { recursive: true });
|
|
51
51
|
if (subFolder !== void 0 && !subFolder.startsWith("/")) subFolder = "/" + subFolder;
|
|
52
|
-
for (let file of routeFiles) if (/^(\+|_).+(\.js|\.ts)$/.test(
|
|
52
|
+
for (let file of routeFiles) if (/^(\+|_).+(\.js|\.ts)$/.test(fpath.basename(file))) {
|
|
53
53
|
let routePath = this.#routePath(file);
|
|
54
54
|
if (subFolder !== void 0) routePath = subFolder + routePath;
|
|
55
55
|
let type = this.#routeType(file);
|
|
56
|
-
file =
|
|
56
|
+
file = fpath.relative(this.root, fpath.resolve(routeFolder, file));
|
|
57
57
|
this.routes.push({
|
|
58
58
|
path: routePath,
|
|
59
59
|
file,
|
|
@@ -70,8 +70,8 @@ var Site = class {
|
|
|
70
70
|
* @param file The file
|
|
71
71
|
* @param type The file type (if the file name is non-standard)
|
|
72
72
|
*/
|
|
73
|
-
addRouteFile(path
|
|
74
|
-
let routePath = this.#routePath(
|
|
73
|
+
addRouteFile(path, file, type, subFolder) {
|
|
74
|
+
let routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));
|
|
75
75
|
let routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);
|
|
76
76
|
if (subFolder !== void 0 && !subFolder.startsWith("/")) subFolder = "/" + subFolder;
|
|
77
77
|
this.routes.push({
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["defaultAdapter: Adapter","defaultAdapter","
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["defaultAdapter: Adapter","defaultAdapter","fs","#routePath","#routeType","#sortRoutes","#routeTypeFromString"],"sources":["../src/site/defaultAdapter.ts","../src/site/Site.ts"],"sourcesContent":["import type Adapter from \"../types/Adapter\";\n\n// TODO: This should be an adapter-auto package that conditionally loads other packages...\n\nconst defaultAdapter: Adapter = {\n\tserve: () => {\n\t\tconsole.log(\"An adapter needs to be set in site.config\");\n\t},\n};\n\nexport default defaultAdapter;\n","import { promises as fs } from \"node:fs\";\nimport fpath from \"node:path\";\nimport { type Plugin, type UserConfig } from \"vite\";\nimport tsconfigPaths from \"vite-tsconfig-paths\";\nimport type Adapter from \"../types/Adapter\";\nimport type Route from \"../types/Route\";\nimport {\n\tERROR_ROUTE,\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tRouteType,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport defaultAdapter from \"./defaultAdapter\";\n\n// 1. The user sets this up\n// 2. It is passed into serverEntry and clientEntry through a Vite plugin\n// (defined in manifest.ts)\n// 3. In those files, it is used to build a Router\n\n/**\n * The Site class contains the information necessary to setup a @torpor/build\n * site, including routes, plugins, and options.\n */\nexport default class Site {\n\troot: string;\n\troutes: Route[] = [];\n\t// Is default plugins a bad idea?\n\t// HACK: Set loose because otherwise it uses a list of allowed extensions\n\t// TODO: Should probably just do this ourselves and let the user pass in\n\t// tsconfigPaths themselves if they want to do something funky\n\tplugins: Plugin[] = [tsconfigPaths({ loose: true })];\n\t// Is default adapter a bad idea?\n\tadapter: Adapter = defaultAdapter;\n\t/**\n\t * Extra inputs, as absolute file paths, that will be compiled with the\n\t * output. What you do with them after that is up to you. File paths ending\n\t * with server.ts/js will only be compiled with the server output\n\t */\n\tinputs: string[] = [];\n\t/**\n\t * Vite config options to merge with the standard Torpor build options.\n\t * `plugins` and `build.rollupOptions.input` will be overridden, so you\n\t * should set `Site.plugins` and `Site.inputs` instead. Other options may be\n\t * overridden or incompatible, so experimentation may be required\n\t */\n\tviteConfig?: UserConfig;\n\n\tconstructor() {\n\t\tthis.root = process.cwd();\n\t}\n\n\t/**\n\t * Adds a folder of routes, based on the names of the files in the folder\n\t * @param folder The folder containing the routes\n\t * @param subFolder If a subFolder is set, all routes in the folder will be\n\t * placed under the subFolder, and only hooks, layouts etc will be used if\n\t * they have the same subFolder. This can be used to create e.g. an `api`\n\t * set of routes with their own hook for authorization from various clients\n\t */\n\tasync addRouteFolder(folder: string, subFolder?: string): Promise<void> {\n\t\tconst routeFolder = fpath.join(this.root, folder);\n\t\tconst routeFiles = await fs.readdir(routeFolder, { recursive: true });\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tfor (let file of routeFiles) {\n\t\t\t// The file must start with `+` or `_` and end with `.js` or `.ts`\n\t\t\tif (/^(\\+|_).+(\\.js|\\.ts)$/.test(fpath.basename(file))) {\n\t\t\t\tlet routePath = this.#routePath(file);\n\t\t\t\tif (subFolder !== undefined) {\n\t\t\t\t\troutePath = subFolder + routePath;\n\t\t\t\t}\n\t\t\t\tlet type = this.#routeType(file);\n\t\t\t\tfile = fpath.relative(this.root, fpath.resolve(routeFolder, file));\n\t\t\t\tthis.routes.push({\n\t\t\t\t\tpath: routePath,\n\t\t\t\t\tfile,\n\t\t\t\t\ttype,\n\t\t\t\t\tsubFolder: subFolder,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.#sortRoutes();\n\t}\n\n\t/**\n\t * Adds a file route, which can have a standard name (e.g. +page.ts) or any\n\t * name if you pass the type\n\t * @param path The route path\n\t * @param file The file\n\t * @param type The file type (if the file name is non-standard)\n\t */\n\taddRouteFile(\n\t\tpath: string,\n\t\tfile: string,\n\t\ttype?:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t\tsubFolder?: string,\n\t): void {\n\t\tlet routePath = this.#routePath(fpath.join(path, type ?? fpath.basename(file)));\n\t\tlet routeType = type ? this.#routeTypeFromString(type) : this.#routeType(file);\n\t\tif (subFolder !== undefined && !subFolder.startsWith(\"/\")) {\n\t\t\tsubFolder = \"/\" + subFolder;\n\t\t}\n\t\tthis.routes.push({\n\t\t\tpath: routePath,\n\t\t\tfile,\n\t\t\ttype: routeType,\n\t\t\tsubFolder: subFolder,\n\t\t});\n\t\tthis.#sortRoutes();\n\t}\n\n\t#routePath(file: string): string {\n\t\tlet routePath = file\n\t\t\t.replace(/^\\//, \"\")\n\t\t\t.replace(/(\\.ts|\\.js)$/, \"\")\n\t\t\t.replace(/_hook.server$/, \"_hook/~server\")\n\t\t\t.replace(/_layout.server$/, \"_layout/~server\")\n\t\t\t.replace(/\\+page.server$/, \"~server\")\n\t\t\t.replace(/\\+server$/, \"\")\n\t\t\t.replace(/\\+page$/, \"\")\n\t\t\t.replace(/\\/$/, \"\");\n\t\treturn routePath.length > 0 ? `/${routePath}` : \"/\";\n\t}\n\n\t#routeType(file: string): RouteType {\n\t\tlet routePath = file.replace(/^\\//, \"\").replace(/(\\.ts|\\.js)$/, \"\");\n\t\tif (routePath.endsWith(\"+page\")) {\n\t\t\treturn PAGE_ROUTE;\n\t\t} else if (routePath.endsWith(\"+page.server\")) {\n\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"+server\")) {\n\t\t\treturn SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout\")) {\n\t\t\treturn LAYOUT_ROUTE;\n\t\t} else if (routePath.endsWith(\"_layout.server\")) {\n\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook\")) {\n\t\t\treturn HOOK_ROUTE;\n\t\t} else if (routePath.endsWith(\"_hook.server\")) {\n\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t} else if (routePath.endsWith(\"_error\")) {\n\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t\treturn -1;\n\t}\n\n\t#routeTypeFromString(\n\t\ttype:\n\t\t\t| \"+page\"\n\t\t\t| \"+page.server\"\n\t\t\t| \"+server\"\n\t\t\t| \"_layout\"\n\t\t\t| \"_layout.server\"\n\t\t\t| \"_hook\"\n\t\t\t| \"_hook.server\"\n\t\t\t| \"_error\",\n\t) {\n\t\tswitch (type) {\n\t\t\tcase \"+page\":\n\t\t\t\treturn PAGE_ROUTE;\n\t\t\tcase \"+page.server\":\n\t\t\t\treturn PAGE_SERVER_ROUTE;\n\t\t\tcase \"+server\":\n\t\t\t\treturn SERVER_ROUTE;\n\t\t\tcase \"_layout\":\n\t\t\t\treturn LAYOUT_ROUTE;\n\t\t\tcase \"_layout.server\":\n\t\t\t\treturn LAYOUT_SERVER_ROUTE;\n\t\t\tcase \"_hook\":\n\t\t\t\treturn HOOK_ROUTE;\n\t\t\tcase \"_hook.server\":\n\t\t\t\treturn HOOK_SERVER_ROUTE;\n\t\t\tcase \"_error\":\n\t\t\t\treturn ERROR_ROUTE;\n\t\t}\n\t}\n\n\t// TODO: You could make your site in a single file, like e.g. Hono...\n\t//addPage(path: string, endPoint: PageEndPoint, serverEndPoint?: PageServerEndPoint) {}\n\t//addEndPoint(path: string, endPoint: ServerEndPoint) {}\n\n\t#sortRoutes() {\n\t\tthis.routes = this.routes.sort((a, b) => {\n\t\t\t// Sort [param]s after paths\n\t\t\t// There might be a quicker/easier way to do this\n\t\t\tfor (let i = 0; i < Math.min(a.path.length, b.path.length); i++) {\n\t\t\t\tif (a.path[i] === \"[\" && b.path[i] !== \"[\") {\n\t\t\t\t\treturn 1;\n\t\t\t\t} else if (b.path[i] === \"[\" && a.path[i] !== \"[\") {\n\t\t\t\t\treturn -1;\n\t\t\t\t} else if (a.path[i] === b.path[i]) {\n\t\t\t\t\t// Keep going...\n\t\t\t\t} else {\n\t\t\t\t\treturn a.path[i].localeCompare(b.path[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn a.path.length - b.path.length;\n\t\t});\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { i as serverError } from "./response-C5TtAsh1.mjs";
|
|
2
2
|
import { n as Server, t as connectMiddleware } from "./connectMiddleware-D7nehjj3.mjs";
|
|
3
3
|
import fs, { existsSync, promises, readFileSync } from "node:fs";
|
|
4
|
-
import
|
|
4
|
+
import fpath from "node:path";
|
|
5
5
|
import { build, createServer, defineConfig, transformWithEsbuild } from "vite";
|
|
6
6
|
import torpor from "@torpor/unplugin/vite";
|
|
7
7
|
import estorpor from "@torpor/unplugin/esbuild";
|
|
@@ -31,8 +31,8 @@ export default {
|
|
|
31
31
|
routes: [
|
|
32
32
|
${site.routes.map((r) => {
|
|
33
33
|
let endPoint;
|
|
34
|
-
if (serverRequest || !/server\.(ts|js)$/.test(r.file)) endPoint = `() => import(/* @vite-ignore */ "${
|
|
35
|
-
else endPoint = readFileSync(
|
|
34
|
+
if (serverRequest || !/server\.(ts|js)$/.test(r.file)) endPoint = `() => import(/* @vite-ignore */ "${fpath.join(site.root, r.file)}")`;
|
|
35
|
+
else endPoint = readFileSync(fpath.join(site.root, r.file)).includes("load:") ? "() => load" : "undefined";
|
|
36
36
|
const sub = r.subFolder ? `"${r.subFolder}"` : "undefined";
|
|
37
37
|
return `{ path: "${r.path}", type: ${r.type}, endPoint: ${endPoint}, subFolder: ${sub} }`;
|
|
38
38
|
}).join(",\n ")}
|
|
@@ -47,15 +47,15 @@ export default {
|
|
|
47
47
|
//#endregion
|
|
48
48
|
//#region src/run/runBuild.ts
|
|
49
49
|
async function runBuild(site) {
|
|
50
|
-
const distFolder =
|
|
50
|
+
const distFolder = fpath.resolve(site.root, "dist");
|
|
51
51
|
if (existsSync(distFolder)) await promises.rm(distFolder, { recursive: true });
|
|
52
|
-
const clientFolder =
|
|
53
|
-
const serverFolder =
|
|
52
|
+
const clientFolder = fpath.join(distFolder, "client");
|
|
53
|
+
const serverFolder = fpath.join(distFolder, "server");
|
|
54
54
|
if (site.adapter.prebuild) await site.adapter.prebuild(site);
|
|
55
|
-
let siteHtml =
|
|
56
|
-
const siteFolder =
|
|
57
|
-
let clientScript =
|
|
58
|
-
let serverScript =
|
|
55
|
+
let siteHtml = fpath.resolve(site.root, "src/site.html");
|
|
56
|
+
const siteFolder = fpath.resolve(site.root, "./node_modules/@torpor/build/src/site/");
|
|
57
|
+
let clientScript = fpath.join(siteFolder, "clientEntry.ts");
|
|
58
|
+
let serverScript = fpath.join(siteFolder, "serverEntry.ts");
|
|
59
59
|
const clientConfig = structuredClone(site.viteConfig ?? {});
|
|
60
60
|
clientConfig.plugins = [
|
|
61
61
|
manifest(site),
|
|
@@ -68,7 +68,7 @@ async function runBuild(site) {
|
|
|
68
68
|
clientConfig.build.rollupOptions.input = [
|
|
69
69
|
siteHtml,
|
|
70
70
|
clientScript,
|
|
71
|
-
...site.routes.filter((r) => !/server\.(ts|js)$/.test(r.file)).map((r) =>
|
|
71
|
+
...site.routes.filter((r) => !/server\.(ts|js)$/.test(r.file)).map((r) => fpath.resolve(site.root, r.file)),
|
|
72
72
|
...site.inputs.filter((f) => !/server\.(ts|js)$/.test(f))
|
|
73
73
|
];
|
|
74
74
|
clientConfig.build.ssrManifest = true;
|
|
@@ -84,14 +84,14 @@ async function runBuild(site) {
|
|
|
84
84
|
serverConfig.build.rollupOptions ??= {};
|
|
85
85
|
serverConfig.build.rollupOptions.input = [
|
|
86
86
|
serverScript,
|
|
87
|
-
...site.routes.map((r) =>
|
|
87
|
+
...site.routes.map((r) => fpath.resolve(site.root, r.file)),
|
|
88
88
|
...site.inputs
|
|
89
89
|
];
|
|
90
90
|
serverConfig.build.ssr = serverScript;
|
|
91
91
|
await build(defineConfig(serverConfig));
|
|
92
|
-
siteHtml =
|
|
93
|
-
await promises.rename(
|
|
94
|
-
await promises.rm(
|
|
92
|
+
siteHtml = fpath.join(clientFolder, "site.html");
|
|
93
|
+
await promises.rename(fpath.join(clientFolder, "src", "site.html"), siteHtml);
|
|
94
|
+
await promises.rm(fpath.join(clientFolder, "src"), { recursive: true });
|
|
95
95
|
if (site.adapter.postbuild) await site.adapter.postbuild(site);
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -135,13 +135,13 @@ async function runDev(site) {
|
|
|
135
135
|
config.optimizeDeps.esbuildOptions.plugins ??= [];
|
|
136
136
|
config.optimizeDeps.esbuildOptions.plugins.push(estorpor());
|
|
137
137
|
const vite = await createServer(config);
|
|
138
|
-
const templateFile =
|
|
138
|
+
const templateFile = fpath.resolve(site.root, "src/site.html");
|
|
139
139
|
let template = await promises.readFile(templateFile, "utf-8");
|
|
140
140
|
template = await vite.transformIndexHtml("", template);
|
|
141
|
-
const siteFolder =
|
|
142
|
-
let clientScript =
|
|
143
|
-
let clientDevScript =
|
|
144
|
-
let serverScript =
|
|
141
|
+
const siteFolder = fpath.resolve(site.root, "./node_modules/@torpor/build/src/site/");
|
|
142
|
+
let clientScript = fpath.join(siteFolder, "clientEntry.ts");
|
|
143
|
+
let clientDevScript = fpath.join(siteFolder, "clientEntryDev.ts");
|
|
144
|
+
let serverScript = fpath.join(siteFolder, "serverEntry.ts");
|
|
145
145
|
template = prepareTemplate(template, clientScript, clientDevScript);
|
|
146
146
|
server.use(connectMiddleware(vite.middlewares));
|
|
147
147
|
server.add("*", async (ev) => {
|
|
@@ -249,32 +249,32 @@ const types = {
|
|
|
249
249
|
//#region src/run/runPreview.ts
|
|
250
250
|
async function runPreview(site) {
|
|
251
251
|
await runBuild(site);
|
|
252
|
-
const distFolder =
|
|
253
|
-
const clientFolder =
|
|
254
|
-
const serverFolder =
|
|
255
|
-
let clientScript = (await promises.readdir(
|
|
252
|
+
const distFolder = fpath.resolve(site.root, "dist");
|
|
253
|
+
const clientFolder = fpath.join(distFolder, "client");
|
|
254
|
+
const serverFolder = fpath.join(distFolder, "server");
|
|
255
|
+
let clientScript = (await promises.readdir(fpath.join(clientFolder, "assets"))).find((f) => f.startsWith("clientEntry-"));
|
|
256
256
|
if (!clientScript) throw new Error("clientEntry.js not found");
|
|
257
257
|
clientScript = `/assets/${clientScript}`;
|
|
258
|
-
let siteHtml =
|
|
258
|
+
let siteHtml = fpath.join(clientFolder, "site.html");
|
|
259
259
|
let template = await promises.readFile(siteHtml, "utf-8");
|
|
260
260
|
template = prepareTemplate(template, clientScript);
|
|
261
261
|
const server = new Server();
|
|
262
262
|
server.add("/assets/*", async (ev) => {
|
|
263
263
|
try {
|
|
264
264
|
const url = new URL(ev.request.url);
|
|
265
|
-
const file =
|
|
265
|
+
const file = fpath.join(site.root, "dist", "client", url.pathname);
|
|
266
266
|
if (existsSync(file)) {
|
|
267
267
|
const body = bufferToArrayBuffer(await promises.readFile(file));
|
|
268
268
|
return new Response(body, {
|
|
269
269
|
status: 200,
|
|
270
|
-
headers: { "Content-Type": contentType(
|
|
270
|
+
headers: { "Content-Type": contentType(fpath.extname(file)) }
|
|
271
271
|
});
|
|
272
272
|
}
|
|
273
273
|
} catch (e) {
|
|
274
274
|
return serverError(e);
|
|
275
275
|
}
|
|
276
276
|
});
|
|
277
|
-
const serverScript =
|
|
277
|
+
const serverScript = fpath.resolve(serverFolder, "serverEntry.js");
|
|
278
278
|
server.add("*", async (ev) => {
|
|
279
279
|
try {
|
|
280
280
|
const { load } = await import(serverScript);
|
|
@@ -298,11 +298,11 @@ function bufferToArrayBuffer(buffer) {
|
|
|
298
298
|
async function run(folder, mode) {
|
|
299
299
|
let configFile = "";
|
|
300
300
|
let deleteConfigFile = false;
|
|
301
|
-
const jsConfigFile =
|
|
302
|
-
const tsConfigFile =
|
|
301
|
+
const jsConfigFile = fpath.join(folder, "site.config.js");
|
|
302
|
+
const tsConfigFile = fpath.join(folder, "site.config.ts");
|
|
303
303
|
if (fs.existsSync(jsConfigFile)) configFile = jsConfigFile;
|
|
304
304
|
else if (fs.existsSync(tsConfigFile)) {
|
|
305
|
-
configFile =
|
|
305
|
+
configFile = fpath.join(folder, "site.config.temp.js");
|
|
306
306
|
let transformed = await transformWithEsbuild(fs.readFileSync(tsConfigFile, "utf-8"), tsConfigFile, { loader: "ts" });
|
|
307
307
|
fs.writeFileSync(configFile, transformed.code);
|
|
308
308
|
deleteConfigFile = true;
|
|
@@ -329,4 +329,4 @@ async function run(folder, mode) {
|
|
|
329
329
|
|
|
330
330
|
//#endregion
|
|
331
331
|
export { runBuild as i, runPreview as n, runDev as r, run as t };
|
|
332
|
-
//# sourceMappingURL=run-
|
|
332
|
+
//# sourceMappingURL=run-BPFtSYA3.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-BPFtSYA3.mjs","names":["endPoint: string","path","path","fs","createViteServer","path","fs","e: any","types: Record<string, string>","path","fs","e: any","path"],"sources":["../src/site/manifest.ts","../src/run/runBuild.ts","../src/run/prepareTemplate.ts","../src/run/runDev.ts","../src/server/contentType.ts","../src/run/runPreview.ts","../src/run/run.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { Plugin } from \"vite\";\nimport Site from \"./Site\";\n\nconst moduleId = \"@torpor/build/manifest\";\n\n/**\n * A Vite plugin that provides information about the app to both clientEntry and\n * serverEntry.\n */\nexport default function manifest(site: Site, server = false): Plugin {\n\treturn {\n\t\tname: \"torpor-manifest\",\n\t\tresolveId: {\n\t\t\torder: \"pre\",\n\t\t\thandler(id) {\n\t\t\t\tif (id === moduleId) {\n\t\t\t\t\treturn id;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// @ts-ignore\n\t\tload(id, viteOptions) {\n\t\t\tif (id === moduleId) {\n\t\t\t\tlet serverRequest = server && !!viteOptions?.ssr;\n\t\t\t\treturn `\n${!serverRequest ? \"const load = { default: { load: true } };\" : \"\"}\nexport default {\n routes: [\n ${site.routes\n\t\t\t.map((r) => {\n\t\t\t\tlet endPoint: string;\n\t\t\t\tif (serverRequest || !/server\\.(ts|js)$/.test(r.file)) {\n\t\t\t\t\tendPoint = `() => import(/* @vite-ignore */ \"${path.join(site.root, r.file)}\")`;\n\t\t\t\t} else {\n\t\t\t\t\t// On the client, for a server route, we need to check\n\t\t\t\t\t// whether there's a load function and set a dummy endPoint\n\t\t\t\t\t// if so. The correct endpoint will be hit in clientEntry\n\t\t\t\t\t// HACK: Should do this better than checking for `load:` in source...\n\t\t\t\t\tconst haveLoad = readFileSync(path.join(site.root, r.file)).includes(\"load:\");\n\t\t\t\t\tendPoint = haveLoad ? \"() => load\" : \"undefined\";\n\t\t\t\t}\n\t\t\t\tconst sub = r.subFolder ? `\"${r.subFolder}\"` : \"undefined\";\n\t\t\t\treturn `{ path: \"${r.path}\", type: ${r.type}, endPoint: ${endPoint}, subFolder: ${sub} }`;\n\t\t\t})\n\t\t\t.join(\",\\n \")}\n ],\n};\n`;\n\t\t\t}\n\t\t},\n\t};\n}\n","import torpor from \"@torpor/unplugin/vite\";\nimport { existsSync, promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { build, defineConfig } from \"vite\";\nimport Site from \"../site/Site\";\nimport manifest from \"../site/manifest.ts\";\n\n// TODO: Don't cache index.html in dev?\n// TODO: Multiple hook.server locations\n// TODO: Don't reload layouts during client routing\n// TODO: Call the correct +page and +server routes when in the same folder\n\nexport default async function runBuild(site: Site): Promise<void> {\n\t// Delete the dist folder if it exists\n\tconst distFolder = path.resolve(site.root, \"dist\");\n\tif (existsSync(distFolder)) {\n\t\tawait fs.rm(distFolder, { recursive: true });\n\t}\n\tconst clientFolder = path.join(distFolder, \"client\");\n\tconst serverFolder = path.join(distFolder, \"server\");\n\n\t// HOOK: Prebuild\n\tif (site.adapter.prebuild) {\n\t\tawait site.adapter.prebuild(site);\n\t}\n\n\t// TODO: From a setting\n\tlet siteHtml = path.resolve(site.root, \"src/site.html\");\n\n\tconst siteFolder = path.resolve(site.root, \"./node_modules/@torpor/build/src/site/\");\n\tlet clientScript = path.join(siteFolder, \"clientEntry.ts\");\n\tlet serverScript = path.join(siteFolder, \"serverEntry.ts\");\n\n\t// Build the client assets, including site.html and the route files\n\t// EXCLUDING anything with `server.js` in the name\n\tconst clientConfig = structuredClone(site.viteConfig ?? {});\n\tclientConfig.plugins = [manifest(site), torpor(), ...site.plugins];\n\tclientConfig.build ??= {};\n\tclientConfig.build.outDir = clientFolder;\n\tclientConfig.build.rollupOptions ??= {};\n\tclientConfig.build.rollupOptions.input = [\n\t\tsiteHtml,\n\t\tclientScript,\n\t\t...site.routes\n\t\t\t.filter((r) => !/server\\.(ts|js)$/.test(r.file))\n\t\t\t.map((r) => path.resolve(site.root, r.file)),\n\t\t...site.inputs.filter((f) => !/server\\.(ts|js)$/.test(f)),\n\t];\n\tclientConfig.build.ssrManifest = true;\n\tawait build(defineConfig(clientConfig));\n\n\t// Build the server assets, including the server entry script and the route\n\t// files\n\tconst serverConfig = structuredClone(site.viteConfig ?? {});\n\tserverConfig.plugins = [manifest(site, true), torpor(), ...site.plugins];\n\tserverConfig.build ??= {};\n\tserverConfig.build.outDir = serverFolder;\n\tserverConfig.build.rollupOptions ??= {};\n\tserverConfig.build.rollupOptions.input = [\n\t\tserverScript,\n\t\t...site.routes.map((r) => path.resolve(site.root, r.file)),\n\t\t...site.inputs,\n\t];\n\tserverConfig.build.ssr = serverScript;\n\tawait build(defineConfig(serverConfig));\n\n\t// Move the site.html file into /client\n\t// HACK: Should do this in Rollup if possible?\n\tsiteHtml = path.join(clientFolder, \"site.html\");\n\tawait fs.rename(path.join(clientFolder, \"src\", \"site.html\"), siteHtml);\n\tawait fs.rm(path.join(clientFolder, \"src\"), { recursive: true });\n\n\t// HOOK: Postbuild\n\tif (site.adapter.postbuild) {\n\t\tawait site.adapter.postbuild(site);\n\t}\n}\n","export default function prepareTemplate(\n\ttemplate: string,\n\tclientScript: string,\n\tclientDevScript?: string,\n): string {\n\tlet result = template;\n\n\t// Put %COMPONENT_HEAD% before </head>\n\t// This is where styles will go\n\tlet headStart = result.indexOf(\"</head>\");\n\tif (headStart === -1) {\n\t\tthrow new Error(`Couldn't find <head> end tag`);\n\t}\n\tresult = result.substring(0, headStart) + \"%COMPONENT_HEAD%\" + result.substring(headStart);\n\n\t// Put %COMPONENT_BODY% inside <div id=\"app\"></div>\n\t// This is where the component's HTML will go\n\tlet bodyStart = regexIndexOf(result, /<div\\s+id=(\"app\"|'app'|app)\\s+/);\n\tbodyStart = result.indexOf(\">\", bodyStart) + 1;\n\tlet bodyEnd = result.indexOf(\"</div>\", bodyStart);\n\tif (bodyStart === -1 || bodyEnd === -1) {\n\t\tthrow new Error(`Couldn't find <div id=\"app\"></div>`);\n\t}\n\tresult = result.substring(0, bodyStart) + \"%COMPONENT_BODY%\" + result.substring(bodyEnd);\n\n\t// Add the clientEntry script at the very end, for hydrating and navigating\n\tif (clientDevScript) {\n\t\tresult += `<script type=\"module\" src=\"${clientDevScript}\"></script>`;\n\t}\n\tresult += `<script type=\"module\" src=\"${clientScript}\"></script>`;\n\n\treturn result;\n}\n\n// From https://stackoverflow.com/a/274094\nfunction regexIndexOf(string: string, regex: RegExp, position?: number) {\n\tvar indexOf = string.substring(position || 0).search(regex);\n\treturn indexOf >= 0 ? indexOf + (position || 0) : indexOf;\n}\n","import estorpor from \"@torpor/unplugin/esbuild\";\nimport torpor from \"@torpor/unplugin/vite\";\nimport { configDotenv } from \"dotenv\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { createServer as createViteServer } from \"vite\";\nimport { serverError } from \"../response.ts\";\nimport Server from \"../server/Server.ts\";\nimport connectMiddleware from \"../server/connect/connectMiddleware.ts\";\nimport Site from \"../site/Site.ts\";\nimport manifest from \"../site/manifest.ts\";\nimport prepareTemplate from \"./prepareTemplate.ts\";\n\nexport default async function runDev(site: Site): Promise<void> {\n\tconst server = new Server();\n\n\t// Create the Vite server in middleware mode and configure the app type as\n\t// \"custom\", disabling Vite's own HTML serving logic so the parent server\n\t// can take control\n\tconst config = structuredClone(site.viteConfig ?? {});\n\tconfig.server = { middlewareMode: true };\n\tconfig.appType = \"custom\";\n\tconfig.plugins = [manifest(site, true), torpor({ dev: true }), ...site.plugins];\n\n\t// HACK: To be able to import `.torp` files from barrel files in\n\t// node_modules, we need to add their libraries to `ssr.noExternal` in\n\t// site.config.ts, and let esbuild know how to compile them here\n\tconfig.optimizeDeps ??= {};\n\tconfig.optimizeDeps.extensions ??= [];\n\tconfig.optimizeDeps.extensions.push(\".torp\");\n\tconfig.optimizeDeps.esbuildOptions ??= {};\n\tconfig.optimizeDeps.esbuildOptions.plugins ??= [];\n\tconfig.optimizeDeps.esbuildOptions.plugins.push(estorpor());\n\n\tconst vite = await createViteServer(config);\n\n\t// Read site.html\n\t// It's called site.html because @torpor/build builds the site (html, routes\n\t// etc) while the user builds the app (components etc)\n\tconst templateFile = path.resolve(site.root, \"src/site.html\");\n\tlet template = await fs.readFile(templateFile, \"utf-8\");\n\n\t// Apply Vite HTML transforms. This injects the Vite HMR client, and also\n\t// applies HTML transforms from Vite plugins. Note that we only support a\n\t// universal transform, not individual transforms for each route\n\ttemplate = await vite.transformIndexHtml(\"\", template);\n\n\tconst siteFolder = path.resolve(site.root, \"./node_modules/@torpor/build/src/site/\");\n\tlet clientScript = path.join(siteFolder, \"clientEntry.ts\");\n\tlet clientDevScript = path.join(siteFolder, \"clientEntryDev.ts\");\n\tlet serverScript = path.join(siteFolder, \"serverEntry.ts\");\n\n\t// Prepare site.html so that we can just splice components into it\n\ttemplate = prepareTemplate(template, clientScript, clientDevScript);\n\n\t// Use Vite's Connect instance as middleware. We need to wrap it with\n\t// createMiddlewareHandler that converts Connect middleware to\n\t// Request/Response web handlers\n\tserver.use(connectMiddleware(vite.middlewares));\n\n\t// Every request (GET, POST, etc) goes through loadEndPoint\n\tserver.add(\"*\", async (ev) => {\n\t\ttry {\n\t\t\t// Load the server entry. ssrLoadModule automatically transforms ESM\n\t\t\t// source code to be usable in Node.js. No bundling is required, and\n\t\t\t// it provides efficient invalidation similar to HMR\n\t\t\tconst { load } = await vite.ssrLoadModule(serverScript);\n\n\t\t\t// Render the app HTML (or fetch server data etc) via serverEntry's\n\t\t\t// exported `load` function\n\t\t\treturn await load(ev, template);\n\t\t} catch (e: any) {\n\t\t\t// If an error is caught, let Vite fix the stack trace so it maps\n\t\t\t// back to your actual source code\n\t\t\tvite.ssrFixStacktrace(e);\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Load environment variables from a `.env` file, with defaults if not set\n\tconfigDotenv();\n\n\tprocess.env.PROTOCOL ??= \"http:\";\n\tprocess.env.HOST ??= \"localhost\";\n\tprocess.env.PORT ??= \"7059\";\n\n\t// Serve the site\n\tsite.adapter.serve(server, site);\n}\n","// From https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types\n\nexport default function contentType(extension: string): string {\n\treturn types[extension] || \"application/octet-stream\";\n}\n\nconst types: Record<string, string> = {\n\t\".aac\": \"audio/aac\",\n\t\".abw\": \"application/x-abiword\",\n\t\".apng\": \"image/apng\",\n\t\".arc\": \"application/x-freearc\",\n\t\".avif\": \"image/avif\",\n\t\".avi\": \"video/x-msvideo\",\n\t\".azw\": \"application/vnd.amazon.ebook\",\n\t\".bin\": \"application/octet-stream\",\n\t\".bmp\": \"image/bmp\",\n\t\".bz\": \"application/x-bzip\",\n\t\".bz2\": \"application/x-bzip2\",\n\t\".cda\": \"application/x-cdf\",\n\t\".csh\": \"application/x-csh\",\n\t\".css\": \"text/css\",\n\t\".csv\": \"text/csv\",\n\t\".doc\": \"application/msword\",\n\t\".docx\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\t\".eot\": \"application/vnd.ms-fontobject\",\n\t\".epub\": \"application/epub+zip\",\n\t\".gz\": \"application/gzip\",\n\t\".gif\": \"image/gif\",\n\t\".htm\": \"text/html\",\n\t\".html\": \"text/html\",\n\t\".ico\": \"image/vnd.microsoft.icon\",\n\t\".ics\": \"text/calendar\",\n\t\".jar\": \"application/java-archive\",\n\t\".jpeg\": \"image/jpeg\",\n\t\".jpg\": \"image/jpeg\",\n\t\".js\": \"text/javascript\",\n\t\".json\": \"application/json\",\n\t\".jsonld\": \"application/ld+json\",\n\t\".mid\": \"audio/midi\",\n\t\".midi\": \"audio/midi\",\n\t\".mjs\": \"text/javascript\",\n\t\".mp3\": \"audio/mpeg\",\n\t\".mp4\": \"video/mp4\",\n\t\".mpeg\": \"video/mpeg\",\n\t\".mpkg\": \"application/vnd.apple.installer+xml\",\n\t\".odp\": \"application/vnd.oasis.opendocument.presentation\",\n\t\".ods\": \"application/vnd.oasis.opendocument.spreadsheet\",\n\t\".odt\": \"application/vnd.oasis.opendocument.text\",\n\t\".oga\": \"audio/ogg\",\n\t\".ogv\": \"video/ogg\",\n\t\".ogx\": \"application/ogg\",\n\t\".opus\": \"audio/ogg\",\n\t\".otf\": \"font/otf\",\n\t\".png\": \"image/png\",\n\t\".pdf\": \"application/pdf\",\n\t\".php\": \"application/x-httpd-php\",\n\t\".ppt\": \"application/vnd.ms-powerpoint\",\n\t\".pptx\": \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n\t\".rar\": \"application/vnd.rar\",\n\t\".rtf\": \"application/rtf\",\n\t\".sh\": \"application/x-sh\",\n\t\".svg\": \"image/svg+xml\",\n\t\".tar\": \"application/x-tar\",\n\t\".tif\": \"image/tiff\",\n\t\".tiff\": \"image/tiff\",\n\t\".ts\": \"video/mp2t\",\n\t\".ttf\": \"font/ttf\",\n\t\".txt\": \"text/plain\",\n\t\".vsd\": \"application/vnd.visio\",\n\t\".wav\": \"audio/wav\",\n\t\".weba\": \"audio/webm\",\n\t\".webm\": \"video/webm\",\n\t\".webp\": \"image/webp\",\n\t\".woff\": \"font/woff\",\n\t\".woff2\": \"font/woff2\",\n\t\".xhtml\": \"application/xhtml+xml\",\n\t\".xls\": \"application/vnd.ms-excel\",\n\t\".xlsx\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n\t\".xml\": \"application/xml\",\n\t\".xul\": \"application/vnd.mozilla.xul+xml\",\n\t\".zip\": \"application/zip\",\n\t\".3gp\": \"video/3gpp\",\n\t\".3g2\": \"video/3gpp2\",\n\t\".7z\": \"application/x-7z-compressed\",\n};\n","import { configDotenv } from \"dotenv\";\nimport { existsSync, promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { serverError } from \"../response.ts\";\nimport Server from \"../server/Server.ts\";\nimport contentType from \"../server/contentType.ts\";\nimport Site from \"../site/Site\";\nimport prepareTemplate from \"./prepareTemplate.ts\";\nimport runBuild from \"./runBuild\";\n\nexport default async function runPreview(site: Site): Promise<void> {\n\t// Build the site\n\tawait runBuild(site);\n\n\tconst distFolder = path.resolve(site.root, \"dist\");\n\tconst clientFolder = path.join(distFolder, \"client\");\n\tconst serverFolder = path.join(distFolder, \"server\");\n\n\t// Find the client script file in /assets\n\tlet clientScript = (await fs.readdir(path.join(clientFolder, \"assets\"))).find((f) =>\n\t\tf.startsWith(\"clientEntry-\"),\n\t);\n\tif (!clientScript) {\n\t\tthrow new Error(\"clientEntry.js not found\");\n\t}\n\tclientScript = `/assets/${clientScript}`;\n\n\t// Read site.html\n\t// It's called site.html because @torpor/build builds the site (html, routes\n\t// etc) while the user builds the app (components etc)\n\tlet siteHtml = path.join(clientFolder, \"site.html\");\n\tlet template = await fs.readFile(siteHtml, \"utf-8\");\n\n\t// Prepare site.html so that we can just splice components into it\n\ttemplate = prepareTemplate(template, clientScript);\n\n\t// Configure the server\n\tconst server = new Server();\n\n\t// Serve dist/client/assets statically\n\tserver.add(\"/assets/*\", async (ev) => {\n\t\ttry {\n\t\t\tconst url = new URL(ev.request.url);\n\t\t\tconst file = path.join(site.root, \"dist\", \"client\", url.pathname);\n\t\t\tif (existsSync(file)) {\n\t\t\t\t// TODO: Stream the data?\n\t\t\t\tconst body = bufferToArrayBuffer(await fs.readFile(file));\n\t\t\t\treturn new Response(body, {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": contentType(path.extname(file)),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (e: any) {\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Every request (GET, POST, etc) goes through loadEndPoint\n\tconst serverScript = path.resolve(serverFolder, \"serverEntry.js\");\n\tserver.add(\"*\", async (ev) => {\n\t\ttry {\n\t\t\t// Load the server entry\n\t\t\tconst { load } = await import(serverScript);\n\n\t\t\t// Render the app HTML (or fetch server data etc) via serverEntry's\n\t\t\t// exported `load` function\n\t\t\treturn await load(ev, template);\n\t\t} catch (e: any) {\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Load environment variables from a `.env` file, with defaults if not set\n\tconfigDotenv();\n\n\tprocess.env.PROTOCOL ??= \"http:\";\n\tprocess.env.HOST ??= \"localhost\";\n\tprocess.env.PORT ??= \"7059\";\n\n\t// Serve the site\n\tsite.adapter.serve(server, site);\n}\n\n// From https://stackoverflow.com/a/79345620\n// No idea why it is needed\nfunction bufferToArrayBuffer(buffer: Buffer): ArrayBuffer {\n\treturn buffer.buffer.slice(\n\t\tbuffer.byteOffset,\n\t\tbuffer.byteOffset + buffer.byteLength,\n\t) as ArrayBuffer;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { transformWithEsbuild } from \"vite\";\nimport Site from \"../site/Site\";\nimport runBuild from \"./runBuild\";\nimport runDev from \"./runDev\";\nimport runPreview from \"./runPreview\";\n\nexport default async function run(\n\tfolder: string,\n\tmode: \"dev\" | \"build\" | \"preview\",\n): Promise<void> {\n\t// Look for and load a site.config.js/ts file in the working directory\n\tlet configFile = \"\";\n\tlet deleteConfigFile = false;\n\tconst jsConfigFile = path.join(folder, \"site.config.js\");\n\tconst tsConfigFile = path.join(folder, \"site.config.ts\");\n\tif (fs.existsSync(jsConfigFile)) {\n\t\t// If it's JS, we can just import it straight up\n\t\tconfigFile = jsConfigFile;\n\t} else if (fs.existsSync(tsConfigFile)) {\n\t\t// If it's TS, we need to convert it to JS\n\t\t// TODO: Put the generated file somewhere better (dist?)\n\t\tconfigFile = path.join(folder, \"site.config.temp.js\");\n\t\tlet source = fs.readFileSync(tsConfigFile, \"utf-8\");\n\t\tlet transformed = await transformWithEsbuild(source, tsConfigFile, {\n\t\t\tloader: \"ts\",\n\t\t});\n\t\tfs.writeFileSync(configFile, transformed.code);\n\t\tdeleteConfigFile = true;\n\t} else {\n\t\tthrow new Error(\"site.config file not found\");\n\t}\n\n\tconst site = (await import(configFile)).default as Site;\n\tif (!site || !site.root || !site.routes) {\n\t\tthrow new Error(\"Invalid site in config file\");\n\t}\n\tif (deleteConfigFile) {\n\t\tfs.rmSync(configFile);\n\t}\n\n\tswitch (mode) {\n\t\tcase \"dev\": {\n\t\t\tawait runDev(site);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"build\": {\n\t\t\tawait runBuild(site);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"preview\": {\n\t\t\tawait runPreview(site);\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tconsole.log(\"No mode passed, running in dev\");\n\t\t\tawait runDev(site);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
package/dist/run.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import "./pathToRegex-TUAMc3zS.mjs";
|
|
2
2
|
import "./seeOther-B4Yhu9iq.mjs";
|
|
3
3
|
import "./response-C5TtAsh1.mjs";
|
|
4
|
-
import { i as runBuild, n as runPreview, r as runDev, t as run } from "./run-
|
|
4
|
+
import { i as runBuild, n as runPreview, r as runDev, t as run } from "./run-BPFtSYA3.mjs";
|
|
5
5
|
import "./ServerEvent-CxPwA4lH.mjs";
|
|
6
6
|
import "./connectMiddleware-D7nehjj3.mjs";
|
|
7
7
|
|
package/dist/test.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { a as LAYOUT_SERVER_ROUTE, c as SERVER_ROUTE, i as LAYOUT_ROUTE, l as Ro
|
|
|
3
3
|
import { t as $page_default } from "./_page-BQs4WvCO.mjs";
|
|
4
4
|
import { n as ok, r as notFound, t as seeOther } from "./seeOther-B4Yhu9iq.mjs";
|
|
5
5
|
import { t as ServerEvent } from "./ServerEvent-CxPwA4lH.mjs";
|
|
6
|
-
import
|
|
6
|
+
import fpath from "node:path";
|
|
7
7
|
|
|
8
8
|
//#region src/test/runTest.ts
|
|
9
9
|
/**
|
|
@@ -22,7 +22,7 @@ async function runTest(site, route, ev) {
|
|
|
22
22
|
type: r.type,
|
|
23
23
|
endPoint: () => import(
|
|
24
24
|
/* @vite-ignore */
|
|
25
|
-
|
|
25
|
+
fpath.join(site.root, r.file)
|
|
26
26
|
),
|
|
27
27
|
subFolder: r.subFolder
|
|
28
28
|
})));
|
|
@@ -30,9 +30,9 @@ async function runTest(site, route, ev) {
|
|
|
30
30
|
}
|
|
31
31
|
async function load(router, ev, template) {
|
|
32
32
|
const url = new URL(ev.request.url);
|
|
33
|
-
const path
|
|
33
|
+
const path = url.pathname;
|
|
34
34
|
const query = url.searchParams;
|
|
35
|
-
const route = router.match(path
|
|
35
|
+
const route = router.match(path, query);
|
|
36
36
|
if (!route) return notFound();
|
|
37
37
|
$page_default.url = url;
|
|
38
38
|
const handler = route.handler;
|
package/dist/test.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.mjs","names":["path","serverEndPoint: ServerEndPoint | undefined","serverHook: ServerHook | undefined","clientEndPoint: PageEndPoint | undefined","serverEndPoint: PageServerEndPoint | undefined","layoutEndPoint: PageEndPoint | undefined","$props: Record<string, any>","slots: Record<string, ServerSlotRender> | undefined","slotFunctions: ServerSlotRender[]"],"sources":["../src/test/runTest.ts"],"sourcesContent":["import { type ServerComponent, type ServerSlotRender } from \"@torpor/view/ssr\";\nimport path from \"node:path\";\nimport notFound from \"../response/notFound.ts\";\nimport ok from \"../response/ok.ts\";\nimport seeOther from \"../response/seeOther.ts\";\nimport ServerEvent from \"../server/ServerEvent.ts\";\nimport Router from \"../site/Router.ts\";\nimport Site from \"../site/Site\";\nimport $page from \"../state/$page.ts\";\nimport type PageEndPoint from \"../types/PageEndPoint.ts\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint.ts\";\nimport type RouteHandler from \"../types/RouteHandler.ts\";\nimport {\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport type ServerEndPoint from \"../types/ServerEndPoint.ts\";\nimport type ServerHook from \"../types/ServerHook.ts\";\nimport type ServerLoadEvent from \"../types/ServerLoadEvent.ts\";\n\n/**\n * Runs a site route in test mode\n * @param site The site configuration, with routing configured\n * @param route The route path e.g. `/home`\n * @param ev An optional ServerEvent, which you can use to set test cookies and headers\n * @returns An HTTP response containing the requested data, HTML, or error status\n */\nexport default async function runTest(\n\tsite: Site,\n\troute: string,\n\tev?: ServerEvent,\n): Promise<Response> {\n\tif (!route.startsWith(\"/\")) route += \"/\";\n\tif (!ev) {\n\t\tconst req = new Request(`http://localhost${route}`);\n\t\tev = new ServerEvent(req);\n\t}\n\n\t// Build the router from the Site object created by the user\n\tconst router = new Router();\n\trouter.addPages(\n\t\tsite.routes.map((r) => ({\n\t\t\tpath: r.path,\n\t\t\ttype: r.type,\n\t\t\tendPoint: () => import(/* @vite-ignore */ path.join(site.root, r.file)),\n\t\t\tsubFolder: r.subFolder,\n\t\t})),\n\t);\n\n\treturn await load(router, ev, \"%COMPONENT_BODY%\");\n}\n\n// HACK: This is a copy of serverEntry\n// TODO: Make it shared instead!\nasync function load(router: Router, ev: ServerEvent, template: string): Promise<Response> {\n\t//const url = new URL(`http://${process.env.HOST ?? \"localhost\"}${ev.request.url}`);\n\tconst url = new URL(ev.request.url);\n\tconst path = url.pathname;\n\tconst query = url.searchParams;\n\n\t//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\tconst route = router.match(path, query);\n\tif (!route) {\n\t\treturn notFound();\n\t}\n\n\t// Update $page before building the components\n\t// TODO: Find somewhere better to put this\n\t$page.url = url;\n\n\tconst handler = route.handler;\n\tconst params = route.params || {};\n\n\t// TODO: Hit the server hook out here\n\t// We could maybe set data loading up as middleware on a route??????\n\n\tswitch (handler.type) {\n\t\tcase PAGE_ROUTE:\n\t\tcase LAYOUT_ROUTE: {\n\t\t\t// It's a /+page.ts or /_layout.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadView(ev, url, handler, params, template);\n\t\t\t} else if (ev.request.method === \"POST\") {\n\t\t\t\treturn await runAction(ev, url, handler, params, query);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase PAGE_SERVER_ROUTE:\n\t\tcase LAYOUT_SERVER_ROUTE: {\n\t\t\t// It's a /+page.server.ts or /_layout.server.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadData(ev, url, handler, \"load\", params);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase SERVER_ROUTE: {\n\t\t\t// It's a /+server.ts endpoint\n\t\t\tconst functionName = ev.request.method.toLowerCase().replace(\"delete\", \"del\");\n\t\t\treturn await loadData(ev, url, handler, functionName, params);\n\t\t}\n\t\tcase HOOK_ROUTE:\n\t\tcase HOOK_SERVER_ROUTE: {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadData(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tfunctionName: string,\n\tparams: Record<string, string>,\n) {\n\tconst serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint()).default;\n\tif (serverEndPoint && serverEndPoint[functionName]) {\n\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\tif (handler.serverHook) {\n\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\tif (serverHook?.handle) {\n\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t}\n\t\t}\n\n\t\tconst result = await serverEndPoint[functionName](serverParams);\n\n\t\t// If there was no response returned from load (such as errors or a\n\t\t// redirect), send an ok response\n\t\treturn result || ok();\n\t}\n\n\treturn notFound();\n}\n\nasync function loadView(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\ttemplate: string,\n) {\n\t// There must be a client endpoint with a component\n\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\tif (!clientEndPoint?.component) {\n\t\treturn notFound();\n\t}\n\n\t// There may be a server endpoint\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t// Maybe hit the server hook\n\tconst serverParams = buildServerParams(ev, url, params);\n\tif (handler.serverHook) {\n\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\tif (serverHook?.handle) {\n\t\t\tawait serverHook.handle(serverParams);\n\t\t}\n\t}\n\n\t// Pass the data into $props\n\t// TODO: Promise.all\n\t// NOTE: We're loading data from top to bottom, overriding as we go, and I'm not sure if this is the best way to go\n\tlet data = {};\n\tif (handler.layouts) {\n\t\tfor (let layout of handler.layouts) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;\n\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\tconst layoutResponse = await loadClientAndServerData(\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tserverParams,\n\t\t\t\tdata,\n\t\t\t\tlayoutEndPoint,\n\t\t\t\tlayoutServerEndPoint,\n\t\t\t);\n\t\t\tif (layoutResponse?.ok === false) {\n\t\t\t\treturn layoutResponse;\n\t\t\t}\n\t\t}\n\t}\n\tlet endPointResponse = await loadClientAndServerData(\n\t\turl,\n\t\tparams,\n\t\tserverParams,\n\t\tdata,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tif (endPointResponse?.ok === false) {\n\t\treturn endPointResponse;\n\t}\n\tlet $props: Record<string, any> = { data };\n\n\tlet styles = \"\";\n\n\t// If there are layouts, work our way upwards, pushing each component into\n\t// the default slot of its parent\n\t// TODO: Also handle layout server data\n\t// TODO: There's probably a nicer way to do this with reducers or something\n\tlet component = clientEndPoint.component as ServerComponent;\n\tlet slots: Record<string, ServerSlotRender> | undefined = undefined;\n\tif (handler.layouts) {\n\t\tlet slotFunctions: ServerSlotRender[] = [];\n\t\tslotFunctions[handler.layouts.length] = (_, $context) => {\n\t\t\tlet { body, head } = (clientEndPoint.component as ServerComponent)($props, $context);\n\t\t\tstyles += head;\n\t\t\treturn body;\n\t\t};\n\t\tfor (let i = handler.layouts.length - 1; i >= 0; i--) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())\n\t\t\t\t?.default;\n\t\t\tif (layoutEndPoint?.component) {\n\t\t\t\tif (i === 0) {\n\t\t\t\t\tcomponent = layoutEndPoint.component as ServerComponent;\n\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t} else {\n\t\t\t\t\tslotFunctions[i] = (_, $context) => {\n\t\t\t\t\t\tlet { body, head } = (layoutEndPoint.component as ServerComponent)($props, $context, {\n\t\t\t\t\t\t\t_: slotFunctions[i + 1],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tstyles += head;\n\t\t\t\t\t\treturn body;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlet html;\n\ttry {\n\t\tlet { body, head } = component($props, undefined, slots);\n\t\tstyles += head;\n\t\thtml = template.replace(\"%COMPONENT_BODY%\", body).replace(\"%COMPONENT_HEAD\", styles);\n\t} catch (error) {\n\t\t// TODO: Show a proper Error component\n\t\thtml = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\tconsole.log(error);\n\t}\n\n\treturn new Response(html, {\n\t\tstatus: 200,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"text/html\",\n\t\t},\n\t});\n}\n\nasync function runAction(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\tquery: URLSearchParams,\n) {\n\tconst actionName = (Array.from(query.keys())[0] || \"default\").replace(/^\\//, \"\");\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint()).default;\n\tif (serverEndPoint?.actions) {\n\t\tconst action = serverEndPoint.actions[actionName];\n\t\tif (action) {\n\t\t\t// TODO: form.errors etc\n\t\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\t\tif (handler.serverHook) {\n\t\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\t\tif (serverHook?.handle) {\n\t\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = await action(serverParams); // <--\n\n\t\t\t// If there was no response returned from the action (such as errors\n\t\t\t// or a redirect), reload the page by redirecting\n\t\t\treturn result || seeOther(url.pathname);\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadClientAndServerData(\n\turl: URL,\n\tparams: Record<string, string>,\n\tserverParams: ServerLoadEvent,\n\tdata: Record<string, any>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n) {\n\tif (clientEndPoint?.load) {\n\t\tconst clientParams = buildClientParams(url, data, params);\n\t\tconst clientResponse = await clientEndPoint.load(clientParams);\n\t\tif (clientResponse) {\n\t\t\tif (clientResponse.ok) {\n\t\t\t\tif (clientResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await clientResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn clientResponse;\n\t\t\t}\n\t\t}\n\t}\n\tif (serverEndPoint?.load) {\n\t\tconst serverResponse = await serverEndPoint.load(serverParams);\n\t\tif (serverResponse) {\n\t\t\tif (serverResponse.ok) {\n\t\t\t\tif (serverResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await serverResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn serverResponse;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction buildClientParams(url: URL, params: Record<string, string>, data: Record<string, any>) {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tdata,\n\t};\n}\n\nfunction buildServerParams(\n\tev: ServerEvent,\n\turl: URL,\n\tparams: Record<string, string>,\n): ServerLoadEvent {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tappData: {},\n\t\trequest: ev.request,\n\t\tcookies: ev.cookies,\n\t\theaders: ev.headers,\n\t\tadapter: ev.adapter,\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"test.mjs","names":["path","serverEndPoint: ServerEndPoint | undefined","serverHook: ServerHook | undefined","clientEndPoint: PageEndPoint | undefined","serverEndPoint: PageServerEndPoint | undefined","layoutEndPoint: PageEndPoint | undefined","$props: Record<string, any>","slots: Record<string, ServerSlotRender> | undefined","slotFunctions: ServerSlotRender[]"],"sources":["../src/test/runTest.ts"],"sourcesContent":["import { type ServerComponent, type ServerSlotRender } from \"@torpor/view/ssr\";\nimport path from \"node:path\";\nimport notFound from \"../response/notFound.ts\";\nimport ok from \"../response/ok.ts\";\nimport seeOther from \"../response/seeOther.ts\";\nimport ServerEvent from \"../server/ServerEvent.ts\";\nimport Router from \"../site/Router.ts\";\nimport Site from \"../site/Site\";\nimport $page from \"../state/$page.ts\";\nimport type PageEndPoint from \"../types/PageEndPoint.ts\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint.ts\";\nimport type RouteHandler from \"../types/RouteHandler.ts\";\nimport {\n\tHOOK_ROUTE,\n\tHOOK_SERVER_ROUTE,\n\tLAYOUT_ROUTE,\n\tLAYOUT_SERVER_ROUTE,\n\tPAGE_ROUTE,\n\tPAGE_SERVER_ROUTE,\n\tSERVER_ROUTE,\n} from \"../types/RouteType\";\nimport type ServerEndPoint from \"../types/ServerEndPoint.ts\";\nimport type ServerHook from \"../types/ServerHook.ts\";\nimport type ServerLoadEvent from \"../types/ServerLoadEvent.ts\";\n\n/**\n * Runs a site route in test mode\n * @param site The site configuration, with routing configured\n * @param route The route path e.g. `/home`\n * @param ev An optional ServerEvent, which you can use to set test cookies and headers\n * @returns An HTTP response containing the requested data, HTML, or error status\n */\nexport default async function runTest(\n\tsite: Site,\n\troute: string,\n\tev?: ServerEvent,\n): Promise<Response> {\n\tif (!route.startsWith(\"/\")) route += \"/\";\n\tif (!ev) {\n\t\tconst req = new Request(`http://localhost${route}`);\n\t\tev = new ServerEvent(req);\n\t}\n\n\t// Build the router from the Site object created by the user\n\tconst router = new Router();\n\trouter.addPages(\n\t\tsite.routes.map((r) => ({\n\t\t\tpath: r.path,\n\t\t\ttype: r.type,\n\t\t\tendPoint: () => import(/* @vite-ignore */ path.join(site.root, r.file)),\n\t\t\tsubFolder: r.subFolder,\n\t\t})),\n\t);\n\n\treturn await load(router, ev, \"%COMPONENT_BODY%\");\n}\n\n// HACK: This is a copy of serverEntry\n// TODO: Make it shared instead!\nasync function load(router: Router, ev: ServerEvent, template: string): Promise<Response> {\n\t//const url = new URL(`http://${process.env.HOST ?? \"localhost\"}${ev.request.url}`);\n\tconst url = new URL(ev.request.url);\n\tconst path = url.pathname;\n\tconst query = url.searchParams;\n\n\t//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : \"\"}`);\n\n\tconst route = router.match(path, query);\n\tif (!route) {\n\t\treturn notFound();\n\t}\n\n\t// Update $page before building the components\n\t// TODO: Find somewhere better to put this\n\t$page.url = url;\n\n\tconst handler = route.handler;\n\tconst params = route.params || {};\n\n\t// TODO: Hit the server hook out here\n\t// We could maybe set data loading up as middleware on a route??????\n\n\tswitch (handler.type) {\n\t\tcase PAGE_ROUTE:\n\t\tcase LAYOUT_ROUTE: {\n\t\t\t// It's a /+page.ts or /_layout.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadView(ev, url, handler, params, template);\n\t\t\t} else if (ev.request.method === \"POST\") {\n\t\t\t\treturn await runAction(ev, url, handler, params, query);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase PAGE_SERVER_ROUTE:\n\t\tcase LAYOUT_SERVER_ROUTE: {\n\t\t\t// It's a /+page.server.ts or /_layout.server.ts endpoint\n\t\t\tif (ev.request.method === \"GET\") {\n\t\t\t\treturn await loadData(ev, url, handler, \"load\", params);\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\t\tcase SERVER_ROUTE: {\n\t\t\t// It's a /+server.ts endpoint\n\t\t\tconst functionName = ev.request.method.toLowerCase().replace(\"delete\", \"del\");\n\t\t\treturn await loadData(ev, url, handler, functionName, params);\n\t\t}\n\t\tcase HOOK_ROUTE:\n\t\tcase HOOK_SERVER_ROUTE: {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadData(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tfunctionName: string,\n\tparams: Record<string, string>,\n) {\n\tconst serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint()).default;\n\tif (serverEndPoint && serverEndPoint[functionName]) {\n\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\tif (handler.serverHook) {\n\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\tif (serverHook?.handle) {\n\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t}\n\t\t}\n\n\t\tconst result = await serverEndPoint[functionName](serverParams);\n\n\t\t// If there was no response returned from load (such as errors or a\n\t\t// redirect), send an ok response\n\t\treturn result || ok();\n\t}\n\n\treturn notFound();\n}\n\nasync function loadView(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\ttemplate: string,\n) {\n\t// There must be a client endpoint with a component\n\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\tif (!clientEndPoint?.component) {\n\t\treturn notFound();\n\t}\n\n\t// There may be a server endpoint\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t// Maybe hit the server hook\n\tconst serverParams = buildServerParams(ev, url, params);\n\tif (handler.serverHook) {\n\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\tif (serverHook?.handle) {\n\t\t\tawait serverHook.handle(serverParams);\n\t\t}\n\t}\n\n\t// Pass the data into $props\n\t// TODO: Promise.all\n\t// NOTE: We're loading data from top to bottom, overriding as we go, and I'm not sure if this is the best way to go\n\tlet data = {};\n\tif (handler.layouts) {\n\t\tfor (let layout of handler.layouts) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;\n\t\t\tconst layoutServerEndPoint: PageServerEndPoint | undefined =\n\t\t\t\tlayout.serverEndPoint && (await layout.serverEndPoint())?.default;\n\t\t\tconst layoutResponse = await loadClientAndServerData(\n\t\t\t\turl,\n\t\t\t\tparams,\n\t\t\t\tserverParams,\n\t\t\t\tdata,\n\t\t\t\tlayoutEndPoint,\n\t\t\t\tlayoutServerEndPoint,\n\t\t\t);\n\t\t\tif (layoutResponse?.ok === false) {\n\t\t\t\treturn layoutResponse;\n\t\t\t}\n\t\t}\n\t}\n\tlet endPointResponse = await loadClientAndServerData(\n\t\turl,\n\t\tparams,\n\t\tserverParams,\n\t\tdata,\n\t\tclientEndPoint,\n\t\tserverEndPoint,\n\t);\n\tif (endPointResponse?.ok === false) {\n\t\treturn endPointResponse;\n\t}\n\tlet $props: Record<string, any> = { data };\n\n\tlet styles = \"\";\n\n\t// If there are layouts, work our way upwards, pushing each component into\n\t// the default slot of its parent\n\t// TODO: Also handle layout server data\n\t// TODO: There's probably a nicer way to do this with reducers or something\n\tlet component = clientEndPoint.component as ServerComponent;\n\tlet slots: Record<string, ServerSlotRender> | undefined = undefined;\n\tif (handler.layouts) {\n\t\tlet slotFunctions: ServerSlotRender[] = [];\n\t\tslotFunctions[handler.layouts.length] = (_, $context) => {\n\t\t\tlet { body, head } = (clientEndPoint.component as ServerComponent)($props, $context);\n\t\t\tstyles += head;\n\t\t\treturn body;\n\t\t};\n\t\tfor (let i = handler.layouts.length - 1; i >= 0; i--) {\n\t\t\tconst layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())\n\t\t\t\t?.default;\n\t\t\tif (layoutEndPoint?.component) {\n\t\t\t\tif (i === 0) {\n\t\t\t\t\tcomponent = layoutEndPoint.component as ServerComponent;\n\t\t\t\t\tslots = { _: slotFunctions[i + 1] };\n\t\t\t\t} else {\n\t\t\t\t\tslotFunctions[i] = (_, $context) => {\n\t\t\t\t\t\tlet { body, head } = (layoutEndPoint.component as ServerComponent)($props, $context, {\n\t\t\t\t\t\t\t_: slotFunctions[i + 1],\n\t\t\t\t\t\t});\n\t\t\t\t\t\tstyles += head;\n\t\t\t\t\t\treturn body;\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tlet html;\n\ttry {\n\t\tlet { body, head } = component($props, undefined, slots);\n\t\tstyles += head;\n\t\thtml = template.replace(\"%COMPONENT_BODY%\", body).replace(\"%COMPONENT_HEAD\", styles);\n\t} catch (error) {\n\t\t// TODO: Show a proper Error component\n\t\thtml = '<span style=\"color: red\">Script syntax error</span><p>' + error + \"</p>\";\n\t\tconsole.log(error);\n\t}\n\n\treturn new Response(html, {\n\t\tstatus: 200,\n\t\theaders: {\n\t\t\t\"Content-Type\": \"text/html\",\n\t\t},\n\t});\n}\n\nasync function runAction(\n\tev: ServerEvent,\n\turl: URL,\n\thandler: RouteHandler,\n\tparams: Record<string, string>,\n\tquery: URLSearchParams,\n) {\n\tconst actionName = (Array.from(query.keys())[0] || \"default\").replace(/^\\//, \"\");\n\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\thandler.serverEndPoint && (await handler.serverEndPoint()).default;\n\tif (serverEndPoint?.actions) {\n\t\tconst action = serverEndPoint.actions[actionName];\n\t\tif (action) {\n\t\t\t// TODO: form.errors etc\n\t\t\tconst serverParams = buildServerParams(ev, url, params);\n\n\t\t\tif (handler.serverHook) {\n\t\t\t\tconst serverHook: ServerHook | undefined = (await handler.serverHook()).default;\n\t\t\t\tif (serverHook?.handle) {\n\t\t\t\t\tawait serverHook.handle(serverParams);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst result = await action(serverParams); // <--\n\n\t\t\t// If there was no response returned from the action (such as errors\n\t\t\t// or a redirect), reload the page by redirecting\n\t\t\treturn result || seeOther(url.pathname);\n\t\t}\n\t}\n\n\treturn notFound();\n}\n\nasync function loadClientAndServerData(\n\turl: URL,\n\tparams: Record<string, string>,\n\tserverParams: ServerLoadEvent,\n\tdata: Record<string, any>,\n\tclientEndPoint?: PageEndPoint,\n\tserverEndPoint?: PageServerEndPoint,\n) {\n\tif (clientEndPoint?.load) {\n\t\tconst clientParams = buildClientParams(url, data, params);\n\t\tconst clientResponse = await clientEndPoint.load(clientParams);\n\t\tif (clientResponse) {\n\t\t\tif (clientResponse.ok) {\n\t\t\t\tif (clientResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await clientResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn clientResponse;\n\t\t\t}\n\t\t}\n\t}\n\tif (serverEndPoint?.load) {\n\t\tconst serverResponse = await serverEndPoint.load(serverParams);\n\t\tif (serverResponse) {\n\t\t\tif (serverResponse.ok) {\n\t\t\t\tif (serverResponse.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n\t\t\t\t\tObject.assign(data, await serverResponse.json());\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn serverResponse;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction buildClientParams(url: URL, params: Record<string, string>, data: Record<string, any>) {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tdata,\n\t};\n}\n\nfunction buildServerParams(\n\tev: ServerEvent,\n\turl: URL,\n\tparams: Record<string, string>,\n): ServerLoadEvent {\n\treturn {\n\t\turl,\n\t\tparams,\n\t\tappData: {},\n\t\trequest: ev.request,\n\t\tcookies: ev.cookies,\n\t\theaders: ev.headers,\n\t\tadapter: ev.adapter,\n\t};\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/site/serverEntry.ts
CHANGED
|
@@ -36,7 +36,17 @@ export async function load(ev: ServerEvent, template: string): Promise<Response>
|
|
|
36
36
|
|
|
37
37
|
//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : ""}`);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
let route = router.match(path, query);
|
|
40
|
+
if (!route) {
|
|
41
|
+
// If the route wasn't found, the user may be posting a form to a
|
|
42
|
+
// +page.server.ts route that doesn't have a corresponding +page.ts
|
|
43
|
+
// route, which is allowed, so check for that as well
|
|
44
|
+
if (ev.request.method === "POST" && !path.endsWith("/~server")) {
|
|
45
|
+
const serverPath =
|
|
46
|
+
(path.endsWith("/") ? path.substring(0, path.length - 1) : path) + "/~server";
|
|
47
|
+
route = router.match(serverPath, query);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
40
50
|
if (!route) {
|
|
41
51
|
return handleResponse(notFound());
|
|
42
52
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"run-DiZgkMnG.mjs","names":["endPoint: string","fs","createViteServer","fs","e: any","types: Record<string, string>","fs","e: any"],"sources":["../src/site/manifest.ts","../src/run/runBuild.ts","../src/run/prepareTemplate.ts","../src/run/runDev.ts","../src/server/contentType.ts","../src/run/runPreview.ts","../src/run/run.ts"],"sourcesContent":["import { readFileSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { Plugin } from \"vite\";\nimport Site from \"./Site\";\n\nconst moduleId = \"@torpor/build/manifest\";\n\n/**\n * A Vite plugin that provides information about the app to both clientEntry and\n * serverEntry.\n */\nexport default function manifest(site: Site, server = false): Plugin {\n\treturn {\n\t\tname: \"torpor-manifest\",\n\t\tresolveId: {\n\t\t\torder: \"pre\",\n\t\t\thandler(id) {\n\t\t\t\tif (id === moduleId) {\n\t\t\t\t\treturn id;\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t\t// @ts-ignore\n\t\tload(id, viteOptions) {\n\t\t\tif (id === moduleId) {\n\t\t\t\tlet serverRequest = server && !!viteOptions?.ssr;\n\t\t\t\treturn `\n${!serverRequest ? \"const load = { default: { load: true } };\" : \"\"}\nexport default {\n routes: [\n ${site.routes\n\t\t\t.map((r) => {\n\t\t\t\tlet endPoint: string;\n\t\t\t\tif (serverRequest || !/server\\.(ts|js)$/.test(r.file)) {\n\t\t\t\t\tendPoint = `() => import(/* @vite-ignore */ \"${path.join(site.root, r.file)}\")`;\n\t\t\t\t} else {\n\t\t\t\t\t// On the client, for a server route, we need to check\n\t\t\t\t\t// whether there's a load function and set a dummy endPoint\n\t\t\t\t\t// if so. The correct endpoint will be hit in clientEntry\n\t\t\t\t\t// HACK: Should do this better than checking for `load:` in source...\n\t\t\t\t\tconst haveLoad = readFileSync(path.join(site.root, r.file)).includes(\"load:\");\n\t\t\t\t\tendPoint = haveLoad ? \"() => load\" : \"undefined\";\n\t\t\t\t}\n\t\t\t\tconst sub = r.subFolder ? `\"${r.subFolder}\"` : \"undefined\";\n\t\t\t\treturn `{ path: \"${r.path}\", type: ${r.type}, endPoint: ${endPoint}, subFolder: ${sub} }`;\n\t\t\t})\n\t\t\t.join(\",\\n \")}\n ],\n};\n`;\n\t\t\t}\n\t\t},\n\t};\n}\n","import torpor from \"@torpor/unplugin/vite\";\nimport { existsSync, promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { build, defineConfig } from \"vite\";\nimport Site from \"../site/Site\";\nimport manifest from \"../site/manifest.ts\";\n\n// TODO: Don't cache index.html in dev?\n// TODO: Multiple hook.server locations\n// TODO: Don't reload layouts during client routing\n// TODO: Call the correct +page and +server routes when in the same folder\n\nexport default async function runBuild(site: Site): Promise<void> {\n\t// Delete the dist folder if it exists\n\tconst distFolder = path.resolve(site.root, \"dist\");\n\tif (existsSync(distFolder)) {\n\t\tawait fs.rm(distFolder, { recursive: true });\n\t}\n\tconst clientFolder = path.join(distFolder, \"client\");\n\tconst serverFolder = path.join(distFolder, \"server\");\n\n\t// HOOK: Prebuild\n\tif (site.adapter.prebuild) {\n\t\tawait site.adapter.prebuild(site);\n\t}\n\n\t// TODO: From a setting\n\tlet siteHtml = path.resolve(site.root, \"src/site.html\");\n\n\tconst siteFolder = path.resolve(site.root, \"./node_modules/@torpor/build/src/site/\");\n\tlet clientScript = path.join(siteFolder, \"clientEntry.ts\");\n\tlet serverScript = path.join(siteFolder, \"serverEntry.ts\");\n\n\t// Build the client assets, including site.html and the route files\n\t// EXCLUDING anything with `server.js` in the name\n\tconst clientConfig = structuredClone(site.viteConfig ?? {});\n\tclientConfig.plugins = [manifest(site), torpor(), ...site.plugins];\n\tclientConfig.build ??= {};\n\tclientConfig.build.outDir = clientFolder;\n\tclientConfig.build.rollupOptions ??= {};\n\tclientConfig.build.rollupOptions.input = [\n\t\tsiteHtml,\n\t\tclientScript,\n\t\t...site.routes\n\t\t\t.filter((r) => !/server\\.(ts|js)$/.test(r.file))\n\t\t\t.map((r) => path.resolve(site.root, r.file)),\n\t\t...site.inputs.filter((f) => !/server\\.(ts|js)$/.test(f)),\n\t];\n\tclientConfig.build.ssrManifest = true;\n\tawait build(defineConfig(clientConfig));\n\n\t// Build the server assets, including the server entry script and the route\n\t// files\n\tconst serverConfig = structuredClone(site.viteConfig ?? {});\n\tserverConfig.plugins = [manifest(site, true), torpor(), ...site.plugins];\n\tserverConfig.build ??= {};\n\tserverConfig.build.outDir = serverFolder;\n\tserverConfig.build.rollupOptions ??= {};\n\tserverConfig.build.rollupOptions.input = [\n\t\tserverScript,\n\t\t...site.routes.map((r) => path.resolve(site.root, r.file)),\n\t\t...site.inputs,\n\t];\n\tserverConfig.build.ssr = serverScript;\n\tawait build(defineConfig(serverConfig));\n\n\t// Move the site.html file into /client\n\t// HACK: Should do this in Rollup if possible?\n\tsiteHtml = path.join(clientFolder, \"site.html\");\n\tawait fs.rename(path.join(clientFolder, \"src\", \"site.html\"), siteHtml);\n\tawait fs.rm(path.join(clientFolder, \"src\"), { recursive: true });\n\n\t// HOOK: Postbuild\n\tif (site.adapter.postbuild) {\n\t\tawait site.adapter.postbuild(site);\n\t}\n}\n","export default function prepareTemplate(\n\ttemplate: string,\n\tclientScript: string,\n\tclientDevScript?: string,\n): string {\n\tlet result = template;\n\n\t// Put %COMPONENT_HEAD% before </head>\n\t// This is where styles will go\n\tlet headStart = result.indexOf(\"</head>\");\n\tif (headStart === -1) {\n\t\tthrow new Error(`Couldn't find <head> end tag`);\n\t}\n\tresult = result.substring(0, headStart) + \"%COMPONENT_HEAD%\" + result.substring(headStart);\n\n\t// Put %COMPONENT_BODY% inside <div id=\"app\"></div>\n\t// This is where the component's HTML will go\n\tlet bodyStart = regexIndexOf(result, /<div\\s+id=(\"app\"|'app'|app)\\s+/);\n\tbodyStart = result.indexOf(\">\", bodyStart) + 1;\n\tlet bodyEnd = result.indexOf(\"</div>\", bodyStart);\n\tif (bodyStart === -1 || bodyEnd === -1) {\n\t\tthrow new Error(`Couldn't find <div id=\"app\"></div>`);\n\t}\n\tresult = result.substring(0, bodyStart) + \"%COMPONENT_BODY%\" + result.substring(bodyEnd);\n\n\t// Add the clientEntry script at the very end, for hydrating and navigating\n\tif (clientDevScript) {\n\t\tresult += `<script type=\"module\" src=\"${clientDevScript}\"></script>`;\n\t}\n\tresult += `<script type=\"module\" src=\"${clientScript}\"></script>`;\n\n\treturn result;\n}\n\n// From https://stackoverflow.com/a/274094\nfunction regexIndexOf(string: string, regex: RegExp, position?: number) {\n\tvar indexOf = string.substring(position || 0).search(regex);\n\treturn indexOf >= 0 ? indexOf + (position || 0) : indexOf;\n}\n","import estorpor from \"@torpor/unplugin/esbuild\";\nimport torpor from \"@torpor/unplugin/vite\";\nimport { configDotenv } from \"dotenv\";\nimport { promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { createServer as createViteServer } from \"vite\";\nimport { serverError } from \"../response.ts\";\nimport Server from \"../server/Server.ts\";\nimport connectMiddleware from \"../server/connect/connectMiddleware.ts\";\nimport Site from \"../site/Site.ts\";\nimport manifest from \"../site/manifest.ts\";\nimport prepareTemplate from \"./prepareTemplate.ts\";\n\nexport default async function runDev(site: Site): Promise<void> {\n\tconst server = new Server();\n\n\t// Create the Vite server in middleware mode and configure the app type as\n\t// \"custom\", disabling Vite's own HTML serving logic so the parent server\n\t// can take control\n\tconst config = structuredClone(site.viteConfig ?? {});\n\tconfig.server = { middlewareMode: true };\n\tconfig.appType = \"custom\";\n\tconfig.plugins = [manifest(site, true), torpor({ dev: true }), ...site.plugins];\n\n\t// HACK: To be able to import `.torp` files from barrel files in\n\t// node_modules, we need to add their libraries to `ssr.noExternal` in\n\t// site.config.ts, and let esbuild know how to compile them here\n\tconfig.optimizeDeps ??= {};\n\tconfig.optimizeDeps.extensions ??= [];\n\tconfig.optimizeDeps.extensions.push(\".torp\");\n\tconfig.optimizeDeps.esbuildOptions ??= {};\n\tconfig.optimizeDeps.esbuildOptions.plugins ??= [];\n\tconfig.optimizeDeps.esbuildOptions.plugins.push(estorpor());\n\n\tconst vite = await createViteServer(config);\n\n\t// Read site.html\n\t// It's called site.html because @torpor/build builds the site (html, routes\n\t// etc) while the user builds the app (components etc)\n\tconst templateFile = path.resolve(site.root, \"src/site.html\");\n\tlet template = await fs.readFile(templateFile, \"utf-8\");\n\n\t// Apply Vite HTML transforms. This injects the Vite HMR client, and also\n\t// applies HTML transforms from Vite plugins. Note that we only support a\n\t// universal transform, not individual transforms for each route\n\ttemplate = await vite.transformIndexHtml(\"\", template);\n\n\tconst siteFolder = path.resolve(site.root, \"./node_modules/@torpor/build/src/site/\");\n\tlet clientScript = path.join(siteFolder, \"clientEntry.ts\");\n\tlet clientDevScript = path.join(siteFolder, \"clientEntryDev.ts\");\n\tlet serverScript = path.join(siteFolder, \"serverEntry.ts\");\n\n\t// Prepare site.html so that we can just splice components into it\n\ttemplate = prepareTemplate(template, clientScript, clientDevScript);\n\n\t// Use Vite's Connect instance as middleware. We need to wrap it with\n\t// createMiddlewareHandler that converts Connect middleware to\n\t// Request/Response web handlers\n\tserver.use(connectMiddleware(vite.middlewares));\n\n\t// Every request (GET, POST, etc) goes through loadEndPoint\n\tserver.add(\"*\", async (ev) => {\n\t\ttry {\n\t\t\t// Load the server entry. ssrLoadModule automatically transforms ESM\n\t\t\t// source code to be usable in Node.js. No bundling is required, and\n\t\t\t// it provides efficient invalidation similar to HMR\n\t\t\tconst { load } = await vite.ssrLoadModule(serverScript);\n\n\t\t\t// Render the app HTML (or fetch server data etc) via serverEntry's\n\t\t\t// exported `load` function\n\t\t\treturn await load(ev, template);\n\t\t} catch (e: any) {\n\t\t\t// If an error is caught, let Vite fix the stack trace so it maps\n\t\t\t// back to your actual source code\n\t\t\tvite.ssrFixStacktrace(e);\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Load environment variables from a `.env` file, with defaults if not set\n\tconfigDotenv();\n\n\tprocess.env.PROTOCOL ??= \"http:\";\n\tprocess.env.HOST ??= \"localhost\";\n\tprocess.env.PORT ??= \"7059\";\n\n\t// Serve the site\n\tsite.adapter.serve(server, site);\n}\n","// From https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types\n\nexport default function contentType(extension: string): string {\n\treturn types[extension] || \"application/octet-stream\";\n}\n\nconst types: Record<string, string> = {\n\t\".aac\": \"audio/aac\",\n\t\".abw\": \"application/x-abiword\",\n\t\".apng\": \"image/apng\",\n\t\".arc\": \"application/x-freearc\",\n\t\".avif\": \"image/avif\",\n\t\".avi\": \"video/x-msvideo\",\n\t\".azw\": \"application/vnd.amazon.ebook\",\n\t\".bin\": \"application/octet-stream\",\n\t\".bmp\": \"image/bmp\",\n\t\".bz\": \"application/x-bzip\",\n\t\".bz2\": \"application/x-bzip2\",\n\t\".cda\": \"application/x-cdf\",\n\t\".csh\": \"application/x-csh\",\n\t\".css\": \"text/css\",\n\t\".csv\": \"text/csv\",\n\t\".doc\": \"application/msword\",\n\t\".docx\": \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n\t\".eot\": \"application/vnd.ms-fontobject\",\n\t\".epub\": \"application/epub+zip\",\n\t\".gz\": \"application/gzip\",\n\t\".gif\": \"image/gif\",\n\t\".htm\": \"text/html\",\n\t\".html\": \"text/html\",\n\t\".ico\": \"image/vnd.microsoft.icon\",\n\t\".ics\": \"text/calendar\",\n\t\".jar\": \"application/java-archive\",\n\t\".jpeg\": \"image/jpeg\",\n\t\".jpg\": \"image/jpeg\",\n\t\".js\": \"text/javascript\",\n\t\".json\": \"application/json\",\n\t\".jsonld\": \"application/ld+json\",\n\t\".mid\": \"audio/midi\",\n\t\".midi\": \"audio/midi\",\n\t\".mjs\": \"text/javascript\",\n\t\".mp3\": \"audio/mpeg\",\n\t\".mp4\": \"video/mp4\",\n\t\".mpeg\": \"video/mpeg\",\n\t\".mpkg\": \"application/vnd.apple.installer+xml\",\n\t\".odp\": \"application/vnd.oasis.opendocument.presentation\",\n\t\".ods\": \"application/vnd.oasis.opendocument.spreadsheet\",\n\t\".odt\": \"application/vnd.oasis.opendocument.text\",\n\t\".oga\": \"audio/ogg\",\n\t\".ogv\": \"video/ogg\",\n\t\".ogx\": \"application/ogg\",\n\t\".opus\": \"audio/ogg\",\n\t\".otf\": \"font/otf\",\n\t\".png\": \"image/png\",\n\t\".pdf\": \"application/pdf\",\n\t\".php\": \"application/x-httpd-php\",\n\t\".ppt\": \"application/vnd.ms-powerpoint\",\n\t\".pptx\": \"application/vnd.openxmlformats-officedocument.presentationml.presentation\",\n\t\".rar\": \"application/vnd.rar\",\n\t\".rtf\": \"application/rtf\",\n\t\".sh\": \"application/x-sh\",\n\t\".svg\": \"image/svg+xml\",\n\t\".tar\": \"application/x-tar\",\n\t\".tif\": \"image/tiff\",\n\t\".tiff\": \"image/tiff\",\n\t\".ts\": \"video/mp2t\",\n\t\".ttf\": \"font/ttf\",\n\t\".txt\": \"text/plain\",\n\t\".vsd\": \"application/vnd.visio\",\n\t\".wav\": \"audio/wav\",\n\t\".weba\": \"audio/webm\",\n\t\".webm\": \"video/webm\",\n\t\".webp\": \"image/webp\",\n\t\".woff\": \"font/woff\",\n\t\".woff2\": \"font/woff2\",\n\t\".xhtml\": \"application/xhtml+xml\",\n\t\".xls\": \"application/vnd.ms-excel\",\n\t\".xlsx\": \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n\t\".xml\": \"application/xml\",\n\t\".xul\": \"application/vnd.mozilla.xul+xml\",\n\t\".zip\": \"application/zip\",\n\t\".3gp\": \"video/3gpp\",\n\t\".3g2\": \"video/3gpp2\",\n\t\".7z\": \"application/x-7z-compressed\",\n};\n","import { configDotenv } from \"dotenv\";\nimport { existsSync, promises as fs } from \"node:fs\";\nimport path from \"node:path\";\nimport { serverError } from \"../response.ts\";\nimport Server from \"../server/Server.ts\";\nimport contentType from \"../server/contentType.ts\";\nimport Site from \"../site/Site\";\nimport prepareTemplate from \"./prepareTemplate.ts\";\nimport runBuild from \"./runBuild\";\n\nexport default async function runPreview(site: Site): Promise<void> {\n\t// Build the site\n\tawait runBuild(site);\n\n\tconst distFolder = path.resolve(site.root, \"dist\");\n\tconst clientFolder = path.join(distFolder, \"client\");\n\tconst serverFolder = path.join(distFolder, \"server\");\n\n\t// Find the client script file in /assets\n\tlet clientScript = (await fs.readdir(path.join(clientFolder, \"assets\"))).find((f) =>\n\t\tf.startsWith(\"clientEntry-\"),\n\t);\n\tif (!clientScript) {\n\t\tthrow new Error(\"clientEntry.js not found\");\n\t}\n\tclientScript = `/assets/${clientScript}`;\n\n\t// Read site.html\n\t// It's called site.html because @torpor/build builds the site (html, routes\n\t// etc) while the user builds the app (components etc)\n\tlet siteHtml = path.join(clientFolder, \"site.html\");\n\tlet template = await fs.readFile(siteHtml, \"utf-8\");\n\n\t// Prepare site.html so that we can just splice components into it\n\ttemplate = prepareTemplate(template, clientScript);\n\n\t// Configure the server\n\tconst server = new Server();\n\n\t// Serve dist/client/assets statically\n\tserver.add(\"/assets/*\", async (ev) => {\n\t\ttry {\n\t\t\tconst url = new URL(ev.request.url);\n\t\t\tconst file = path.join(site.root, \"dist\", \"client\", url.pathname);\n\t\t\tif (existsSync(file)) {\n\t\t\t\t// TODO: Stream the data?\n\t\t\t\tconst body = bufferToArrayBuffer(await fs.readFile(file));\n\t\t\t\treturn new Response(body, {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\theaders: {\n\t\t\t\t\t\t\"Content-Type\": contentType(path.extname(file)),\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (e: any) {\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Every request (GET, POST, etc) goes through loadEndPoint\n\tconst serverScript = path.resolve(serverFolder, \"serverEntry.js\");\n\tserver.add(\"*\", async (ev) => {\n\t\ttry {\n\t\t\t// Load the server entry\n\t\t\tconst { load } = await import(serverScript);\n\n\t\t\t// Render the app HTML (or fetch server data etc) via serverEntry's\n\t\t\t// exported `load` function\n\t\t\treturn await load(ev, template);\n\t\t} catch (e: any) {\n\t\t\treturn serverError(e);\n\t\t}\n\t});\n\n\t// Load environment variables from a `.env` file, with defaults if not set\n\tconfigDotenv();\n\n\tprocess.env.PROTOCOL ??= \"http:\";\n\tprocess.env.HOST ??= \"localhost\";\n\tprocess.env.PORT ??= \"7059\";\n\n\t// Serve the site\n\tsite.adapter.serve(server, site);\n}\n\n// From https://stackoverflow.com/a/79345620\n// No idea why it is needed\nfunction bufferToArrayBuffer(buffer: Buffer): ArrayBuffer {\n\treturn buffer.buffer.slice(\n\t\tbuffer.byteOffset,\n\t\tbuffer.byteOffset + buffer.byteLength,\n\t) as ArrayBuffer;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { transformWithEsbuild } from \"vite\";\nimport Site from \"../site/Site\";\nimport runBuild from \"./runBuild\";\nimport runDev from \"./runDev\";\nimport runPreview from \"./runPreview\";\n\nexport default async function run(\n\tfolder: string,\n\tmode: \"dev\" | \"build\" | \"preview\",\n): Promise<void> {\n\t// Look for and load a site.config.js/ts file in the working directory\n\tlet configFile = \"\";\n\tlet deleteConfigFile = false;\n\tconst jsConfigFile = path.join(folder, \"site.config.js\");\n\tconst tsConfigFile = path.join(folder, \"site.config.ts\");\n\tif (fs.existsSync(jsConfigFile)) {\n\t\t// If it's JS, we can just import it straight up\n\t\tconfigFile = jsConfigFile;\n\t} else if (fs.existsSync(tsConfigFile)) {\n\t\t// If it's TS, we need to convert it to JS\n\t\t// TODO: Put the generated file somewhere better (dist?)\n\t\tconfigFile = path.join(folder, \"site.config.temp.js\");\n\t\tlet source = fs.readFileSync(tsConfigFile, \"utf-8\");\n\t\tlet transformed = await transformWithEsbuild(source, tsConfigFile, {\n\t\t\tloader: \"ts\",\n\t\t});\n\t\tfs.writeFileSync(configFile, transformed.code);\n\t\tdeleteConfigFile = true;\n\t} else {\n\t\tthrow new Error(\"site.config file not found\");\n\t}\n\n\tconst site = (await import(configFile)).default as Site;\n\tif (!site || !site.root || !site.routes) {\n\t\tthrow new Error(\"Invalid site in config file\");\n\t}\n\tif (deleteConfigFile) {\n\t\tfs.rmSync(configFile);\n\t}\n\n\tswitch (mode) {\n\t\tcase \"dev\": {\n\t\t\tawait runDev(site);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"build\": {\n\t\t\tawait runBuild(site);\n\t\t\tbreak;\n\t\t}\n\t\tcase \"preview\": {\n\t\t\tawait runPreview(site);\n\t\t\tbreak;\n\t\t}\n\t\tdefault: {\n\t\t\tconsole.log(\"No mode passed, running in dev\");\n\t\t\tawait runDev(site);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|