@torpor/build 1.0.0 → 1.0.1
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/{flattenHeaders-C_YYLdOq.mjs → Server-BnjLJleZ.mjs} +2 -12
- package/dist/Server-BnjLJleZ.mjs.map +1 -0
- package/dist/{Server-C_IKav_e.d.mts → Server-Cler2w5O.d.mts} +3 -48
- package/dist/Server-Cler2w5O.d.mts.map +1 -0
- package/dist/ServerEvent-CTx3Q-hk.d.mts +48 -0
- package/dist/ServerEvent-CTx3Q-hk.d.mts.map +1 -0
- package/dist/{Site-CMa153FA.d.mts → Site-CE0_o5Ci.d.mts} +3 -2
- package/dist/Site-CE0_o5Ci.d.mts.map +1 -0
- package/dist/bin/index.js +1 -1
- package/dist/clientEntry.d.mts +1 -0
- package/dist/clientEntry.mjs +59 -0
- package/dist/clientEntry.mjs.map +1 -0
- package/dist/clientEntryDev.d.mts +1 -0
- package/dist/clientEntryDev.mjs +7 -0
- package/dist/clientEntryDev.mjs.map +1 -0
- package/dist/dev.d.mts +3 -0
- package/dist/dev.mjs +3 -0
- package/dist/endpoint-EULRGCKA.mjs +108 -0
- package/dist/endpoint-EULRGCKA.mjs.map +1 -0
- package/dist/flattenHeaders-DM5qsSqO.mjs +13 -0
- package/dist/flattenHeaders-DM5qsSqO.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/load-BntzvmwL.mjs +228 -0
- package/dist/load-BntzvmwL.mjs.map +1 -0
- package/dist/nav.mjs +1 -225
- package/dist/nav.mjs.map +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/run.d.mts +1 -1
- package/dist/run.d.mts.map +1 -1
- package/dist/run.mjs +1 -1
- package/dist/{runOpenApi-BUi1RH1l.mjs → runOpenApi-DlOgF2Il.mjs} +54 -16
- package/dist/runOpenApi-DlOgF2Il.mjs.map +1 -0
- package/dist/server/Server.d.mts +2 -0
- package/dist/server/Server.mjs +2 -0
- package/dist/server.d.mts +2 -1
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +2 -1
- package/dist/server.mjs.map +1 -1
- package/dist/serverEntry-1qY3wZig.mjs +351 -0
- package/dist/serverEntry-1qY3wZig.mjs.map +1 -0
- package/dist/serverEntry-BAO8m03V.d.mts +6 -0
- package/dist/serverEntry-BAO8m03V.d.mts.map +1 -0
- package/dist/serverEntry.d.mts +2 -0
- package/dist/serverEntry.mjs +2 -0
- package/dist/test.d.mts +2 -2
- package/dist/test.mjs +2 -104
- package/dist/test.mjs.map +1 -1
- package/package.json +9 -8
- package/dist/Server-C_IKav_e.d.mts.map +0 -1
- package/dist/Site-CMa153FA.d.mts.map +0 -1
- package/dist/flattenHeaders-C_YYLdOq.mjs.map +0 -1
- package/dist/runOpenApi-BUi1RH1l.mjs.map +0 -1
- package/src/bin/index.ts +0 -22
- package/src/dev.ts +0 -10
- package/src/form/formDataToRecord.ts +0 -23
- package/src/form/readForm.ts +0 -71
- package/src/form.ts +0 -4
- package/src/index.ts +0 -82
- package/src/nav/api.test-d.ts +0 -79
- package/src/nav/api.ts +0 -104
- package/src/nav/formSubmit.ts +0 -70
- package/src/nav/load.ts +0 -9
- package/src/nav/loadData.ts +0 -134
- package/src/nav/navigate.ts +0 -189
- package/src/nav/reload.ts +0 -9
- package/src/nav/route.ts +0 -38
- package/src/nav.ts +0 -6
- package/src/openapi/docsHtml.ts +0 -25
- package/src/openapi/document.ts +0 -154
- package/src/openapi/plugin.ts +0 -78
- package/src/openapi/types.ts +0 -82
- package/src/openapi.ts +0 -14
- package/src/response/TypedResponse.ts +0 -17
- package/src/response/badRequest.ts +0 -31
- package/src/response/created.ts +0 -31
- package/src/response/forbidden.ts +0 -21
- package/src/response/found.ts +0 -30
- package/src/response/methodNotAllowed.ts +0 -18
- package/src/response/movedPermanently.ts +0 -25
- package/src/response/notFound.ts +0 -24
- package/src/response/notModified.ts +0 -34
- package/src/response/ok.ts +0 -38
- package/src/response/permanentRedirect.ts +0 -30
- package/src/response/response.ts +0 -22
- package/src/response/seeOther.ts +0 -19
- package/src/response/serverError.ts +0 -24
- package/src/response/temporaryRedirect.ts +0 -31
- package/src/response/transfer.ts +0 -14
- package/src/response/unauthorized.ts +0 -21
- package/src/response/unprocessable.ts +0 -30
- package/src/response.ts +0 -37
- package/src/run/depCache.ts +0 -175
- package/src/run/devPlugin.ts +0 -128
- package/src/run/prepareTemplate.ts +0 -42
- package/src/run/run.ts +0 -86
- package/src/run/runBuild.ts +0 -128
- package/src/run/runDev.ts +0 -177
- package/src/run/runOpenApi.ts +0 -52
- package/src/run/runPreview.ts +0 -84
- package/src/run/staleTorpCopies.ts +0 -100
- package/src/run.ts +0 -7
- package/src/schema.ts +0 -7
- package/src/server/CookieHelper.ts +0 -46
- package/src/server/HeaderHelper.ts +0 -25
- package/src/server/Server.ts +0 -168
- package/src/server/ServerEvent.ts +0 -62
- package/src/server/connect/connectMiddleware.ts +0 -85
- package/src/server/connect/flattenHeaders.ts +0 -22
- package/src/server/connect/nodeMessageToNodeResponse.ts +0 -89
- package/src/server/connect/requestToNodeMessage.ts +0 -29
- package/src/server/contentType.ts +0 -85
- package/src/server/types/HttpMethod.ts +0 -12
- package/src/server/types/MiddlewareFunction.ts +0 -22
- package/src/server/types/ServerFunction.ts +0 -7
- package/src/server.ts +0 -7
- package/src/site/Router.ts +0 -175
- package/src/site/Site.ts +0 -388
- package/src/site/checkLayoutSlots.ts +0 -114
- package/src/site/checkRoutes.ts +0 -435
- package/src/site/clientEntry.ts +0 -121
- package/src/site/clientEntryDev.ts +0 -3
- package/src/site/defaultAdapter.ts +0 -11
- package/src/site/layoutSlots.ts +0 -53
- package/src/site/manifest.ts +0 -173
- package/src/site/serverEntry.ts +0 -648
- package/src/state/$page.ts +0 -25
- package/src/state/$serverPage.ts +0 -22
- package/src/state/client.ts +0 -15
- package/src/state.ts +0 -3
- package/src/test/runTest.ts +0 -538
- package/src/test.ts +0 -3
- package/src/types/Adapter.ts +0 -20
- package/src/types/ClientState.ts +0 -8
- package/src/types/InternalState.ts +0 -7
- package/src/types/Jsonify.ts +0 -20
- package/src/types/LayoutHandler.ts +0 -5
- package/src/types/LayoutPath.ts +0 -10
- package/src/types/ManifestRoute.ts +0 -6
- package/src/types/PageData.test-d.ts +0 -136
- package/src/types/PageData.ts +0 -35
- package/src/types/PageEndPoint.ts +0 -55
- package/src/types/PageForm.test-d.ts +0 -78
- package/src/types/PageForm.ts +0 -29
- package/src/types/PageLoadEvent.ts +0 -26
- package/src/types/PageLoadReturn.ts +0 -13
- package/src/types/PageProps.ts +0 -14
- package/src/types/PageServerAction.ts +0 -13
- package/src/types/PageServerEndPoint.test-d.ts +0 -105
- package/src/types/PageServerEndPoint.ts +0 -110
- package/src/types/PageServerLoad.ts +0 -15
- package/src/types/PageState.ts +0 -8
- package/src/types/ParseRouteParams.test-d.ts +0 -84
- package/src/types/ParseRouteParams.ts +0 -64
- package/src/types/Route.ts +0 -30
- package/src/types/RouteHandler.ts +0 -23
- package/src/types/RouteLayoutHandler.ts +0 -5
- package/src/types/RouteMatchResult.ts +0 -7
- package/src/types/RouteType.ts +0 -19
- package/src/types/ServerEndPoint.test-d.ts +0 -77
- package/src/types/ServerEndPoint.ts +0 -169
- package/src/types/ServerHook.ts +0 -18
- package/src/types/ServerLoadEvent.ts +0 -82
- package/src/types/ServerRequest.ts +0 -15
- package/src/types/SitePlugin.ts +0 -24
- package/src/types/StandardSchema.ts +0 -109
- package/src/utils/pathToRegex.ts +0 -17
- package/src/utils/pathTrie.ts +0 -182
- package/src/utils/searchParamsToRecord.ts +0 -18
- package/src/utils/torporPackages.ts +0 -150
- package/src/utils/tsconfigAliases.ts +0 -90
- package/src/validation/ValidationError.ts +0 -18
- package/src/validation/endpoint.ts +0 -83
- package/src/validation/validate.ts +0 -26
- package/src/vite-env.d.ts +0 -2
package/src/run/devPlugin.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
2
|
-
import { existsSync, promises as fs } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { Readable } from "node:stream";
|
|
5
|
-
import { type Plugin, type ViteDevServer } from "vite";
|
|
6
|
-
import { serverError } from "../response.ts";
|
|
7
|
-
import Server from "../server/Server.ts";
|
|
8
|
-
import flattenHeaders from "../server/connect/flattenHeaders.ts";
|
|
9
|
-
import type Site from "../site/Site.ts";
|
|
10
|
-
import prepareTemplate from "./prepareTemplate.ts";
|
|
11
|
-
|
|
12
|
-
type ReqHandler = (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* The default Node-runtime dev plugin. Reads `src/site.html`, sets up a torpor
|
|
16
|
-
* `Server` whose catch-all route renders via `vite.ssrLoadModule`, and registers
|
|
17
|
-
* a Connect middleware (after Vite's own middlewares) that bridges Node
|
|
18
|
-
* req/res to the torpor Server's fetch handler.
|
|
19
|
-
*
|
|
20
|
-
* Adapters that need a different runtime (e.g. workerd) provide their own
|
|
21
|
-
* `dev()` plugin instead.
|
|
22
|
-
*/
|
|
23
|
-
export default function devPlugin(site: Site): Plugin {
|
|
24
|
-
return {
|
|
25
|
-
name: "torpor-dev",
|
|
26
|
-
configureServer(vite) {
|
|
27
|
-
// Kick off async setup immediately; the middleware awaits it so we
|
|
28
|
-
// don't depend on whether Vite awaits configureServer itself.
|
|
29
|
-
const handlerPromise = createDevHandler(vite, site);
|
|
30
|
-
// Return a post-hook so our middleware runs AFTER Vite's internal
|
|
31
|
-
// middlewares (static serving, transforms, HMR), acting as the SSR
|
|
32
|
-
// fallback.
|
|
33
|
-
return () => {
|
|
34
|
-
vite.middlewares.use(async (req, res, next) => {
|
|
35
|
-
try {
|
|
36
|
-
const handler = await handlerPromise;
|
|
37
|
-
await handler(req, res);
|
|
38
|
-
} catch (e) {
|
|
39
|
-
next(e as Error);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function createDevHandler(vite: ViteDevServer, site: Site): Promise<ReqHandler> {
|
|
48
|
-
const siteFolder = path.resolve(site.root, "./node_modules/@torpor/build/src/site/");
|
|
49
|
-
const serverScript = path.join(siteFolder, "serverEntry.ts");
|
|
50
|
-
|
|
51
|
-
// Read site.html if present
|
|
52
|
-
// It's called site.html because @torpor/build builds the site (html, routes
|
|
53
|
-
// etc) while the user builds the app (components etc). An endpoints-only
|
|
54
|
-
// site has no site.html, and no template is needed
|
|
55
|
-
let template: string | undefined;
|
|
56
|
-
const templateFile = path.resolve(site.root, "src/site.html");
|
|
57
|
-
if (existsSync(templateFile)) {
|
|
58
|
-
template = await fs.readFile(templateFile, "utf-8");
|
|
59
|
-
|
|
60
|
-
// Apply Vite HTML transforms. This injects the Vite HMR client, and also
|
|
61
|
-
// applies HTML transforms from Vite plugins. Note that we only support a
|
|
62
|
-
// universal transform, not individual transforms for each route
|
|
63
|
-
template = await vite.transformIndexHtml("", template);
|
|
64
|
-
|
|
65
|
-
// Prepare site.html so that we can just splice components into it
|
|
66
|
-
const clientScript = path.join(siteFolder, "clientEntry.ts");
|
|
67
|
-
const clientDevScript = path.join(siteFolder, "clientEntryDev.ts");
|
|
68
|
-
template = prepareTemplate(template, clientScript, clientDevScript);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const server = new Server();
|
|
72
|
-
|
|
73
|
-
// Every request (GET, POST, etc) goes through loadEndPoint
|
|
74
|
-
server.add("*", async (ev) => {
|
|
75
|
-
try {
|
|
76
|
-
// Load the server entry. ssrLoadModule automatically transforms ESM
|
|
77
|
-
// source code to be usable in Node.js. No bundling is required, and
|
|
78
|
-
// it provides efficient invalidation similar to HMR
|
|
79
|
-
const { load } = await vite.ssrLoadModule(serverScript);
|
|
80
|
-
|
|
81
|
-
// Render the app HTML (or fetch server data etc) via serverEntry's
|
|
82
|
-
// exported `load` function
|
|
83
|
-
return await load(ev, template);
|
|
84
|
-
} catch (e: any) {
|
|
85
|
-
// If an error is caught, let Vite fix the stack trace so it maps
|
|
86
|
-
// back to your actual source code
|
|
87
|
-
vite.ssrFixStacktrace(e);
|
|
88
|
-
return serverError(e);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
// Put adapter-specific functionality in the `adapter` property of
|
|
93
|
-
// globalThis for now
|
|
94
|
-
// @ts-ignore
|
|
95
|
-
globalThis.adapter = { env: process.env };
|
|
96
|
-
|
|
97
|
-
return async (req, res) => {
|
|
98
|
-
const request = await nodeReqToRequest(req);
|
|
99
|
-
const response = await server.fetch(request);
|
|
100
|
-
await sendResponse(response, res);
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function nodeReqToRequest(req: IncomingMessage): Promise<Request> {
|
|
105
|
-
const url = req.url ?? "/";
|
|
106
|
-
const host = req.headers.host ?? "localhost";
|
|
107
|
-
const protocol = "encrypted" in req.socket && req.socket.encrypted ? "https" : "http";
|
|
108
|
-
const init: RequestInit = {
|
|
109
|
-
method: req.method,
|
|
110
|
-
headers: flattenHeaders(req.headers),
|
|
111
|
-
};
|
|
112
|
-
if (req.method !== "GET" && req.method !== "HEAD") {
|
|
113
|
-
init.body = Readable.toWeb(req) as ReadableStream;
|
|
114
|
-
// @ts-ignore duplex is required when streaming a body
|
|
115
|
-
init.duplex = "half";
|
|
116
|
-
}
|
|
117
|
-
return new Request(`${protocol}://${host}${url}`, init);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
async function sendResponse(response: Response, res: ServerResponse): Promise<void> {
|
|
121
|
-
res.statusCode = response.status;
|
|
122
|
-
response.headers.forEach((value, key) => res.setHeader(key, value));
|
|
123
|
-
if (!response.body) {
|
|
124
|
-
res.end();
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
Readable.fromWeb(response.body as unknown as import("node:stream/web").ReadableStream).pipe(res);
|
|
128
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
export default function prepareTemplate(
|
|
2
|
-
template: string,
|
|
3
|
-
clientScript: string,
|
|
4
|
-
clientDevScript?: string,
|
|
5
|
-
): string {
|
|
6
|
-
let result = template;
|
|
7
|
-
|
|
8
|
-
// Put %COMPONENT_HEAD% before </head>
|
|
9
|
-
// This is where styles will go
|
|
10
|
-
let headStart = result.indexOf("</head>");
|
|
11
|
-
if (headStart === -1) {
|
|
12
|
-
throw new Error(`Couldn't find <head> end tag`);
|
|
13
|
-
}
|
|
14
|
-
result = result.substring(0, headStart) + "%COMPONENT_HEAD%" + result.substring(headStart);
|
|
15
|
-
|
|
16
|
-
// Put %COMPONENT_BODY% inside <div id="app"></div>
|
|
17
|
-
// This is where the component's HTML will go
|
|
18
|
-
let divMatchStart = regexIndexOf(result, /<div\s+id=("app"|'app'|app)[\s>]/);
|
|
19
|
-
if (divMatchStart === -1) {
|
|
20
|
-
throw new Error(`Couldn't find <div id="app"></div>`);
|
|
21
|
-
}
|
|
22
|
-
let bodyStart = result.indexOf(">", divMatchStart) + 1;
|
|
23
|
-
let bodyEnd = result.indexOf("</div>", bodyStart);
|
|
24
|
-
if (bodyEnd === -1) {
|
|
25
|
-
throw new Error(`Couldn't find <div id="app"></div>`);
|
|
26
|
-
}
|
|
27
|
-
result = result.substring(0, bodyStart) + "%COMPONENT_BODY%" + result.substring(bodyEnd);
|
|
28
|
-
|
|
29
|
-
// Add the clientEntry script at the very end, for hydrating and navigating
|
|
30
|
-
if (clientDevScript) {
|
|
31
|
-
result += `<script type="module" src="${clientDevScript}"></script>`;
|
|
32
|
-
}
|
|
33
|
-
result += `<script type="module" src="${clientScript}"></script>`;
|
|
34
|
-
|
|
35
|
-
return result;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// From https://stackoverflow.com/a/274094
|
|
39
|
-
function regexIndexOf(string: string, regex: RegExp, position?: number) {
|
|
40
|
-
var indexOf = string.substring(position || 0).search(regex);
|
|
41
|
-
return indexOf >= 0 ? indexOf + (position || 0) : indexOf;
|
|
42
|
-
}
|
package/src/run/run.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { createServer as createViteServer, type ViteDevServer } from "vite";
|
|
4
|
-
import Site from "../site/Site";
|
|
5
|
-
import runBuild from "./runBuild";
|
|
6
|
-
import runDev from "./runDev";
|
|
7
|
-
import runPreview from "./runPreview";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Looks for and loads a site.config.js/ts file in the working directory,
|
|
11
|
-
* running the site's plugins. The Vite server used to load the config is
|
|
12
|
-
* returned as well, so that (for example) route files can be loaded through
|
|
13
|
-
* it; callers are responsible for closing it.
|
|
14
|
-
*/
|
|
15
|
-
export async function loadSite(folder: string): Promise<{ site: Site; vite: ViteDevServer }> {
|
|
16
|
-
// Look for and load a site.config.js/ts file in the working directory
|
|
17
|
-
const jsConfigFile = path.join(folder, "site.config.js");
|
|
18
|
-
const tsConfigFile = path.join(folder, "site.config.ts");
|
|
19
|
-
let configFile = "";
|
|
20
|
-
if (fs.existsSync(jsConfigFile)) {
|
|
21
|
-
configFile = jsConfigFile;
|
|
22
|
-
} else if (fs.existsSync(tsConfigFile)) {
|
|
23
|
-
configFile = tsConfigFile;
|
|
24
|
-
} else {
|
|
25
|
-
throw new Error("site.config file not found");
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Use a temporary Vite server to load the config, so that local TS imports
|
|
29
|
-
// (e.g. a routes.ts file) and path aliases are resolved correctly
|
|
30
|
-
const vite = await createViteServer({
|
|
31
|
-
server: { middlewareMode: true },
|
|
32
|
-
appType: "custom",
|
|
33
|
-
resolve: { tsconfigPaths: true },
|
|
34
|
-
optimizeDeps: { noDiscovery: true },
|
|
35
|
-
});
|
|
36
|
-
try {
|
|
37
|
-
const site = (await vite.ssrLoadModule(configFile)).default as Site;
|
|
38
|
-
site.configFile = configFile;
|
|
39
|
-
|
|
40
|
-
if (!site || !site.root || !site.routes) {
|
|
41
|
-
throw new Error("Invalid site in config file");
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Run the site's plugins. The manifest plugin also runs them when the
|
|
45
|
-
// server starts up (dev SSR and production), so that plugin routes are
|
|
46
|
-
// registered in the runtime as well
|
|
47
|
-
for (const plugin of site.plugins) {
|
|
48
|
-
await plugin(site);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return { site, vite };
|
|
52
|
-
} catch (error) {
|
|
53
|
-
await vite.close();
|
|
54
|
-
throw error;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export default async function run(
|
|
59
|
-
folder: string,
|
|
60
|
-
mode: "dev" | "build" | "preview",
|
|
61
|
-
): Promise<void> {
|
|
62
|
-
const { site, vite } = await loadSite(folder);
|
|
63
|
-
try {
|
|
64
|
-
switch (mode) {
|
|
65
|
-
case "dev": {
|
|
66
|
-
await runDev(site);
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
case "build": {
|
|
70
|
-
await runBuild(site);
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
case "preview": {
|
|
74
|
-
await runPreview(site);
|
|
75
|
-
break;
|
|
76
|
-
}
|
|
77
|
-
default: {
|
|
78
|
-
console.log("No mode passed, running in dev");
|
|
79
|
-
await runDev(site);
|
|
80
|
-
break;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
} finally {
|
|
84
|
-
await vite.close();
|
|
85
|
-
}
|
|
86
|
-
}
|
package/src/run/runBuild.ts
DELETED
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
import torpor from "@torpor/unplugin/vite";
|
|
2
|
-
import { existsSync, promises as fs } from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { build, defineConfig, type AliasOptions } from "vite";
|
|
5
|
-
import Site from "../site/Site";
|
|
6
|
-
import { checkApiCalls, checkRoutes, reportRouteIssues } from "../site/checkRoutes";
|
|
7
|
-
import { checkLayoutSlots } from "../site/checkLayoutSlots";
|
|
8
|
-
import manifest from "../site/manifest.ts";
|
|
9
|
-
import tsconfigAliases, { type AliasEntry } from "../utils/tsconfigAliases";
|
|
10
|
-
import { addTorporPackageConfig } from "../utils/torporPackages";
|
|
11
|
-
|
|
12
|
-
// TODO: Don't cache index.html in dev?
|
|
13
|
-
// TODO: Don't reload layouts during client routing
|
|
14
|
-
// TODO: Call the correct +page and +server routes when in the same folder
|
|
15
|
-
|
|
16
|
-
export default async function runBuild(site: Site): Promise<void> {
|
|
17
|
-
// Check route type annotations and makeApi calls against the routes
|
|
18
|
-
// derived from file locations, and check that layouts render their slot;
|
|
19
|
-
// errors fail the build before anything is written
|
|
20
|
-
let errorCount = reportRouteIssues(checkRoutes(site));
|
|
21
|
-
errorCount += reportRouteIssues(checkApiCalls(site));
|
|
22
|
-
errorCount += reportRouteIssues(checkLayoutSlots(site));
|
|
23
|
-
if (errorCount > 0) {
|
|
24
|
-
throw new Error(
|
|
25
|
-
`Route type check failed with ${errorCount} error${errorCount === 1 ? "" : "s"} (see above)`,
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Delete the dist folder if it exists
|
|
30
|
-
const distFolder = path.resolve(site.root, "dist");
|
|
31
|
-
if (existsSync(distFolder)) {
|
|
32
|
-
await fs.rm(distFolder, { recursive: true });
|
|
33
|
-
}
|
|
34
|
-
const clientFolder = path.join(distFolder, "client");
|
|
35
|
-
const serverFolder = path.join(distFolder, "server");
|
|
36
|
-
|
|
37
|
-
// HOOK: Prebuild
|
|
38
|
-
if (site.adapter.prebuild) {
|
|
39
|
-
await site.adapter.prebuild(site);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// TODO: From a setting
|
|
43
|
-
// An endpoints-only site has no site.html, so everything template-related
|
|
44
|
-
// is optional
|
|
45
|
-
const siteHtml = path.resolve(site.root, "src/site.html");
|
|
46
|
-
const hasSiteHtml = existsSync(siteHtml);
|
|
47
|
-
|
|
48
|
-
const siteFolder = path.resolve(site.root, "./node_modules/@torpor/build/src/site/");
|
|
49
|
-
let clientScript = path.join(siteFolder, "clientEntry.ts");
|
|
50
|
-
let serverScript = path.join(siteFolder, "serverEntry.ts");
|
|
51
|
-
|
|
52
|
-
// Build the client assets, including site.html and the route files
|
|
53
|
-
// EXCLUDING anything with `server.js` in the name
|
|
54
|
-
const clientConfig = structuredClone(site.viteConfig ?? {});
|
|
55
|
-
// Resolve tsconfig path aliases (e.g. `@/*`). Previously provided by the
|
|
56
|
-
// default `vite-tsconfig-paths` plugin on Site; vite-plus handles it inline
|
|
57
|
-
// for the client, but hardcodes tsconfigPaths:false on the SSR
|
|
58
|
-
// externalization path, so mirror tsconfig `compilerOptions.paths` as Vite
|
|
59
|
-
// `resolve.alias` to resolve them during transform for both client and SSR
|
|
60
|
-
clientConfig.resolve ??= {};
|
|
61
|
-
clientConfig.resolve.tsconfigPaths ??= true;
|
|
62
|
-
clientConfig.resolve.alias = [
|
|
63
|
-
...asAliasArray(clientConfig.resolve.alias),
|
|
64
|
-
...tsconfigAliases(site.root),
|
|
65
|
-
];
|
|
66
|
-
clientConfig.plugins = [manifest(site), torpor(), ...site.vitePlugins];
|
|
67
|
-
clientConfig.build ??= {};
|
|
68
|
-
clientConfig.build.outDir = clientFolder;
|
|
69
|
-
clientConfig.build.rollupOptions ??= {};
|
|
70
|
-
clientConfig.build.rollupOptions.input = [
|
|
71
|
-
...(hasSiteHtml ? [siteHtml] : []),
|
|
72
|
-
clientScript,
|
|
73
|
-
...site.routes
|
|
74
|
-
.filter((r) => r.file && !/server\.(ts|js)$/.test(r.file))
|
|
75
|
-
.map((r) => path.resolve(site.root, r.file!)),
|
|
76
|
-
...site.inputs.filter((f) => !/server\.(ts|js)$/.test(f)),
|
|
77
|
-
];
|
|
78
|
-
clientConfig.build.ssrManifest = true;
|
|
79
|
-
await build(defineConfig(clientConfig));
|
|
80
|
-
|
|
81
|
-
// Build the server assets, including the server entry script and the route
|
|
82
|
-
// files
|
|
83
|
-
const serverConfig = structuredClone(site.viteConfig ?? {});
|
|
84
|
-
// Resolve tsconfig path aliases (e.g. `@/*`), as above
|
|
85
|
-
serverConfig.resolve ??= {};
|
|
86
|
-
serverConfig.resolve.tsconfigPaths ??= true;
|
|
87
|
-
serverConfig.resolve.alias = [
|
|
88
|
-
...asAliasArray(serverConfig.resolve.alias),
|
|
89
|
-
...tsconfigAliases(site.root),
|
|
90
|
-
];
|
|
91
|
-
serverConfig.plugins = [manifest(site, true), torpor(), ...site.vitePlugins];
|
|
92
|
-
serverConfig.build ??= {};
|
|
93
|
-
serverConfig.build.outDir = serverFolder;
|
|
94
|
-
// Bundle packages that ship `.torp` files into the server build, as they
|
|
95
|
-
// need the torpor compiler (Node/workerd can't load them externalized)
|
|
96
|
-
addTorporPackageConfig(site.root, serverConfig);
|
|
97
|
-
serverConfig.build.rollupOptions ??= {};
|
|
98
|
-
serverConfig.build.rollupOptions.input = [
|
|
99
|
-
serverScript,
|
|
100
|
-
...site.routes.filter((r) => r.file).map((r) => path.resolve(site.root, r.file!)),
|
|
101
|
-
...site.inputs,
|
|
102
|
-
];
|
|
103
|
-
serverConfig.build.ssr = serverScript;
|
|
104
|
-
await build(defineConfig(serverConfig));
|
|
105
|
-
|
|
106
|
-
// Move the site.html file into /client
|
|
107
|
-
// HACK: Should do this in Rollup if possible?
|
|
108
|
-
if (hasSiteHtml) {
|
|
109
|
-
await fs.rename(
|
|
110
|
-
path.join(clientFolder, "src", "site.html"),
|
|
111
|
-
path.join(clientFolder, "site.html"),
|
|
112
|
-
);
|
|
113
|
-
await fs.rm(path.join(clientFolder, "src"), { recursive: true });
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// HOOK: Postbuild
|
|
117
|
-
if (site.adapter.postbuild) {
|
|
118
|
-
await site.adapter.postbuild(site);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function asAliasArray(alias: AliasOptions | undefined): AliasEntry[] {
|
|
123
|
-
// Normalize an existing `resolve.alias` value (array | object | undefined)
|
|
124
|
-
// into an array so we can concatenate our tsconfig-derived aliases.
|
|
125
|
-
if (!alias) return [];
|
|
126
|
-
if (Array.isArray(alias)) return alias;
|
|
127
|
-
return Object.entries(alias).map(([find, replacement]) => ({ find, replacement }));
|
|
128
|
-
}
|
package/src/run/runDev.ts
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import estorpor from "@torpor/unplugin/esbuild";
|
|
2
|
-
import torpor from "@torpor/unplugin/vite";
|
|
3
|
-
import { configDotenv } from "dotenv";
|
|
4
|
-
import { readFileSync } from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import {
|
|
7
|
-
type AliasOptions,
|
|
8
|
-
createServer as createViteServer,
|
|
9
|
-
type Plugin,
|
|
10
|
-
type ViteDevServer,
|
|
11
|
-
} from "vite";
|
|
12
|
-
import Site from "../site/Site.ts";
|
|
13
|
-
import {
|
|
14
|
-
checkApiCallSource,
|
|
15
|
-
checkApiCalls,
|
|
16
|
-
checkRoute,
|
|
17
|
-
checkRoutes,
|
|
18
|
-
createApiCallCheck,
|
|
19
|
-
type RouteCheckIssue,
|
|
20
|
-
reportRouteIssues,
|
|
21
|
-
} from "../site/checkRoutes";
|
|
22
|
-
import manifest from "../site/manifest.ts";
|
|
23
|
-
import { checkLayoutSlot, checkLayoutSlots } from "../site/checkLayoutSlots";
|
|
24
|
-
import { LAYOUT_ROUTE } from "../types/RouteType";
|
|
25
|
-
import tsconfigAliases, { type AliasEntry } from "../utils/tsconfigAliases";
|
|
26
|
-
import { addTorporPackageConfig } from "../utils/torporPackages";
|
|
27
|
-
import devPlugin from "./devPlugin.ts";
|
|
28
|
-
import { clearStaleDepCache } from "./depCache";
|
|
29
|
-
import { reportStaleTorpCopies } from "./staleTorpCopies";
|
|
30
|
-
|
|
31
|
-
export default async function runDev(site: Site): Promise<void> {
|
|
32
|
-
// Create the Vite dev server. Unlike the previous middleware-mode setup, we
|
|
33
|
-
// let Vite own the HTTP server (so HMR/websockets work natively) and let the
|
|
34
|
-
// adapter's `dev()` plugin(s) handle SSR via configureServer.
|
|
35
|
-
const config = structuredClone(site.viteConfig ?? {});
|
|
36
|
-
config.appType = "custom";
|
|
37
|
-
config.server ??= {};
|
|
38
|
-
config.server.host ??= "localhost";
|
|
39
|
-
config.server.port ??= 7059;
|
|
40
|
-
// Resolve tsconfig path aliases (e.g. `@/*`). Previously provided by the
|
|
41
|
-
// default `vite-tsconfig-paths` plugin on Site; vite-plus handles it inline
|
|
42
|
-
config.resolve ??= {};
|
|
43
|
-
config.resolve.tsconfigPaths ??= true;
|
|
44
|
-
// Resolve `@torpor/view` (runtime, compiler, SSR) from source in dev mode
|
|
45
|
-
// so changes to the compiler take effect without rebuilding dist.
|
|
46
|
-
config.resolve.conditions ??= [];
|
|
47
|
-
config.resolve.conditions.push("development");
|
|
48
|
-
// vite-plus' `tsconfigPaths` isn't honored by the SSR module-runner's
|
|
49
|
-
// externalization path (it hardcodes tsconfigPaths:false), so dev SSR can't
|
|
50
|
-
// resolve path aliases. Mirror tsconfig `compilerOptions.paths` as Vite
|
|
51
|
-
// `resolve.alias` so they resolve during transform for both client and SSR.
|
|
52
|
-
config.resolve.alias = [...asAliasArray(config.resolve.alias), ...tsconfigAliases(site.root)];
|
|
53
|
-
|
|
54
|
-
// The adapter provides the dev-runtime plugin(s); fall back to the
|
|
55
|
-
// framework's Node-runtime plugin when it doesn't.
|
|
56
|
-
const adapterDev = site.adapter.dev?.(site);
|
|
57
|
-
const devPlugins = normalizePlugins(adapterDev ?? devPlugin(site));
|
|
58
|
-
|
|
59
|
-
config.plugins = [
|
|
60
|
-
manifest(site, true),
|
|
61
|
-
torpor({ dev: true }),
|
|
62
|
-
...devPlugins,
|
|
63
|
-
...site.vitePlugins,
|
|
64
|
-
];
|
|
65
|
-
|
|
66
|
-
// HACK: To be able to import `.torp` files from barrel files in
|
|
67
|
-
// node_modules, we need to add their libraries to `ssr.noExternal` in
|
|
68
|
-
// site.config.ts, and let esbuild know how to compile them here
|
|
69
|
-
config.optimizeDeps ??= {};
|
|
70
|
-
config.optimizeDeps.extensions ??= [];
|
|
71
|
-
config.optimizeDeps.extensions.push(".torp");
|
|
72
|
-
config.optimizeDeps.rolldownOptions ??= {};
|
|
73
|
-
config.optimizeDeps.rolldownOptions.plugins ??= [estorpor()];
|
|
74
|
-
// TODO: config.optimizeDeps.rolldownOptions.plugins.push(estorpor());
|
|
75
|
-
|
|
76
|
-
// Packages that ship `.torp` files (e.g. icon libraries) need the torpor
|
|
77
|
-
// compiler: dep optimization would parse them as plain JavaScript and
|
|
78
|
-
// fail, and SSR externalization would leave raw `.torp` imports that
|
|
79
|
-
// Node/workerd can't load. Exclude them from optimization and mark them
|
|
80
|
-
// for SSR bundling so they go through the torpor plugin
|
|
81
|
-
addTorporPackageConfig(site.root, config);
|
|
82
|
-
|
|
83
|
-
// Workspace packages may have been rebuilt since the last dev run; drop
|
|
84
|
-
// Vite's dep cache so SSR never executes stale prebundled modules
|
|
85
|
-
clearStaleDepCache(site.root, (message) => console.log(`\n${message}`));
|
|
86
|
-
|
|
87
|
-
// A workspace package with dist .torp copies (e.g. @torpor/ui) whose src
|
|
88
|
-
// changed without a rebuild serves OLD components to the site, silently;
|
|
89
|
-
// report the drift so it can be fixed with a rebuild
|
|
90
|
-
reportStaleTorpCopies(site.root, (message) => console.log(`\n${message}`));
|
|
91
|
-
|
|
92
|
-
// Load environment variables from a `.env` file, with defaults if not set
|
|
93
|
-
configDotenv();
|
|
94
|
-
|
|
95
|
-
process.env.PROTOCOL ??= "http:";
|
|
96
|
-
process.env.HOST ??= "localhost";
|
|
97
|
-
process.env.PORT ??= "7059";
|
|
98
|
-
|
|
99
|
-
const connectingUrl = `${process.env.PROTOCOL}//${process.env.HOST}:${process.env.PORT}`;
|
|
100
|
-
console.log(`\nConnecting to ${connectingUrl}`);
|
|
101
|
-
|
|
102
|
-
const vite = await createViteServer(config);
|
|
103
|
-
await vite.listen();
|
|
104
|
-
|
|
105
|
-
watchRouteTypes(site, vite);
|
|
106
|
-
|
|
107
|
-
const listeningUrl = vite.resolvedUrls?.local?.[0] ?? connectingUrl;
|
|
108
|
-
console.log(`Listening on ${listeningUrl}\n`);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* Reports route type issues at startup, then re-checks route files and
|
|
113
|
-
* `makeApi` calls as they change so annotation problems surface during
|
|
114
|
-
* development without failing the dev server.
|
|
115
|
-
*/
|
|
116
|
-
function watchRouteTypes(site: Site, vite: ViteDevServer): void {
|
|
117
|
-
reportRouteIssues(checkRoutes(site));
|
|
118
|
-
reportRouteIssues(checkApiCalls(site));
|
|
119
|
-
reportRouteIssues(checkLayoutSlots(site));
|
|
120
|
-
|
|
121
|
-
// Map absolute route file paths to their manifest entries, so changed
|
|
122
|
-
// files can be re-checked against their derived route. Layout route files
|
|
123
|
-
// are included for their slot check (a .torp layout is its own component)
|
|
124
|
-
const routeFiles = new Map(
|
|
125
|
-
site.routes
|
|
126
|
-
.filter(
|
|
127
|
-
(r) => r.file?.endsWith(".ts") || (r.file?.endsWith(".torp") && r.type === LAYOUT_ROUTE),
|
|
128
|
-
)
|
|
129
|
-
.map((r) => [path.resolve(site.root, r.file!), r]),
|
|
130
|
-
);
|
|
131
|
-
const apiCheck = createApiCallCheck(site);
|
|
132
|
-
// Only report when a file's issues change, to avoid repeating the same
|
|
133
|
-
// warnings on every save
|
|
134
|
-
const reported = new Map<string, string>();
|
|
135
|
-
|
|
136
|
-
const report = (file: string, issues: RouteCheckIssue[]) => {
|
|
137
|
-
const key = JSON.stringify(issues);
|
|
138
|
-
if (reported.get(file) === key) return;
|
|
139
|
-
reported.set(file, key);
|
|
140
|
-
reportRouteIssues(issues);
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const recheck = (file: string): void => {
|
|
144
|
-
const route = routeFiles.get(file);
|
|
145
|
-
if (route) {
|
|
146
|
-
report(
|
|
147
|
-
file,
|
|
148
|
-
route.type === LAYOUT_ROUTE ? checkLayoutSlot(site, route) : checkRoute(site, route),
|
|
149
|
-
);
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (!/\.(ts|js|torp)$/.test(file)) return;
|
|
153
|
-
let source: string;
|
|
154
|
-
try {
|
|
155
|
-
source = readFileSync(file, "utf8");
|
|
156
|
-
} catch {
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
report(file, checkApiCallSource(source, file, apiCheck));
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
vite.watcher.on("change", recheck);
|
|
163
|
-
vite.watcher.on("add", recheck);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function normalizePlugins(plugins: Plugin | Plugin[] | void): Plugin[] {
|
|
167
|
-
if (!plugins) return [];
|
|
168
|
-
return Array.isArray(plugins) ? plugins : [plugins];
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
function asAliasArray(alias: AliasOptions | undefined): AliasEntry[] {
|
|
172
|
-
// Normalize an existing `resolve.alias` value (array | object | undefined)
|
|
173
|
-
// into an array so we can concatenate our tsconfig-derived aliases.
|
|
174
|
-
if (!alias) return [];
|
|
175
|
-
if (Array.isArray(alias)) return alias;
|
|
176
|
-
return Object.entries(alias).map(([find, replacement]) => ({ find, replacement }));
|
|
177
|
-
}
|
package/src/run/runOpenApi.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { writeFile } from "node:fs/promises";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import type { ViteDevServer } from "vite";
|
|
4
|
-
import buildOpenApiDocument from "../openapi/document";
|
|
5
|
-
import { OPEN_API_STATE_KEY } from "../openapi/plugin";
|
|
6
|
-
import type { OpenApiEndPoint, OpenApiRouteEntry, ResolvedOpenApiOptions } from "../openapi/types";
|
|
7
|
-
import type Site from "../site/Site";
|
|
8
|
-
import { SERVER_ROUTE } from "../types/RouteType";
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Writes an OpenAPI document for the site's +server endpoints to a file.
|
|
12
|
-
* Route files are loaded through the supplied Vite server, so this must be
|
|
13
|
-
* called while the server from `loadSite` is still open.
|
|
14
|
-
*/
|
|
15
|
-
export default async function runOpenApi(
|
|
16
|
-
site: Site,
|
|
17
|
-
vite: ViteDevServer,
|
|
18
|
-
outFile = "openapi.json",
|
|
19
|
-
): Promise<void> {
|
|
20
|
-
const options = site.pluginState.get(OPEN_API_STATE_KEY) as ResolvedOpenApiOptions | undefined;
|
|
21
|
-
if (!options) {
|
|
22
|
-
throw new Error(
|
|
23
|
-
'No OpenAPI options found. Add the openApi() plugin to site.plugins to use "tb --openapi"',
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const entries: OpenApiRouteEntry[] = [];
|
|
28
|
-
for (const route of site.routes) {
|
|
29
|
-
if (route.type !== SERVER_ROUTE) {
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
// Don't document the docs page itself
|
|
33
|
-
if (options.docs && route.path === options.docs) {
|
|
34
|
-
continue;
|
|
35
|
-
}
|
|
36
|
-
if (route.endPoint && !route.file) {
|
|
37
|
-
// Inline endpoint
|
|
38
|
-
entries.push({ path: route.path, endPoint: route.endPoint as OpenApiEndPoint });
|
|
39
|
-
} else if (route.file) {
|
|
40
|
-
const file = path.resolve(site.root, route.file);
|
|
41
|
-
const mod = await vite.ssrLoadModule(file);
|
|
42
|
-
entries.push({ path: route.path, endPoint: mod.default });
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const doc = buildOpenApiDocument(entries, options);
|
|
47
|
-
await writeFile(path.resolve(site.root, outFile), JSON.stringify(doc, null, 2) + "\n");
|
|
48
|
-
|
|
49
|
-
console.log(
|
|
50
|
-
`OpenAPI document written to ${outFile} (${Object.keys(doc.paths ?? {}).length} paths)`,
|
|
51
|
-
);
|
|
52
|
-
}
|