reroute-js 0.0.7 → 0.0.8
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/_/basic/package.json +1 -1
- package/_/blog/package.json +1 -1
- package/cli/bin.d.ts +1 -1
- package/cli/bin.d.ts.map +1 -1
- package/cli/bin.js +161 -350
- package/cli/bin.js.map +5 -18
- package/cli/index.d.ts +2 -0
- package/cli/index.d.ts.map +1 -0
- package/cli/index.js +147 -0
- package/cli/index.js.map +10 -0
- package/cli/src/{index.d.ts → cli.d.ts} +1 -1
- package/cli/src/cli.d.ts.map +1 -0
- package/cli/src/commands/gen.d.ts.map +1 -1
- package/cli/src/libs/index.d.ts +2 -0
- package/cli/src/libs/index.d.ts.map +1 -0
- package/cli/src/libs/tailwind.d.ts +31 -4
- package/cli/src/libs/tailwind.d.ts.map +1 -1
- package/core/index.js +189 -168
- package/core/index.js.map +6 -6
- package/core/src/bundler/transpile.d.ts.map +1 -1
- package/core/src/index.d.ts +0 -1
- package/core/src/index.d.ts.map +1 -1
- package/elysia/index.js +231 -369
- package/elysia/index.js.map +7 -8
- package/elysia/src/plugin.d.ts.map +1 -1
- package/package.json +5 -1
- package/cli/src/index.d.ts.map +0 -1
- package/core/src/tailwind.d.ts +0 -15
- package/core/src/tailwind.d.ts.map +0 -1
package/elysia/index.js
CHANGED
|
@@ -31,11 +31,11 @@ var exports_path = {};
|
|
|
31
31
|
__export(exports_path, {
|
|
32
32
|
stripStart: () => stripStart,
|
|
33
33
|
stripEnd: () => stripEnd,
|
|
34
|
-
join: () =>
|
|
34
|
+
join: () => join2,
|
|
35
35
|
extname: () => extname,
|
|
36
36
|
basename: () => basename
|
|
37
37
|
});
|
|
38
|
-
function
|
|
38
|
+
function join2(...parts) {
|
|
39
39
|
return parts.join("/").replace(/\/+/g, "/");
|
|
40
40
|
}
|
|
41
41
|
function extname(p) {
|
|
@@ -53,9 +53,6 @@ function stripEnd(p, ch) {
|
|
|
53
53
|
return p.endsWith(ch) ? p.slice(0, -ch.length) : p;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
// packages/elysia/src/plugin.ts
|
|
57
|
-
import { watch as fsWatch } from "node:fs";
|
|
58
|
-
|
|
59
56
|
// packages/core/src/bundler/hash.ts
|
|
60
57
|
async function generateContentHash(content) {
|
|
61
58
|
const data = new TextEncoder().encode(content);
|
|
@@ -65,7 +62,100 @@ async function generateContentHash(content) {
|
|
|
65
62
|
hex += b.toString(16).padStart(2, "0");
|
|
66
63
|
return hex.slice(0, 8);
|
|
67
64
|
}
|
|
65
|
+
// packages/cli/src/libs/tailwind.ts
|
|
66
|
+
import { spawn } from "node:child_process";
|
|
67
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
68
|
+
import { join } from "node:path";
|
|
69
|
+
function isTailwindAvailable(cwd) {
|
|
70
|
+
const packageJsonPath = join(cwd, "package.json");
|
|
71
|
+
if (!existsSync(packageJsonPath)) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
76
|
+
const deps = {
|
|
77
|
+
...packageJson.dependencies,
|
|
78
|
+
...packageJson.devDependencies
|
|
79
|
+
};
|
|
80
|
+
return "@tailwindcss/cli" in deps;
|
|
81
|
+
} catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function getTailwindPaths(cwd) {
|
|
86
|
+
const input = join(cwd, "src/client/theme.css");
|
|
87
|
+
const output = join(cwd, ".reroute/theme.css");
|
|
88
|
+
return { input, output };
|
|
89
|
+
}
|
|
90
|
+
function hasTailwindInput(cwd) {
|
|
91
|
+
const { input } = getTailwindPaths(cwd);
|
|
92
|
+
if (!existsSync(input)) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
try {
|
|
96
|
+
const content = readFileSync(input, "utf-8");
|
|
97
|
+
return content.includes('@import "tailwindcss"');
|
|
98
|
+
} catch {
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function resolveTailwindBin(cwd) {
|
|
103
|
+
const pathsToTry = [
|
|
104
|
+
join(cwd, "node_modules/.bin/tailwindcss"),
|
|
105
|
+
join(cwd, "../node_modules/.bin/tailwindcss"),
|
|
106
|
+
join(cwd, "../../node_modules/.bin/tailwindcss"),
|
|
107
|
+
join(cwd, "../../../node_modules/.bin/tailwindcss")
|
|
108
|
+
];
|
|
109
|
+
for (const binPath of pathsToTry) {
|
|
110
|
+
if (existsSync(binPath)) {
|
|
111
|
+
return binPath;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return join(cwd, "node_modules/.bin/tailwindcss");
|
|
115
|
+
}
|
|
116
|
+
async function buildTailwind(cwd) {
|
|
117
|
+
const { input, output } = getTailwindPaths(cwd);
|
|
118
|
+
return new Promise((resolve, reject) => {
|
|
119
|
+
const tailwindBin = resolveTailwindBin(cwd);
|
|
120
|
+
const args = ["-i", input, "-o", output];
|
|
121
|
+
console.log(`[reroute/tailwind] build start: -i ${input} -o ${output}`);
|
|
122
|
+
const tailwind = spawn(tailwindBin, args, {
|
|
123
|
+
cwd,
|
|
124
|
+
stdio: "pipe"
|
|
125
|
+
});
|
|
126
|
+
tailwind.stdout?.on("data", (data) => {
|
|
127
|
+
const line = data.toString().trim();
|
|
128
|
+
if (line) {
|
|
129
|
+
console.log(`[reroute/tailwind] ${line}`);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
tailwind.stderr?.on("data", (data) => {
|
|
133
|
+
const line = data.toString().trim();
|
|
134
|
+
if (line) {
|
|
135
|
+
console.log(`[reroute/tailwind] ${line}`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
tailwind.on("close", (code) => {
|
|
139
|
+
if (code === 0) {
|
|
140
|
+
console.log("[reroute/tailwind] build done");
|
|
141
|
+
resolve();
|
|
142
|
+
} else {
|
|
143
|
+
reject(new Error(`Tailwind CSS build failed with code ${code}`));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
tailwind.on("error", (error) => {
|
|
147
|
+
reject(error);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
}
|
|
68
151
|
// packages/core/src/bundler/transpile.ts
|
|
152
|
+
function isWatchMode() {
|
|
153
|
+
try {
|
|
154
|
+
return Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
|
|
155
|
+
} catch {
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
69
159
|
async function transpileFile(filePath, originalPath, options, bundleCache) {
|
|
70
160
|
const src = await Bun.file(filePath).text();
|
|
71
161
|
const cacheKey = `${filePath}-${await generateContentHash(src)}`;
|
|
@@ -73,6 +163,16 @@ async function transpileFile(filePath, originalPath, options, bundleCache) {
|
|
|
73
163
|
return bundleCache.get(cacheKey);
|
|
74
164
|
}
|
|
75
165
|
console.log(`[reroute] Building ${originalPath}${options.minify ? " (minified)" : ""}...`);
|
|
166
|
+
try {
|
|
167
|
+
if (isWatchMode()) {
|
|
168
|
+
const cwd = typeof process !== "undefined" && process.cwd ? process.cwd() : "";
|
|
169
|
+
if (cwd && isTailwindAvailable(cwd) && hasTailwindInput(cwd)) {
|
|
170
|
+
await buildTailwind(cwd);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
} catch (e) {
|
|
174
|
+
console.warn("[reroute/tailwind] rebuild failed:", e);
|
|
175
|
+
}
|
|
76
176
|
async function doBuild(sm) {
|
|
77
177
|
return await Bun.build({
|
|
78
178
|
entrypoints: [filePath],
|
|
@@ -82,7 +182,7 @@ async function transpileFile(filePath, originalPath, options, bundleCache) {
|
|
|
82
182
|
splitting: false,
|
|
83
183
|
sourcemap: sm,
|
|
84
184
|
define: {
|
|
85
|
-
"process.env.
|
|
185
|
+
"process.env.BUN_ENV": options.minify ? '"production"' : '"development"'
|
|
86
186
|
}
|
|
87
187
|
});
|
|
88
188
|
}
|
|
@@ -124,10 +224,10 @@ async function transpileFile(filePath, originalPath, options, bundleCache) {
|
|
|
124
224
|
async function getBundleUrlsFor(modules, clientDir, prefix, options, bundleCache) {
|
|
125
225
|
const mods = Array.isArray(modules) ? modules : [modules];
|
|
126
226
|
const urls = [];
|
|
127
|
-
const { join:
|
|
227
|
+
const { join: join3 } = await Promise.resolve().then(() => exports_path);
|
|
128
228
|
for (const mod of mods) {
|
|
129
229
|
const rel = mod.replace(/^\.\//, "");
|
|
130
|
-
const fullPath =
|
|
230
|
+
const fullPath = join3(clientDir, rel);
|
|
131
231
|
try {
|
|
132
232
|
const bundleInfo = await transpileFile(fullPath, rel, options, bundleCache);
|
|
133
233
|
const base = basename(rel, extname(rel));
|
|
@@ -139,171 +239,16 @@ async function getBundleUrlsFor(modules, clientDir, prefix, options, bundleCache
|
|
|
139
239
|
}
|
|
140
240
|
return urls;
|
|
141
241
|
}
|
|
142
|
-
// packages/core/src/content/builder.ts
|
|
143
|
-
import { mkdir, readdir } from "node:fs/promises";
|
|
144
|
-
import { pathToFileURL } from "node:url";
|
|
145
|
-
async function sha8(text) {
|
|
146
|
-
const data = new TextEncoder().encode(text);
|
|
147
|
-
const buf = await crypto.subtle.digest("SHA-256", data);
|
|
148
|
-
let hex = "";
|
|
149
|
-
for (const b of new Uint8Array(buf))
|
|
150
|
-
hex += b.toString(16).padStart(2, "0");
|
|
151
|
-
return hex.slice(0, 8);
|
|
152
|
-
}
|
|
153
|
-
async function buildChunkFor(absSrc, cwd, collection, name) {
|
|
154
|
-
try {
|
|
155
|
-
const result = await Bun.build({
|
|
156
|
-
entrypoints: [absSrc],
|
|
157
|
-
target: "browser",
|
|
158
|
-
format: "esm",
|
|
159
|
-
splitting: false,
|
|
160
|
-
sourcemap: "none",
|
|
161
|
-
minify: false,
|
|
162
|
-
define: { "process.env.NODE_ENV": '"production"' }
|
|
163
|
-
});
|
|
164
|
-
if (!result.success)
|
|
165
|
-
return null;
|
|
166
|
-
const code = await result.outputs[0]?.text();
|
|
167
|
-
const hash2 = await sha8(code);
|
|
168
|
-
const relDir = join(".reroute", "chunks", collection);
|
|
169
|
-
const absDir = join(cwd, relDir);
|
|
170
|
-
const outFile = `${name}.${hash2}.js`;
|
|
171
|
-
const outPath = join(absDir, outFile);
|
|
172
|
-
await mkdir(absDir, { recursive: true });
|
|
173
|
-
const exists = await Bun.file(outPath).exists();
|
|
174
|
-
if (!exists)
|
|
175
|
-
await Bun.write(outPath, code);
|
|
176
|
-
const url = `/${join(relDir, outFile).replace(/\\+/g, "/")}`;
|
|
177
|
-
return { outPath, url, code };
|
|
178
|
-
} catch (e) {
|
|
179
|
-
console.error("[reroute] Failed to build content chunk:", absSrc, e);
|
|
180
|
-
return null;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
async function getMetaFor(absSrc, isWatchMode) {
|
|
184
|
-
try {
|
|
185
|
-
const url = pathToFileURL(absSrc).href + (isWatchMode ? `?t=${Date.now()}` : "");
|
|
186
|
-
const m = await import(url);
|
|
187
|
-
return m.meta || m.frontmatter || {};
|
|
188
|
-
} catch {
|
|
189
|
-
return {};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
async function rebuildContentArtifacts(cwd, clientDir, isWatchMode = true) {
|
|
193
|
-
const routesRoot = join(clientDir, "routes");
|
|
194
|
-
const items = [];
|
|
195
|
-
try {
|
|
196
|
-
const entries = await readdir(routesRoot, { withFileTypes: true });
|
|
197
|
-
for (const dir of entries) {
|
|
198
|
-
if (!dir.isDirectory())
|
|
199
|
-
continue;
|
|
200
|
-
const collection = dir.name;
|
|
201
|
-
const contentDir = join(routesRoot, collection, "content");
|
|
202
|
-
let contentFiles = [];
|
|
203
|
-
try {
|
|
204
|
-
const list = await readdir(contentDir, { withFileTypes: true });
|
|
205
|
-
contentFiles = list.filter((e) => e.isFile() && /\.(tsx|ts)$/.test(e.name) && !e.name.startsWith("_")).map((e) => e.name);
|
|
206
|
-
} catch {
|
|
207
|
-
continue;
|
|
208
|
-
}
|
|
209
|
-
for (const file of contentFiles) {
|
|
210
|
-
const name = file.replace(/\.(tsx|ts)$/, "");
|
|
211
|
-
const absSrc = join(contentDir, file);
|
|
212
|
-
const chunk = await buildChunkFor(absSrc, cwd, collection, name);
|
|
213
|
-
if (!chunk)
|
|
214
|
-
continue;
|
|
215
|
-
const meta = await getMetaFor(absSrc, isWatchMode);
|
|
216
|
-
items.push({
|
|
217
|
-
collection,
|
|
218
|
-
name,
|
|
219
|
-
slug: name,
|
|
220
|
-
href: `/${collection}/${name}`,
|
|
221
|
-
moduleUrl: chunk.url,
|
|
222
|
-
meta
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
} catch (e) {
|
|
227
|
-
console.error("[reroute] Failed to scan content routes:", e);
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
try {
|
|
231
|
-
const lines = [];
|
|
232
|
-
lines.push("// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8");
|
|
233
|
-
lines.push("/* eslint-disable */");
|
|
234
|
-
lines.push("// @ts-nocheck");
|
|
235
|
-
lines.push("");
|
|
236
|
-
lines.push("export const contents = [");
|
|
237
|
-
for (const e of items) {
|
|
238
|
-
lines.push(" { collection: '" + e.collection + "', slug: '" + e.slug + "', name: '" + e.name + "', href: '" + e.href + "', module: '" + e.moduleUrl + "', meta: " + JSON.stringify(e.meta || {}) + " },");
|
|
239
|
-
}
|
|
240
|
-
lines.push("] as const;");
|
|
241
|
-
lines.push("");
|
|
242
|
-
lines.push("export const byCollection: Record<string, any[]> = {};");
|
|
243
|
-
lines.push("for (const c of contents) { (byCollection[c.collection] ||= []).push(c as any); }");
|
|
244
|
-
lines.push("");
|
|
245
|
-
lines.push("export const byCollectionAndName: Record<string, Record<string, any>> = {};");
|
|
246
|
-
lines.push("for (const c of contents) { ((byCollectionAndName[c.collection] ||= {})[c.name] = c as any); }");
|
|
247
|
-
lines.push("");
|
|
248
|
-
lines.push("export type Collections = keyof typeof byCollection;");
|
|
249
|
-
lines.push("export type Names<C extends Collections> = keyof (typeof byCollectionAndName)[C];");
|
|
250
|
-
lines.push("export type ContentEntry = (typeof contents)[number];");
|
|
251
|
-
lines.push("");
|
|
252
|
-
lines.push("export function getContentEntry<C extends string, N extends string>(collection: C, name: N) {");
|
|
253
|
-
lines.push(" const m = (byCollectionAndName as any)[collection];");
|
|
254
|
-
lines.push(" return m ? (m as Record<string, any>)[name] : undefined;");
|
|
255
|
-
lines.push("}");
|
|
256
|
-
lines.push("");
|
|
257
|
-
await mkdir(join(cwd, ".reroute"), { recursive: true });
|
|
258
|
-
await Bun.write(join(cwd, ".reroute", "content.ts"), lines.join(`
|
|
259
|
-
`));
|
|
260
|
-
} catch (e) {
|
|
261
|
-
console.error("[reroute] Failed to write .reroute/content.ts:", e);
|
|
262
|
-
}
|
|
263
|
-
try {
|
|
264
|
-
const byCol = new Map;
|
|
265
|
-
for (const it of items) {
|
|
266
|
-
const arr = byCol.get(it.collection) || [];
|
|
267
|
-
arr.push(it);
|
|
268
|
-
byCol.set(it.collection, arr);
|
|
269
|
-
}
|
|
270
|
-
await mkdir(join(cwd, ".reroute", "collections"), { recursive: true });
|
|
271
|
-
for (const [collection, list] of byCol) {
|
|
272
|
-
const js = [];
|
|
273
|
-
js.push("// \uD83D\uDEA8 Auto-generated by Reroute - DO NOT EDIT \uD83D\uDEA8");
|
|
274
|
-
js.push("");
|
|
275
|
-
js.push("export const items = [");
|
|
276
|
-
for (const e of list) {
|
|
277
|
-
js.push(` { collection: '${e.collection}', slug: '${e.slug}', name: '${e.name}', href: '${e.href}', module: '${e.moduleUrl}', meta: ${JSON.stringify(e.meta || {})} },`);
|
|
278
|
-
}
|
|
279
|
-
js.push("];");
|
|
280
|
-
js.push("");
|
|
281
|
-
js.push("export const byName = {};");
|
|
282
|
-
js.push("for (const it of items) { byName[it.name] = it; }");
|
|
283
|
-
js.push("");
|
|
284
|
-
js.push("export function get(collectionName, name) {");
|
|
285
|
-
js.push(` if (collectionName !== '${collection}') return undefined;`);
|
|
286
|
-
js.push(" return byName[name];");
|
|
287
|
-
js.push("}");
|
|
288
|
-
js.push("");
|
|
289
|
-
await Bun.write(join(cwd, ".reroute", "collections", `${collection}.js`), js.join(`
|
|
290
|
-
`));
|
|
291
|
-
}
|
|
292
|
-
} catch (e) {
|
|
293
|
-
console.error("[reroute] Failed to write .reroute/collections/*:", e);
|
|
294
|
-
}
|
|
295
|
-
console.log("[reroute] Content artifacts up-to-date");
|
|
296
|
-
}
|
|
297
242
|
// packages/core/src/content/discovery.ts
|
|
298
|
-
import { readdir
|
|
243
|
+
import { readdir, stat as stat2 } from "node:fs/promises";
|
|
299
244
|
|
|
300
245
|
// packages/core/src/content/metadata.ts
|
|
301
246
|
import { stat } from "node:fs/promises";
|
|
302
|
-
import { pathToFileURL
|
|
303
|
-
async function getContentMeta(absPath,
|
|
247
|
+
import { pathToFileURL } from "node:url";
|
|
248
|
+
async function getContentMeta(absPath, isWatchMode2) {
|
|
304
249
|
try {
|
|
305
|
-
const url =
|
|
306
|
-
const mod = await import(`${url}${
|
|
250
|
+
const url = pathToFileURL(absPath).href;
|
|
251
|
+
const mod = await import(`${url}${isWatchMode2 ? `?t=${Date.now()}` : ""}`);
|
|
307
252
|
const meta = mod.meta || mod.frontmatter || {};
|
|
308
253
|
if (meta && typeof meta === "object")
|
|
309
254
|
return meta;
|
|
@@ -339,10 +284,10 @@ function escapeHtml(input) {
|
|
|
339
284
|
async function listContentFiles(dir, baseRel) {
|
|
340
285
|
const out = [];
|
|
341
286
|
try {
|
|
342
|
-
const entries = await
|
|
287
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
343
288
|
for (const entry of entries) {
|
|
344
|
-
const full =
|
|
345
|
-
const rel =
|
|
289
|
+
const full = join2(dir, entry.name);
|
|
290
|
+
const rel = join2(baseRel, entry.name);
|
|
346
291
|
if (entry.isDirectory()) {
|
|
347
292
|
const nested = await listContentFiles(full, rel);
|
|
348
293
|
out.push(...nested);
|
|
@@ -355,19 +300,19 @@ async function listContentFiles(dir, baseRel) {
|
|
|
355
300
|
} catch {}
|
|
356
301
|
return out;
|
|
357
302
|
}
|
|
358
|
-
async function buildContentDTOs(collectionPath, clientDir, prefix,
|
|
303
|
+
async function buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode2) {
|
|
359
304
|
const normalized = stripStart(stripEnd(collectionPath, "/"), "/");
|
|
360
|
-
const contentRelDir =
|
|
361
|
-
const contentAbsDir =
|
|
305
|
+
const contentRelDir = join2("routes", normalized, "content");
|
|
306
|
+
const contentAbsDir = join2(clientDir, contentRelDir);
|
|
362
307
|
const files = await listContentFiles(contentAbsDir, "");
|
|
363
308
|
const items = [];
|
|
364
309
|
for (const rel of files) {
|
|
365
|
-
const fullRelPath =
|
|
366
|
-
const absPath =
|
|
310
|
+
const fullRelPath = join2(contentRelDir, rel);
|
|
311
|
+
const absPath = join2(clientDir, fullRelPath);
|
|
367
312
|
const noExt = rel.replace(/\.(tsx|ts)$/, "");
|
|
368
313
|
const name = basename(noExt);
|
|
369
314
|
const moduleUrl = `${prefix}/${fullRelPath}`.replace(/\/+/g, "/");
|
|
370
|
-
const meta = await getContentMeta(absPath,
|
|
315
|
+
const meta = await getContentMeta(absPath, isWatchMode2);
|
|
371
316
|
const href = `/${normalized}/${name}`.replace(/\\+/g, "/");
|
|
372
317
|
items.push({
|
|
373
318
|
slug: noExt,
|
|
@@ -381,13 +326,13 @@ async function buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode)
|
|
|
381
326
|
return items;
|
|
382
327
|
}
|
|
383
328
|
async function discoverCollections(clientDir) {
|
|
384
|
-
const root =
|
|
329
|
+
const root = join2(clientDir, "routes");
|
|
385
330
|
const collections = new Set;
|
|
386
331
|
try {
|
|
387
|
-
const entries = await
|
|
332
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
388
333
|
for (const entry of entries) {
|
|
389
334
|
if (entry.isDirectory()) {
|
|
390
|
-
const contentDir =
|
|
335
|
+
const contentDir = join2(root, entry.name, "content");
|
|
391
336
|
try {
|
|
392
337
|
await stat2(contentDir);
|
|
393
338
|
collections.add(entry.name);
|
|
@@ -400,18 +345,18 @@ async function discoverCollections(clientDir) {
|
|
|
400
345
|
// packages/core/src/content/registry.ts
|
|
401
346
|
async function generateContentRegistry(cwd) {
|
|
402
347
|
try {
|
|
403
|
-
const p =
|
|
348
|
+
const p = join2(cwd, ".reroute", "content.ts");
|
|
404
349
|
const exists = await Bun.file(p).exists();
|
|
405
350
|
console.log(exists ? "[reroute] Content registry up-to-date" : "[reroute] Warning: .reroute/content.ts not found");
|
|
406
351
|
} catch {}
|
|
407
352
|
}
|
|
408
353
|
// packages/core/src/ssr/data.ts
|
|
409
|
-
import { pathToFileURL as
|
|
354
|
+
import { pathToFileURL as pathToFileURL3 } from "node:url";
|
|
410
355
|
|
|
411
356
|
// packages/core/src/ssr/modules.ts
|
|
412
|
-
import { readdir as
|
|
413
|
-
import { pathToFileURL as
|
|
414
|
-
async function importContentModuleForPath(pathname, clientDir, cwd,
|
|
357
|
+
import { readdir as readdir2, stat as stat3 } from "node:fs/promises";
|
|
358
|
+
import { pathToFileURL as pathToFileURL2 } from "node:url";
|
|
359
|
+
async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
|
|
415
360
|
try {
|
|
416
361
|
const parts = pathname.split("/").filter(Boolean);
|
|
417
362
|
if (parts.length < 2)
|
|
@@ -419,51 +364,51 @@ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode)
|
|
|
419
364
|
const collection = parts[0];
|
|
420
365
|
const name = parts[1];
|
|
421
366
|
try {
|
|
422
|
-
const registryPath =
|
|
423
|
-
const reg = await import(
|
|
367
|
+
const registryPath = join2(cwd, ".reroute", "content.ts");
|
|
368
|
+
const reg = await import(pathToFileURL2(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
424
369
|
const get = reg?.getContentEntry;
|
|
425
370
|
const entry = typeof get === "function" ? get(collection, name) : undefined;
|
|
426
371
|
const moduleUrl = entry?.module;
|
|
427
372
|
if (moduleUrl?.endsWith(".js")) {
|
|
428
|
-
const abs =
|
|
429
|
-
const href =
|
|
373
|
+
const abs = join2(cwd, moduleUrl.replace(/^\//, ""));
|
|
374
|
+
const href = pathToFileURL2(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
|
|
430
375
|
const mod = await import(href);
|
|
431
376
|
return mod;
|
|
432
377
|
}
|
|
433
378
|
} catch {}
|
|
434
379
|
try {
|
|
435
|
-
const chunkDir =
|
|
436
|
-
const files = await
|
|
380
|
+
const chunkDir = join2(cwd, ".reroute", "chunks", collection);
|
|
381
|
+
const files = await readdir2(chunkDir);
|
|
437
382
|
const matches = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
|
|
438
383
|
if (matches.length) {
|
|
439
384
|
let latest = matches[0];
|
|
440
385
|
let latestM = 0;
|
|
441
386
|
for (const f of matches) {
|
|
442
387
|
try {
|
|
443
|
-
const s = await stat3(
|
|
388
|
+
const s = await stat3(join2(chunkDir, f));
|
|
444
389
|
if (s.mtimeMs >= latestM) {
|
|
445
390
|
latestM = s.mtimeMs;
|
|
446
391
|
latest = f;
|
|
447
392
|
}
|
|
448
393
|
} catch {}
|
|
449
394
|
}
|
|
450
|
-
const absChunk =
|
|
451
|
-
const href =
|
|
395
|
+
const absChunk = join2(chunkDir, latest);
|
|
396
|
+
const href = pathToFileURL2(absChunk).href + (isWatchMode2 ? `?t=${Date.now()}` : "");
|
|
452
397
|
const mod = await import(href);
|
|
453
398
|
return mod;
|
|
454
399
|
}
|
|
455
400
|
} catch {}
|
|
456
401
|
try {
|
|
457
|
-
const srcTsx =
|
|
458
|
-
const srcTs =
|
|
402
|
+
const srcTsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
|
|
403
|
+
const srcTs = join2(clientDir, "routes", collection, "content", `${name}.ts`);
|
|
459
404
|
let absSrc = null;
|
|
460
405
|
if (await Bun.file(srcTsx).exists())
|
|
461
406
|
absSrc = srcTsx;
|
|
462
407
|
else if (await Bun.file(srcTs).exists())
|
|
463
408
|
absSrc = srcTs;
|
|
464
409
|
if (absSrc) {
|
|
465
|
-
const href =
|
|
466
|
-
const mod = await (
|
|
410
|
+
const href = pathToFileURL2(absSrc).href;
|
|
411
|
+
const mod = await (isWatchMode2 ? import(`${href}?t=${Date.now()}`) : import(href));
|
|
467
412
|
return mod;
|
|
468
413
|
}
|
|
469
414
|
} catch {}
|
|
@@ -472,7 +417,7 @@ async function importContentModuleForPath(pathname, clientDir, cwd, isWatchMode)
|
|
|
472
417
|
}
|
|
473
418
|
|
|
474
419
|
// packages/core/src/ssr/seed.ts
|
|
475
|
-
async function seedSSRModuleForPath(pathname, clientDir, cwd,
|
|
420
|
+
async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2) {
|
|
476
421
|
try {
|
|
477
422
|
const parts = pathname.split("/").filter(Boolean);
|
|
478
423
|
if (parts.length < 2)
|
|
@@ -480,7 +425,7 @@ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
|
|
|
480
425
|
const collection = parts[0];
|
|
481
426
|
const name = parts[1];
|
|
482
427
|
const key = `${collection}:${name}`;
|
|
483
|
-
const mod = await importContentModuleForPath(pathname, clientDir, cwd,
|
|
428
|
+
const mod = await importContentModuleForPath(pathname, clientDir, cwd, isWatchMode2);
|
|
484
429
|
if (!mod)
|
|
485
430
|
return;
|
|
486
431
|
const C = mod.default || mod;
|
|
@@ -500,9 +445,9 @@ async function seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode) {
|
|
|
500
445
|
|
|
501
446
|
// packages/core/src/ssr/data.ts
|
|
502
447
|
async function computeSSRDataForPath(params) {
|
|
503
|
-
const { pathname, clientDir, cwd, isWatchMode } = params;
|
|
448
|
+
const { pathname, clientDir, cwd, isWatchMode: isWatchMode2 } = params;
|
|
504
449
|
try {
|
|
505
|
-
await seedSSRModuleForPath(pathname, clientDir, cwd,
|
|
450
|
+
await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
|
|
506
451
|
} catch {}
|
|
507
452
|
try {
|
|
508
453
|
const parts = pathname.split("/").filter(Boolean);
|
|
@@ -517,15 +462,15 @@ async function computeSSRDataForPath(params) {
|
|
|
517
462
|
}
|
|
518
463
|
} catch {}
|
|
519
464
|
try {
|
|
520
|
-
const routesPath =
|
|
521
|
-
const m = await import(
|
|
465
|
+
const routesPath = join2(cwd, ".reroute", "routes.ts");
|
|
466
|
+
const m = await import(pathToFileURL3(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
522
467
|
const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
|
|
523
468
|
const r = match?.route;
|
|
524
469
|
const paramsValue = match?.params || {};
|
|
525
470
|
if (r && typeof r.path === "string") {
|
|
526
471
|
try {
|
|
527
|
-
const abs =
|
|
528
|
-
const mod = await import(
|
|
472
|
+
const abs = join2(clientDir, "routes", String(r.path));
|
|
473
|
+
const mod = await import(pathToFileURL3(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
529
474
|
const ssr = mod?.ssr;
|
|
530
475
|
const dataFn = ssr?.data;
|
|
531
476
|
if (typeof dataFn === "function") {
|
|
@@ -537,8 +482,8 @@ async function computeSSRDataForPath(params) {
|
|
|
537
482
|
return null;
|
|
538
483
|
}
|
|
539
484
|
// packages/core/src/ssr/render.ts
|
|
540
|
-
import { readdir as
|
|
541
|
-
import { pathToFileURL as
|
|
485
|
+
import { readdir as readdir3, stat as stat4 } from "node:fs/promises";
|
|
486
|
+
import { pathToFileURL as pathToFileURL4 } from "node:url";
|
|
542
487
|
|
|
543
488
|
// node_modules/dedent/dist/dedent.mjs
|
|
544
489
|
function ownKeys(object, enumerableOnly) {
|
|
@@ -662,7 +607,7 @@ import { renderToString } from "react-dom/server";
|
|
|
662
607
|
|
|
663
608
|
// packages/core/src/template/html.ts
|
|
664
609
|
async function loadIndexHtml(clientDir) {
|
|
665
|
-
const templatePath =
|
|
610
|
+
const templatePath = join2(clientDir, "index.html");
|
|
666
611
|
try {
|
|
667
612
|
const content = await Bun.file(templatePath).text();
|
|
668
613
|
return content;
|
|
@@ -739,7 +684,7 @@ async function renderSSRDocument(options) {
|
|
|
739
684
|
rootComponent,
|
|
740
685
|
clientDir,
|
|
741
686
|
cwd,
|
|
742
|
-
isWatchMode,
|
|
687
|
+
isWatchMode: isWatchMode2,
|
|
743
688
|
bundleUrl,
|
|
744
689
|
head = "",
|
|
745
690
|
lang = "en",
|
|
@@ -761,7 +706,7 @@ async function renderSSRDocument(options) {
|
|
|
761
706
|
let modulePath = "";
|
|
762
707
|
let isContentCollection = false;
|
|
763
708
|
try {
|
|
764
|
-
const maybeDir =
|
|
709
|
+
const maybeDir = join2(clientDir, "routes", collection, "content");
|
|
765
710
|
const s = await stat4(maybeDir);
|
|
766
711
|
isContentCollection = typeof s?.isDirectory === "function" ? s.isDirectory() : true;
|
|
767
712
|
} catch {
|
|
@@ -771,8 +716,8 @@ async function renderSSRDocument(options) {
|
|
|
771
716
|
throw new Error("skip-content-preload");
|
|
772
717
|
}
|
|
773
718
|
try {
|
|
774
|
-
const registryPath =
|
|
775
|
-
const reg = await import(
|
|
719
|
+
const registryPath = join2(cwd, ".reroute", "content.ts");
|
|
720
|
+
const reg = await import(pathToFileURL4(registryPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
776
721
|
const get = reg?.getContentEntry;
|
|
777
722
|
const entry = typeof get === "function" ? get(collection, name) : undefined;
|
|
778
723
|
const moduleUrl = entry?.module;
|
|
@@ -782,33 +727,33 @@ async function renderSSRDocument(options) {
|
|
|
782
727
|
} catch {}
|
|
783
728
|
if (!modulePath) {
|
|
784
729
|
try {
|
|
785
|
-
const chunkDir =
|
|
786
|
-
const files = await
|
|
730
|
+
const chunkDir = join2(cwd, ".reroute", "chunks", collection);
|
|
731
|
+
const files = await readdir3(chunkDir);
|
|
787
732
|
const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
|
|
788
733
|
if (candidates.length) {
|
|
789
734
|
let latest = candidates[0];
|
|
790
735
|
let latestM = 0;
|
|
791
736
|
for (const candidateName of candidates) {
|
|
792
737
|
try {
|
|
793
|
-
const s = await stat4(
|
|
738
|
+
const s = await stat4(join2(chunkDir, candidateName));
|
|
794
739
|
if (s.mtimeMs >= latestM) {
|
|
795
740
|
latestM = s.mtimeMs;
|
|
796
741
|
latest = candidateName;
|
|
797
742
|
}
|
|
798
743
|
} catch {}
|
|
799
744
|
}
|
|
800
|
-
modulePath = `/${
|
|
745
|
+
modulePath = `/${join2(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
|
|
801
746
|
}
|
|
802
747
|
} catch {}
|
|
803
748
|
}
|
|
804
749
|
if (!modulePath) {
|
|
805
|
-
const tsx =
|
|
806
|
-
const ts =
|
|
750
|
+
const tsx = join2(clientDir, "routes", collection, "content", `${name}.tsx`);
|
|
751
|
+
const ts = join2(clientDir, "routes", collection, "content", `${name}.ts`);
|
|
807
752
|
let srcUrl = "";
|
|
808
753
|
if (await Bun.file(tsx).exists()) {
|
|
809
|
-
srcUrl = `/${
|
|
754
|
+
srcUrl = `/${join2("routes", collection, "content", `${name}.tsx`).replace(/\\+/g, "/")}`;
|
|
810
755
|
} else if (await Bun.file(ts).exists()) {
|
|
811
|
-
srcUrl = `/${
|
|
756
|
+
srcUrl = `/${join2("routes", collection, "content", `${name}.ts`).replace(/\\+/g, "/")}`;
|
|
812
757
|
}
|
|
813
758
|
if (srcUrl) {
|
|
814
759
|
modulePath = srcUrl;
|
|
@@ -826,7 +771,7 @@ async function renderSSRDocument(options) {
|
|
|
826
771
|
}
|
|
827
772
|
}
|
|
828
773
|
} catch {}
|
|
829
|
-
await seedSSRModuleForPath(pathname, clientDir, cwd,
|
|
774
|
+
await seedSSRModuleForPath(pathname, clientDir, cwd, isWatchMode2);
|
|
830
775
|
const __SSR_DATA__ = {};
|
|
831
776
|
try {
|
|
832
777
|
try {
|
|
@@ -846,15 +791,15 @@ async function renderSSRDocument(options) {
|
|
|
846
791
|
}
|
|
847
792
|
} catch {}
|
|
848
793
|
try {
|
|
849
|
-
const routesPath =
|
|
850
|
-
const m = await import(
|
|
794
|
+
const routesPath = join2(cwd, ".reroute", "routes.ts");
|
|
795
|
+
const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
851
796
|
const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
|
|
852
797
|
const r = match?.route;
|
|
853
798
|
const params = match?.params || {};
|
|
854
799
|
if (r && typeof r.path === "string") {
|
|
855
800
|
try {
|
|
856
|
-
const abs =
|
|
857
|
-
const mod = await import(
|
|
801
|
+
const abs = join2(clientDir, "routes", String(r.path));
|
|
802
|
+
const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
858
803
|
const ssr = mod?.ssr;
|
|
859
804
|
const dataFn = ssr?.data;
|
|
860
805
|
if (typeof dataFn === "function") {
|
|
@@ -870,8 +815,8 @@ async function renderSSRDocument(options) {
|
|
|
870
815
|
} catch {}
|
|
871
816
|
let __byCollectionForSSR = {};
|
|
872
817
|
try {
|
|
873
|
-
const p =
|
|
874
|
-
const mod = await import(
|
|
818
|
+
const p = join2(cwd, ".reroute", "content.ts");
|
|
819
|
+
const mod = await import(pathToFileURL4(p).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
875
820
|
__byCollectionForSSR = mod?.byCollection || {};
|
|
876
821
|
try {
|
|
877
822
|
globalThis.__REROUTE_COLLECTIONS__ = __byCollectionForSSR;
|
|
@@ -885,10 +830,10 @@ async function renderSSRDocument(options) {
|
|
|
885
830
|
let inlineStyleTag = "";
|
|
886
831
|
try {
|
|
887
832
|
const candidates = [
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
833
|
+
join2(clientDir, "..", ".reroute", "theme.css"),
|
|
834
|
+
join2(clientDir, "..", "..", ".reroute", "theme.css"),
|
|
835
|
+
join2(clientDir, "..", "..", "..", ".reroute", "theme.css"),
|
|
836
|
+
join2(clientDir, "..", "..", "..", "..", ".reroute", "theme.css")
|
|
892
837
|
];
|
|
893
838
|
let cssPath = "";
|
|
894
839
|
for (const p of candidates) {
|
|
@@ -971,7 +916,7 @@ async function renderSSRDocument(options) {
|
|
|
971
916
|
</script>`;
|
|
972
917
|
} catch {}
|
|
973
918
|
hydrationScript += scripts.map((src) => `<script type="module" src="${src}"></script>`).join("");
|
|
974
|
-
if (
|
|
919
|
+
if (isWatchMode2) {
|
|
975
920
|
hydrationScript += `<script type="module" src="/__reroute_watch.js"></script>`;
|
|
976
921
|
}
|
|
977
922
|
let perPageHead = "";
|
|
@@ -996,8 +941,8 @@ ${ssrHead}`;
|
|
|
996
941
|
}
|
|
997
942
|
} catch {}
|
|
998
943
|
try {
|
|
999
|
-
const routesPath =
|
|
1000
|
-
const m = await import(
|
|
944
|
+
const routesPath = join2(cwd, ".reroute", "routes.ts");
|
|
945
|
+
const m = await import(pathToFileURL4(routesPath).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
1001
946
|
const match = typeof m.matchRoute === "function" ? m.matchRoute(pathname) : null;
|
|
1002
947
|
const r = match?.route;
|
|
1003
948
|
if (!r) {
|
|
@@ -1005,8 +950,8 @@ ${ssrHead}`;
|
|
|
1005
950
|
}
|
|
1006
951
|
if (r && typeof r.path === "string") {
|
|
1007
952
|
try {
|
|
1008
|
-
const abs =
|
|
1009
|
-
const mod = await import(
|
|
953
|
+
const abs = join2(clientDir, "routes", String(r.path));
|
|
954
|
+
const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
1010
955
|
const meta = mod?.meta;
|
|
1011
956
|
const ssr = mod?.ssr;
|
|
1012
957
|
if (meta)
|
|
@@ -1040,8 +985,8 @@ ${ssrHead}`;
|
|
|
1040
985
|
}
|
|
1041
986
|
if (chosen && typeof chosen.path === "string") {
|
|
1042
987
|
try {
|
|
1043
|
-
const abs =
|
|
1044
|
-
const mod = await import(
|
|
988
|
+
const abs = join2(clientDir, "routes", String(chosen.path));
|
|
989
|
+
const mod = await import(pathToFileURL4(abs).href + (isWatchMode2 ? `?t=${Date.now()}` : ""));
|
|
1045
990
|
const meta = mod?.meta;
|
|
1046
991
|
const ssr = mod?.ssr;
|
|
1047
992
|
if (meta)
|
|
@@ -1074,65 +1019,6 @@ ${ssrHead}`;
|
|
|
1074
1019
|
status: statusOverride || 200
|
|
1075
1020
|
};
|
|
1076
1021
|
}
|
|
1077
|
-
// packages/core/src/tailwind.ts
|
|
1078
|
-
import { spawn } from "node:child_process";
|
|
1079
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
1080
|
-
import { join as join2 } from "node:path";
|
|
1081
|
-
function isTailwindAvailable(cwd) {
|
|
1082
|
-
const packageJsonPath = join2(cwd, "package.json");
|
|
1083
|
-
if (!existsSync(packageJsonPath))
|
|
1084
|
-
return false;
|
|
1085
|
-
try {
|
|
1086
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
1087
|
-
const deps = {
|
|
1088
|
-
...packageJson.dependencies,
|
|
1089
|
-
...packageJson.devDependencies
|
|
1090
|
-
};
|
|
1091
|
-
return !!deps && "@tailwindcss/cli" in deps;
|
|
1092
|
-
} catch {
|
|
1093
|
-
return false;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
function getTailwindPaths(cwd) {
|
|
1097
|
-
const input = join2(cwd, "src/client/theme.css");
|
|
1098
|
-
const output = join2(cwd, ".reroute/theme.css");
|
|
1099
|
-
return { input, output };
|
|
1100
|
-
}
|
|
1101
|
-
function hasTailwindInput(cwd) {
|
|
1102
|
-
const { input } = getTailwindPaths(cwd);
|
|
1103
|
-
if (!existsSync(input))
|
|
1104
|
-
return false;
|
|
1105
|
-
try {
|
|
1106
|
-
const content = readFileSync(input, "utf-8");
|
|
1107
|
-
return content.includes('@import "tailwindcss"');
|
|
1108
|
-
} catch {
|
|
1109
|
-
return false;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
function resolveTailwindBin(cwd) {
|
|
1113
|
-
const pathsToTry = [
|
|
1114
|
-
join2(cwd, "node_modules/.bin/tailwindcss"),
|
|
1115
|
-
join2(cwd, "../node_modules/.bin/tailwindcss"),
|
|
1116
|
-
join2(cwd, "../../node_modules/.bin/tailwindcss"),
|
|
1117
|
-
join2(cwd, "../../../node_modules/.bin/tailwindcss")
|
|
1118
|
-
];
|
|
1119
|
-
for (const binPath of pathsToTry)
|
|
1120
|
-
if (existsSync(binPath))
|
|
1121
|
-
return binPath;
|
|
1122
|
-
return join2(cwd, "node_modules/.bin/tailwindcss");
|
|
1123
|
-
}
|
|
1124
|
-
async function buildTailwind(cwd) {
|
|
1125
|
-
const { input, output } = getTailwindPaths(cwd);
|
|
1126
|
-
if (!isTailwindAvailable(cwd) || !hasTailwindInput(cwd))
|
|
1127
|
-
return;
|
|
1128
|
-
await new Promise((resolve, reject) => {
|
|
1129
|
-
const tailwindBin = resolveTailwindBin(cwd);
|
|
1130
|
-
const args = ["-i", input, "-o", output];
|
|
1131
|
-
const tailwind = spawn(tailwindBin, args, { cwd, stdio: "inherit" });
|
|
1132
|
-
tailwind.on("close", (code) => code === 0 ? resolve() : reject(new Error(`Tailwind CSS build failed with code ${code}`)));
|
|
1133
|
-
tailwind.on("error", (error) => reject(error));
|
|
1134
|
-
});
|
|
1135
|
-
}
|
|
1136
1022
|
// packages/core/src/utils/cache.ts
|
|
1137
1023
|
class LRUCache {
|
|
1138
1024
|
cache;
|
|
@@ -1224,7 +1110,7 @@ function registerArtifactsRoutes(app, cwd) {
|
|
|
1224
1110
|
const sub = String(params["*"] || "").replace(/^\/+/, "");
|
|
1225
1111
|
if (!sub)
|
|
1226
1112
|
throw new NotFoundError;
|
|
1227
|
-
const abs =
|
|
1113
|
+
const abs = join2(cwd, ".reroute", sub);
|
|
1228
1114
|
try {
|
|
1229
1115
|
const exists = await Bun.file(abs).exists();
|
|
1230
1116
|
if (!exists)
|
|
@@ -1252,12 +1138,12 @@ function registerArtifactsRoutes(app, cwd) {
|
|
|
1252
1138
|
|
|
1253
1139
|
// packages/elysia/src/routes/content.ts
|
|
1254
1140
|
import { NotFoundError as NotFoundError2 } from "elysia";
|
|
1255
|
-
function registerContentRoutes(app, clientDir, prefix,
|
|
1141
|
+
function registerContentRoutes(app, clientDir, prefix, isWatchMode2) {
|
|
1256
1142
|
app.get("/__content/*", async ({ params, set }) => {
|
|
1257
1143
|
const collectionPath = String(params["*"] || "").trim();
|
|
1258
1144
|
if (!collectionPath)
|
|
1259
1145
|
throw new NotFoundError2;
|
|
1260
|
-
const items = await buildContentDTOs(collectionPath, clientDir, prefix,
|
|
1146
|
+
const items = await buildContentDTOs(collectionPath, clientDir, prefix, isWatchMode2);
|
|
1261
1147
|
const body = JSON.stringify({ collection: collectionPath, items });
|
|
1262
1148
|
set.status = 200;
|
|
1263
1149
|
set.headers["content-type"] = "application/json; charset=utf-8";
|
|
@@ -1319,7 +1205,7 @@ function jsonError(message, status = 500) {
|
|
|
1319
1205
|
}
|
|
1320
1206
|
|
|
1321
1207
|
// packages/elysia/src/routes/dev.ts
|
|
1322
|
-
function registerDevRoutes(app, liveReloadClients,
|
|
1208
|
+
function registerDevRoutes(app, liveReloadClients, isWatchMode2, opts) {
|
|
1323
1209
|
app.get("/__reroute_preload", async ({ query }) => {
|
|
1324
1210
|
const rawSrc = String(query.src || "").trim();
|
|
1325
1211
|
const key = String(query.key || "").trim();
|
|
@@ -1341,7 +1227,7 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode, opts) {
|
|
|
1341
1227
|
return new Response(code, {
|
|
1342
1228
|
headers: {
|
|
1343
1229
|
"content-type": "application/javascript; charset=utf-8",
|
|
1344
|
-
"cache-control":
|
|
1230
|
+
"cache-control": isWatchMode2 ? "no-cache" : "public, max-age=31536000, immutable"
|
|
1345
1231
|
}
|
|
1346
1232
|
});
|
|
1347
1233
|
});
|
|
@@ -1359,14 +1245,14 @@ function registerDevRoutes(app, liveReloadClients, isWatchMode, opts) {
|
|
|
1359
1245
|
pathname,
|
|
1360
1246
|
clientDir: opts?.clientDir || "",
|
|
1361
1247
|
cwd: opts?.cwd || "",
|
|
1362
|
-
isWatchMode
|
|
1248
|
+
isWatchMode: isWatchMode2
|
|
1363
1249
|
});
|
|
1364
1250
|
return jsonWithCache({ data: data2 }, opts?.dataCacheControl || "no-cache", headers);
|
|
1365
1251
|
} catch (_e) {
|
|
1366
1252
|
return jsonError("failed", 500);
|
|
1367
1253
|
}
|
|
1368
1254
|
});
|
|
1369
|
-
if (!
|
|
1255
|
+
if (!isWatchMode2)
|
|
1370
1256
|
return app;
|
|
1371
1257
|
console.log("[reroute] Registering SSE endpoint at /__reroute_watch");
|
|
1372
1258
|
app.get("/__reroute_watch", () => {
|
|
@@ -1438,7 +1324,7 @@ function registerSSRRoutes(app, options) {
|
|
|
1438
1324
|
rootComponent,
|
|
1439
1325
|
clientDir,
|
|
1440
1326
|
cwd,
|
|
1441
|
-
isWatchMode,
|
|
1327
|
+
isWatchMode: isWatchMode2,
|
|
1442
1328
|
getBundleUrl,
|
|
1443
1329
|
head = "",
|
|
1444
1330
|
lang = "en",
|
|
@@ -1463,7 +1349,7 @@ function registerSSRRoutes(app, options) {
|
|
|
1463
1349
|
rootComponent,
|
|
1464
1350
|
clientDir,
|
|
1465
1351
|
cwd,
|
|
1466
|
-
isWatchMode,
|
|
1352
|
+
isWatchMode: isWatchMode2,
|
|
1467
1353
|
bundleUrl,
|
|
1468
1354
|
head,
|
|
1469
1355
|
lang,
|
|
@@ -1496,7 +1382,7 @@ function registerSSRRoutes(app, options) {
|
|
|
1496
1382
|
pathname: p,
|
|
1497
1383
|
clientDir,
|
|
1498
1384
|
cwd,
|
|
1499
|
-
isWatchMode
|
|
1385
|
+
isWatchMode: isWatchMode2
|
|
1500
1386
|
});
|
|
1501
1387
|
return jsonWithCache({ data: data2 }, dataCacheControl || "no-cache", request.headers);
|
|
1502
1388
|
} catch (_e) {
|
|
@@ -1505,7 +1391,7 @@ function registerSSRRoutes(app, options) {
|
|
|
1505
1391
|
}
|
|
1506
1392
|
if (method === "GET" && !isInternal) {
|
|
1507
1393
|
try {
|
|
1508
|
-
if (
|
|
1394
|
+
if (isWatchMode2) {
|
|
1509
1395
|
await generateContentRegistry(cwd);
|
|
1510
1396
|
}
|
|
1511
1397
|
const bundleUrl = await getBundleUrl();
|
|
@@ -1514,7 +1400,7 @@ function registerSSRRoutes(app, options) {
|
|
|
1514
1400
|
rootComponent,
|
|
1515
1401
|
clientDir,
|
|
1516
1402
|
cwd,
|
|
1517
|
-
isWatchMode,
|
|
1403
|
+
isWatchMode: isWatchMode2,
|
|
1518
1404
|
bundleUrl,
|
|
1519
1405
|
head,
|
|
1520
1406
|
lang,
|
|
@@ -1546,15 +1432,15 @@ function registerStaticRoutes(app, options) {
|
|
|
1546
1432
|
shouldIgnore,
|
|
1547
1433
|
bundleCache,
|
|
1548
1434
|
fileCache,
|
|
1549
|
-
isWatchMode
|
|
1435
|
+
isWatchMode: isWatchMode2
|
|
1550
1436
|
} = options;
|
|
1551
1437
|
app.get(`${prefix}/*`, async ({ params, headers }) => {
|
|
1552
1438
|
const requestPath = params["*"];
|
|
1553
1439
|
const hashedJsMatch = requestPath.match(/^(.+)\.([a-f0-9]{8})\.js$/);
|
|
1554
1440
|
if (hashedJsMatch) {
|
|
1555
1441
|
const [, filename, hash2] = hashedJsMatch;
|
|
1556
|
-
const tsxPath =
|
|
1557
|
-
const tsPath =
|
|
1442
|
+
const tsxPath = join2(clientDir, `${filename}.tsx`);
|
|
1443
|
+
const tsPath = join2(clientDir, `${filename}.ts`);
|
|
1558
1444
|
let filePath2 = null;
|
|
1559
1445
|
if (await Bun.file(tsxPath).exists()) {
|
|
1560
1446
|
filePath2 = tsxPath;
|
|
@@ -1584,8 +1470,8 @@ function registerStaticRoutes(app, options) {
|
|
|
1584
1470
|
const sourceMapMatch = requestPath.match(/^(.+)\.([a-f0-9]{8})\.js\.map$/);
|
|
1585
1471
|
if (sourceMapMatch) {
|
|
1586
1472
|
const [, filename, hash2] = sourceMapMatch;
|
|
1587
|
-
const tsxPath =
|
|
1588
|
-
const tsPath =
|
|
1473
|
+
const tsxPath = join2(clientDir, `${filename}.tsx`);
|
|
1474
|
+
const tsPath = join2(clientDir, `${filename}.ts`);
|
|
1589
1475
|
let filePath2 = null;
|
|
1590
1476
|
if (await Bun.file(tsxPath).exists()) {
|
|
1591
1477
|
filePath2 = tsxPath;
|
|
@@ -1620,7 +1506,7 @@ function registerStaticRoutes(app, options) {
|
|
|
1620
1506
|
const name = m[2];
|
|
1621
1507
|
try {
|
|
1622
1508
|
const cwd = process.cwd();
|
|
1623
|
-
const regPath =
|
|
1509
|
+
const regPath = join2(cwd, ".reroute", "content.ts");
|
|
1624
1510
|
const reg = await import((await import("node:url")).pathToFileURL(regPath).href + `?t=${Date.now()}`);
|
|
1625
1511
|
const get = reg?.getContentEntry;
|
|
1626
1512
|
const entry = typeof get === "function" ? get(collection, name) : undefined;
|
|
@@ -1633,7 +1519,7 @@ function registerStaticRoutes(app, options) {
|
|
|
1633
1519
|
}
|
|
1634
1520
|
} catch {}
|
|
1635
1521
|
try {
|
|
1636
|
-
const chunkDir =
|
|
1522
|
+
const chunkDir = join2(process.cwd(), ".reroute", "chunks", collection);
|
|
1637
1523
|
const files = await (await import("node:fs/promises")).readdir(chunkDir);
|
|
1638
1524
|
const candidates = files.filter((n) => n.startsWith(`${name}.`) && n.endsWith(".js"));
|
|
1639
1525
|
if (candidates.length) {
|
|
@@ -1642,14 +1528,14 @@ function registerStaticRoutes(app, options) {
|
|
|
1642
1528
|
const { stat: stat5 } = await import("node:fs/promises");
|
|
1643
1529
|
for (const f of candidates) {
|
|
1644
1530
|
try {
|
|
1645
|
-
const s = await stat5(
|
|
1531
|
+
const s = await stat5(join2(chunkDir, f));
|
|
1646
1532
|
if (s.mtimeMs >= latestM) {
|
|
1647
1533
|
latestM = s.mtimeMs;
|
|
1648
1534
|
latest = f;
|
|
1649
1535
|
}
|
|
1650
1536
|
} catch {}
|
|
1651
1537
|
}
|
|
1652
|
-
const loc = `/${
|
|
1538
|
+
const loc = `/${join2(".reroute", "chunks", collection, latest).replace(/\\+/g, "/")}`;
|
|
1653
1539
|
return new Response(null, {
|
|
1654
1540
|
status: 302,
|
|
1655
1541
|
headers: { Location: loc }
|
|
@@ -1658,7 +1544,7 @@ function registerStaticRoutes(app, options) {
|
|
|
1658
1544
|
} catch {}
|
|
1659
1545
|
}
|
|
1660
1546
|
} catch {}
|
|
1661
|
-
const filePath2 =
|
|
1547
|
+
const filePath2 = join2(clientDir, requestPath);
|
|
1662
1548
|
if (shouldIgnore(filePath2))
|
|
1663
1549
|
throw new NotFoundError5;
|
|
1664
1550
|
try {
|
|
@@ -1671,7 +1557,7 @@ function registerStaticRoutes(app, options) {
|
|
|
1671
1557
|
return new Response(body, {
|
|
1672
1558
|
headers: {
|
|
1673
1559
|
"Content-Type": contentType,
|
|
1674
|
-
"Cache-Control":
|
|
1560
|
+
"Cache-Control": isWatchMode2 ? "no-cache" : `${directive}, max-age=${maxAge}`,
|
|
1675
1561
|
...extraHeaders,
|
|
1676
1562
|
...staticHeaders
|
|
1677
1563
|
}
|
|
@@ -1683,12 +1569,12 @@ function registerStaticRoutes(app, options) {
|
|
|
1683
1569
|
throw new NotFoundError5;
|
|
1684
1570
|
}
|
|
1685
1571
|
}
|
|
1686
|
-
const filePath =
|
|
1572
|
+
const filePath = join2(clientDir, requestPath);
|
|
1687
1573
|
try {
|
|
1688
1574
|
let actualFilePath = filePath;
|
|
1689
1575
|
let exists = await Bun.file(actualFilePath).exists();
|
|
1690
1576
|
if (!exists && indexHTML) {
|
|
1691
|
-
actualFilePath =
|
|
1577
|
+
actualFilePath = join2(filePath, "index.html");
|
|
1692
1578
|
exists = await Bun.file(actualFilePath).exists();
|
|
1693
1579
|
}
|
|
1694
1580
|
if (!exists)
|
|
@@ -1765,13 +1651,11 @@ var reroute = (options = {}) => async (app) => {
|
|
|
1765
1651
|
}
|
|
1766
1652
|
};
|
|
1767
1653
|
const clientDir = assets.startsWith("/") ? assets : `${cwd.replace(/\/$/, "")}/${assets.replace(/^\.\//, "")}`;
|
|
1768
|
-
const join3 = (...parts) => parts.join("/").replace(/\/+/g, "/");
|
|
1769
1654
|
const shouldIgnore = !ignorePatterns.length ? () => false : (file) => ignorePatterns.find((pattern) => typeof pattern === "string" ? file.includes(pattern) : pattern.test(file));
|
|
1770
|
-
const
|
|
1655
|
+
const isWatchMode2 = Array.isArray(process.execArgv) && process.execArgv.includes("--watch") || Array.isArray(process.argv) && process.argv.includes("--watch");
|
|
1771
1656
|
const dataCacheControl = `${directive}, max-age=${maxAge}`;
|
|
1772
|
-
if (
|
|
1657
|
+
if (isWatchMode2)
|
|
1773
1658
|
console.log(`[reroute] Live reload enabled`);
|
|
1774
|
-
}
|
|
1775
1659
|
await generateContentRegistry(cwd);
|
|
1776
1660
|
let cachedBundleUrlPromise = null;
|
|
1777
1661
|
const ensureBundleUrl = () => {
|
|
@@ -1780,8 +1664,8 @@ var reroute = (options = {}) => async (app) => {
|
|
|
1780
1664
|
}
|
|
1781
1665
|
return cachedBundleUrlPromise;
|
|
1782
1666
|
};
|
|
1783
|
-
registerContentRoutes(app, clientDir, prefix,
|
|
1784
|
-
registerDevRoutes(app, liveReloadClients,
|
|
1667
|
+
registerContentRoutes(app, clientDir, prefix, isWatchMode2);
|
|
1668
|
+
registerDevRoutes(app, liveReloadClients, isWatchMode2, {
|
|
1785
1669
|
clientDir,
|
|
1786
1670
|
cwd,
|
|
1787
1671
|
dataCacheControl
|
|
@@ -1800,49 +1684,27 @@ var reroute = (options = {}) => async (app) => {
|
|
|
1800
1684
|
pathname,
|
|
1801
1685
|
clientDir,
|
|
1802
1686
|
cwd,
|
|
1803
|
-
isWatchMode
|
|
1687
|
+
isWatchMode: isWatchMode2
|
|
1804
1688
|
});
|
|
1805
1689
|
return jsonWithCache({ data: data2 }, dataCacheControl, headers);
|
|
1806
1690
|
} catch (_e) {
|
|
1807
1691
|
return jsonError("failed", 500);
|
|
1808
1692
|
}
|
|
1809
1693
|
});
|
|
1810
|
-
if (
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
console.log("[reroute] Rebuilt on change and notified clients");
|
|
1825
|
-
} catch (e) {
|
|
1826
|
-
console.error("[reroute] Dev rebuild failed:", e);
|
|
1827
|
-
}
|
|
1828
|
-
}, 120);
|
|
1829
|
-
};
|
|
1830
|
-
fsWatch(clientDir, { recursive: true }, (_event, filename) => {
|
|
1831
|
-
try {
|
|
1832
|
-
const name = String(filename || "");
|
|
1833
|
-
if (!name)
|
|
1834
|
-
return;
|
|
1835
|
-
if (!/\.(ts|tsx|js|jsx|html|css|json)$/i.test(name))
|
|
1836
|
-
return;
|
|
1837
|
-
if (shouldIgnore(join3(clientDir, name)))
|
|
1838
|
-
return;
|
|
1839
|
-
schedule();
|
|
1840
|
-
} catch {}
|
|
1841
|
-
});
|
|
1842
|
-
console.log(`[reroute] Watching ${clientDir} for changes`);
|
|
1843
|
-
} catch (e) {
|
|
1844
|
-
console.warn("[reroute] Failed to start dev file watcher:", e);
|
|
1845
|
-
}
|
|
1694
|
+
if (isWatchMode2) {
|
|
1695
|
+
app.post("/__reroute_reload", () => {
|
|
1696
|
+
try {
|
|
1697
|
+
notifyReload();
|
|
1698
|
+
return new Response(JSON.stringify({ ok: true }), {
|
|
1699
|
+
headers: { "content-type": "application/json" }
|
|
1700
|
+
});
|
|
1701
|
+
} catch {
|
|
1702
|
+
return new Response(JSON.stringify({ ok: false }), {
|
|
1703
|
+
status: 500,
|
|
1704
|
+
headers: { "content-type": "application/json" }
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
});
|
|
1846
1708
|
}
|
|
1847
1709
|
registerArtifactsRoutes(app, cwd);
|
|
1848
1710
|
if (rootComponent) {
|
|
@@ -1854,7 +1716,7 @@ var reroute = (options = {}) => async (app) => {
|
|
|
1854
1716
|
rootComponent,
|
|
1855
1717
|
clientDir,
|
|
1856
1718
|
cwd,
|
|
1857
|
-
isWatchMode,
|
|
1719
|
+
isWatchMode: isWatchMode2,
|
|
1858
1720
|
getBundleUrl: ensureBundleUrl,
|
|
1859
1721
|
head: ssrHead,
|
|
1860
1722
|
lang: ssrLang,
|
|
@@ -1876,7 +1738,7 @@ var reroute = (options = {}) => async (app) => {
|
|
|
1876
1738
|
shouldIgnore,
|
|
1877
1739
|
bundleCache,
|
|
1878
1740
|
fileCache,
|
|
1879
|
-
isWatchMode
|
|
1741
|
+
isWatchMode: isWatchMode2
|
|
1880
1742
|
});
|
|
1881
1743
|
return app;
|
|
1882
1744
|
};
|
|
@@ -1884,4 +1746,4 @@ export {
|
|
|
1884
1746
|
reroute
|
|
1885
1747
|
};
|
|
1886
1748
|
|
|
1887
|
-
//# debugId=
|
|
1749
|
+
//# debugId=78F127C42E76400F64756E2164756E21
|