@docubook/flame 1.4.3 → 1.5.0
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/.docu/lib/build.deno.js +11 -0
- package/.docu/lib/build.impl-ST63VRTV.js +12 -0
- package/.docu/lib/build.node.js +10 -0
- package/.docu/lib/chunk-2QHMGZIL.js +2419 -0
- package/.docu/lib/chunk-654THQOR.js +461 -0
- package/.docu/lib/chunk-C6RZ2KBH.js +79 -0
- package/.docu/lib/chunk-HH4YXWEF.js +300 -0
- package/.docu/lib/chunk-J5NMYSBJ.js +59 -0
- package/.docu/lib/chunk-RE4NGTMT.js +185 -0
- package/.docu/lib/chunk-X6GYOIYZ.js +383 -0
- package/.docu/lib/chunk-ZOWTASXL.js +92 -0
- package/.docu/lib/clean.js +32 -0
- package/.docu/lib/deploy.deno.js +13 -0
- package/.docu/lib/deploy.node.js +10 -0
- package/.docu/lib/preview.deno.js +10 -0
- package/.docu/lib/preview.node.js +10 -0
- package/.docu/lib/server.deno.js +11 -0
- package/.docu/lib/server.node.js +11 -0
- package/.docu/node/build-summary.ts +126 -0
- package/.docu/node/build.deno.ts +7 -0
- package/.docu/node/build.impl.ts +424 -0
- package/.docu/node/build.node.ts +3 -0
- package/.docu/node/deploy.deno.ts +11 -0
- package/.docu/node/deploy.node.ts +6 -0
- package/.docu/node/deploy.shared.ts +85 -0
- package/.docu/node/deploy.ts +11 -0
- package/.docu/node/escapeHtml.ts +18 -0
- package/.docu/node/git.ts +79 -0
- package/.docu/node/html.shared.ts +110 -0
- package/.docu/node/html.ts +1 -1
- package/.docu/node/hydrate.node.ts +287 -0
- package/.docu/node/hydrate.ts +16 -19
- package/.docu/node/mdx.ts +1 -1
- package/.docu/node/paths.ts +24 -0
- package/.docu/node/plugin-builder.ts +6 -2
- package/.docu/node/plugin.ts +11 -2
- package/.docu/node/preview.deno.ts +4 -0
- package/.docu/node/preview.impl.ts +96 -0
- package/.docu/node/preview.node.ts +4 -0
- package/.docu/node/security.ts +5 -0
- package/.docu/node/server-routes.ts +4 -4
- package/.docu/node/server.deno.ts +4 -0
- package/.docu/node/server.impl.ts +184 -0
- package/.docu/node/server.node.ts +4 -0
- package/.docu/styles/globals.css +20 -5
- package/README.md +57 -506
- package/bin/cli.js +89 -14
- package/bin/compile-lib.mjs +67 -0
- package/package.json +9 -5
- package/template/docs/getting-started/configuration.mdx +18 -0
- package/template/docs/getting-started/overview.mdx +50 -0
- package/template/docs/guide/deployment.mdx +27 -0
- package/template/docs/guide/routing.mdx +25 -0
- package/template/docs/index.mdx +8 -205
- package/template/docu.json +32 -1
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import {
|
|
2
|
+
BuildPluginBuilder,
|
|
3
|
+
DocsLayout,
|
|
4
|
+
DocsPage,
|
|
5
|
+
IndexPage,
|
|
6
|
+
NotFoundPage,
|
|
7
|
+
buildClientBundle,
|
|
8
|
+
captureException,
|
|
9
|
+
compileMdx,
|
|
10
|
+
computeInlineThemeCss,
|
|
11
|
+
generateSearchIndex,
|
|
12
|
+
getGitLastModifiedBatch,
|
|
13
|
+
htmlShell,
|
|
14
|
+
initSentry,
|
|
15
|
+
loadPlugins
|
|
16
|
+
} from "./chunk-2QHMGZIL.js";
|
|
17
|
+
import {
|
|
18
|
+
generateNonce,
|
|
19
|
+
scanMdxFiles
|
|
20
|
+
} from "./chunk-RE4NGTMT.js";
|
|
21
|
+
import {
|
|
22
|
+
logger
|
|
23
|
+
} from "./chunk-HH4YXWEF.js";
|
|
24
|
+
import {
|
|
25
|
+
ASSETS_DIR,
|
|
26
|
+
CACHE_FILE,
|
|
27
|
+
DIST_DIR,
|
|
28
|
+
DOCS_ASSETS_DIR,
|
|
29
|
+
DOCS_DIR,
|
|
30
|
+
PROJECT_ROOT,
|
|
31
|
+
loadDocuConfig
|
|
32
|
+
} from "./chunk-J5NMYSBJ.js";
|
|
33
|
+
|
|
34
|
+
// .docu/node/build.impl.ts
|
|
35
|
+
import { readFile, writeFile, mkdir, readdir as readdir2, copyFile } from "node:fs/promises";
|
|
36
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
37
|
+
import { createHash } from "node:crypto";
|
|
38
|
+
import { join as join2, dirname } from "node:path";
|
|
39
|
+
import React from "react";
|
|
40
|
+
import { renderToString } from "react-dom/server";
|
|
41
|
+
|
|
42
|
+
// .docu/node/build-summary.ts
|
|
43
|
+
import { readdir, stat } from "node:fs/promises";
|
|
44
|
+
import { join, relative, extname } from "node:path";
|
|
45
|
+
import { existsSync } from "node:fs";
|
|
46
|
+
var MAX_FILES_SHOWN = 10;
|
|
47
|
+
var SEP = "\u2500".repeat(60);
|
|
48
|
+
function formatSize(bytes) {
|
|
49
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
50
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
|
|
51
|
+
return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
|
|
52
|
+
}
|
|
53
|
+
async function walkFiles(dir) {
|
|
54
|
+
const out = [];
|
|
55
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
const full = join(dir, entry.name);
|
|
58
|
+
if (entry.isDirectory()) {
|
|
59
|
+
out.push(...await walkFiles(full));
|
|
60
|
+
} else if (entry.isFile()) {
|
|
61
|
+
const s = await stat(full);
|
|
62
|
+
out.push({ path: full, size: s.size });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
async function collectBuildOutput(distDir) {
|
|
68
|
+
if (!existsSync(distDir)) return null;
|
|
69
|
+
const all = await walkFiles(distDir);
|
|
70
|
+
if (all.length === 0) return null;
|
|
71
|
+
const files = all.map((f) => ({ path: relative(distDir, f.path), size: f.size })).sort((a, b) => b.size !== a.size ? b.size - a.size : a.path.localeCompare(b.path));
|
|
72
|
+
const byExt = /* @__PURE__ */ new Map();
|
|
73
|
+
for (const f of files) {
|
|
74
|
+
const ext = extname(f.path) || "(none)";
|
|
75
|
+
const entry = byExt.get(ext) ?? { ext, count: 0, size: 0 };
|
|
76
|
+
entry.count++;
|
|
77
|
+
entry.size += f.size;
|
|
78
|
+
byExt.set(ext, entry);
|
|
79
|
+
}
|
|
80
|
+
const byType = [...byExt.values()].sort(
|
|
81
|
+
(a, b) => b.size !== a.size ? b.size - a.size : b.count - a.count
|
|
82
|
+
);
|
|
83
|
+
return {
|
|
84
|
+
files,
|
|
85
|
+
byType,
|
|
86
|
+
totalFiles: files.length,
|
|
87
|
+
totalSize: files.reduce((sum, f) => sum + f.size, 0)
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function formatBuildSummary(output) {
|
|
91
|
+
const lines = [];
|
|
92
|
+
lines.push("\u{1F4E6} Build Output Summary:");
|
|
93
|
+
lines.push(SEP);
|
|
94
|
+
const shown = output.files.slice(0, MAX_FILES_SHOWN);
|
|
95
|
+
const nameWidth = Math.min(Math.max(...shown.map((f) => f.path.length), 1), 50);
|
|
96
|
+
for (const f of shown) {
|
|
97
|
+
lines.push(` ${f.path.padEnd(nameWidth)} ${formatSize(f.size).padStart(10)}`);
|
|
98
|
+
}
|
|
99
|
+
const remaining = output.totalFiles - shown.length;
|
|
100
|
+
if (remaining > 0) {
|
|
101
|
+
lines.push(` ... and ${remaining} more file${remaining === 1 ? "" : "s"}`);
|
|
102
|
+
}
|
|
103
|
+
lines.push(SEP);
|
|
104
|
+
lines.push("\u{1F4CA} Summary by Type:");
|
|
105
|
+
const extWidth = Math.max(...output.byType.map((t) => t.ext.length), 1);
|
|
106
|
+
for (const t of output.byType) {
|
|
107
|
+
const plural = t.count === 1 ? "file" : "files";
|
|
108
|
+
lines.push(
|
|
109
|
+
` ${t.ext.padEnd(extWidth)} ${String(t.count).padStart(3)} ${plural} ${formatSize(
|
|
110
|
+
t.size
|
|
111
|
+
).padStart(10)}`
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
lines.push(SEP);
|
|
115
|
+
const totalPlural = output.totalFiles === 1 ? "file" : "files";
|
|
116
|
+
lines.push(
|
|
117
|
+
`\u{1F4C8} Total: ${output.totalFiles} ${totalPlural} ${formatSize(output.totalSize).padStart(10)}`
|
|
118
|
+
);
|
|
119
|
+
lines.push(SEP);
|
|
120
|
+
return lines.join("\n");
|
|
121
|
+
}
|
|
122
|
+
async function generateBuildSummary(distDir) {
|
|
123
|
+
const output = await collectBuildOutput(distDir);
|
|
124
|
+
return output ? formatBuildSummary(output) : null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// .docu/node/build.impl.ts
|
|
128
|
+
function parseArgs() {
|
|
129
|
+
const args = process.argv.slice(2);
|
|
130
|
+
return {
|
|
131
|
+
force: args.includes("--force") || args.includes("-f"),
|
|
132
|
+
clean: args.includes("--clean") || args.includes("-c")
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
function hashContent(content) {
|
|
136
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
137
|
+
}
|
|
138
|
+
async function readCache() {
|
|
139
|
+
try {
|
|
140
|
+
if (existsSync2(CACHE_FILE)) {
|
|
141
|
+
const data = await readFile(CACHE_FILE, "utf-8");
|
|
142
|
+
return JSON.parse(data);
|
|
143
|
+
}
|
|
144
|
+
} catch (err) {
|
|
145
|
+
console.error("Failed to load build cache:", err.message);
|
|
146
|
+
}
|
|
147
|
+
return {};
|
|
148
|
+
}
|
|
149
|
+
async function writeCache(cache) {
|
|
150
|
+
await writeFile(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
151
|
+
}
|
|
152
|
+
function parseConcurrency() {
|
|
153
|
+
return Math.max(1, parseInt(process.env.BUILD_CONCURRENCY || "4", 10) || 4);
|
|
154
|
+
}
|
|
155
|
+
function shouldRebuild(path, mtime, cache) {
|
|
156
|
+
const cached = cache[path];
|
|
157
|
+
if (!cached) return "yes";
|
|
158
|
+
if (mtime > cached.builtAt) return "hash_check";
|
|
159
|
+
return "no";
|
|
160
|
+
}
|
|
161
|
+
var assetManifest = { js: "client.js", css: "client.css" };
|
|
162
|
+
var inlineThemeCss;
|
|
163
|
+
async function renderDocsPage(docuConfig, slug, rawMdx, filePath, gitDates, builder, nonce) {
|
|
164
|
+
let content = rawMdx;
|
|
165
|
+
if (builder) {
|
|
166
|
+
const transformed = await builder.runOnLoad(filePath, content);
|
|
167
|
+
if (transformed?.contents) {
|
|
168
|
+
content = transformed.contents;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
let result;
|
|
172
|
+
try {
|
|
173
|
+
const remarkPlugins = builder?.collectRemarkPlugins();
|
|
174
|
+
const rehypePlugins = builder?.collectRehypePlugins();
|
|
175
|
+
result = await compileMdx(content, filePath, gitDates, remarkPlugins, rehypePlugins);
|
|
176
|
+
} catch (err) {
|
|
177
|
+
const msg = err instanceof Error ? err.message : "Unknown MDX error";
|
|
178
|
+
throw new Error(`MDX Error in: docs/${slug}.mdx
|
|
179
|
+
${msg}`, { cause: err });
|
|
180
|
+
}
|
|
181
|
+
let frontmatter = result.frontmatter;
|
|
182
|
+
if (builder) {
|
|
183
|
+
frontmatter = await builder.runTransformFrontmatterChain(frontmatter, {
|
|
184
|
+
slug,
|
|
185
|
+
filePath,
|
|
186
|
+
content
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
const title = (typeof frontmatter.title === "string" ? frontmatter.title : "") || slug || "Docs";
|
|
190
|
+
const description = typeof frontmatter.description === "string" ? frontmatter.description : "";
|
|
191
|
+
const slugParts = slug ? slug.split("/") : [];
|
|
192
|
+
const page = React.createElement(
|
|
193
|
+
DocsLayout,
|
|
194
|
+
{ repoUrl: docuConfig.repo?.url },
|
|
195
|
+
React.createElement(DocsPage, {
|
|
196
|
+
slug: slugParts,
|
|
197
|
+
title,
|
|
198
|
+
description,
|
|
199
|
+
date: frontmatter.date || void 0,
|
|
200
|
+
content: result.content,
|
|
201
|
+
tocs: result.tocs,
|
|
202
|
+
filePath,
|
|
203
|
+
repoUrl: docuConfig.repo?.url,
|
|
204
|
+
compiledSource: result.compiledSource
|
|
205
|
+
})
|
|
206
|
+
);
|
|
207
|
+
const body = renderToString(page);
|
|
208
|
+
const ctx = { slug, filePath, frontmatter, content, config: docuConfig };
|
|
209
|
+
const headExtra = builder?.collectHead(ctx);
|
|
210
|
+
const bodyExtra = builder?.collectBody(ctx);
|
|
211
|
+
const depth = slug ? slug.split("/").length : 1;
|
|
212
|
+
const favicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
213
|
+
let html = htmlShell({
|
|
214
|
+
title,
|
|
215
|
+
description,
|
|
216
|
+
body,
|
|
217
|
+
favicon,
|
|
218
|
+
css: assetManifest.css,
|
|
219
|
+
js: assetManifest.js,
|
|
220
|
+
nonce,
|
|
221
|
+
themeCss: inlineThemeCss,
|
|
222
|
+
depth,
|
|
223
|
+
headExtra,
|
|
224
|
+
bodyExtra
|
|
225
|
+
});
|
|
226
|
+
if (builder) {
|
|
227
|
+
html = await builder.runTransformHtmlChain(html, ctx);
|
|
228
|
+
}
|
|
229
|
+
return html;
|
|
230
|
+
}
|
|
231
|
+
async function copyDirectoryRecursive(src, dest) {
|
|
232
|
+
if (!existsSync2(src)) return;
|
|
233
|
+
await mkdir(dest, { recursive: true });
|
|
234
|
+
const entries = await readdir2(src, { withFileTypes: true });
|
|
235
|
+
for (const entry of entries) {
|
|
236
|
+
const srcPath = join2(src, entry.name);
|
|
237
|
+
const destPath = join2(dest, entry.name);
|
|
238
|
+
if (entry.isDirectory()) {
|
|
239
|
+
await copyDirectoryRecursive(srcPath, destPath);
|
|
240
|
+
} else {
|
|
241
|
+
await copyFile(srcPath, destPath);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function runBuild() {
|
|
246
|
+
const docuConfig = loadDocuConfig();
|
|
247
|
+
const args = parseArgs();
|
|
248
|
+
logger.buildStart();
|
|
249
|
+
if (args.clean) {
|
|
250
|
+
const { rm } = await import("node:fs/promises");
|
|
251
|
+
try {
|
|
252
|
+
await rm(DIST_DIR, { recursive: true, force: true });
|
|
253
|
+
} catch (err) {
|
|
254
|
+
console.error("Failed to clean dist directory:", err.message);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
await mkdir(DIST_DIR, { recursive: true });
|
|
258
|
+
await mkdir(ASSETS_DIR, { recursive: true });
|
|
259
|
+
await copyDirectoryRecursive(DOCS_ASSETS_DIR, join2(DIST_DIR, "docs", "assets"));
|
|
260
|
+
const mdxFiles = await scanMdxFiles(DOCS_DIR);
|
|
261
|
+
const cache = args.force ? {} : await readCache();
|
|
262
|
+
let built = 0;
|
|
263
|
+
let skipped = 0;
|
|
264
|
+
logger.bundleStart();
|
|
265
|
+
let t = performance.now();
|
|
266
|
+
assetManifest = await buildClientBundle();
|
|
267
|
+
logger.bundleDone(Math.round(performance.now() - t));
|
|
268
|
+
inlineThemeCss = computeInlineThemeCss();
|
|
269
|
+
const lastManifest = cache["__assets__"];
|
|
270
|
+
const assetsChanged = !lastManifest || lastManifest.hash !== `${assetManifest.js}:${assetManifest.css}`;
|
|
271
|
+
if (assetsChanged) {
|
|
272
|
+
cache["__assets__"] = {
|
|
273
|
+
hash: `${assetManifest.js}:${assetManifest.css}`,
|
|
274
|
+
mtime: 0,
|
|
275
|
+
builtAt: Date.now()
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
const pluginsConfig = docuConfig.plugins ?? [];
|
|
279
|
+
const builder = pluginsConfig.length > 0 ? new BuildPluginBuilder(docuConfig) : null;
|
|
280
|
+
if (builder) {
|
|
281
|
+
const plugins = await loadPlugins(pluginsConfig);
|
|
282
|
+
for (const plugin of plugins) {
|
|
283
|
+
await plugin.setup(builder);
|
|
284
|
+
}
|
|
285
|
+
await builder.runOnStart();
|
|
286
|
+
}
|
|
287
|
+
logger.spinner.start("Building pages...");
|
|
288
|
+
t = performance.now();
|
|
289
|
+
const allRelPaths = mdxFiles.map((f) => f.absPath.replace(PROJECT_ROOT + "/", ""));
|
|
290
|
+
const indexMdxFull = join2(DOCS_DIR, "index.mdx");
|
|
291
|
+
if (existsSync2(indexMdxFull)) {
|
|
292
|
+
allRelPaths.push(indexMdxFull.replace(PROJECT_ROOT + "/", ""));
|
|
293
|
+
}
|
|
294
|
+
const gitDates = await getGitLastModifiedBatch(allRelPaths);
|
|
295
|
+
const CONCURRENCY = parseConcurrency();
|
|
296
|
+
const buildTasks = [];
|
|
297
|
+
const errors = [];
|
|
298
|
+
for (const file of mdxFiles) {
|
|
299
|
+
const rebuildDecision = shouldRebuild(file.path, file.mtime, cache);
|
|
300
|
+
if (rebuildDecision === "no") {
|
|
301
|
+
const outputPath = join2(DIST_DIR, "docs", `${file.path}.html`);
|
|
302
|
+
if (existsSync2(outputPath) && !assetsChanged) {
|
|
303
|
+
skipped++;
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
let rawMdx;
|
|
308
|
+
try {
|
|
309
|
+
rawMdx = await readFile(file.absPath, "utf-8");
|
|
310
|
+
} catch (err) {
|
|
311
|
+
if (err.code !== "ENOENT") throw err;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (rebuildDecision === "hash_check") {
|
|
315
|
+
const contentHash = hashContent(rawMdx);
|
|
316
|
+
const cached = cache[file.path];
|
|
317
|
+
if (cached && cached.hash === contentHash) {
|
|
318
|
+
if (!assetsChanged) {
|
|
319
|
+
const outputPath = join2(DIST_DIR, "docs", `${file.path}.html`);
|
|
320
|
+
if (existsSync2(outputPath)) {
|
|
321
|
+
cache[file.path] = { ...cached, mtime: file.mtime, builtAt: Date.now() };
|
|
322
|
+
skipped++;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
const relPath = file.absPath.replace(PROJECT_ROOT + "/", "");
|
|
329
|
+
const capturedRawMdx = rawMdx;
|
|
330
|
+
const capturedFile = file;
|
|
331
|
+
buildTasks.push(async () => {
|
|
332
|
+
try {
|
|
333
|
+
const pageNonce = generateNonce();
|
|
334
|
+
const html = await renderDocsPage(
|
|
335
|
+
docuConfig,
|
|
336
|
+
capturedFile.path,
|
|
337
|
+
capturedRawMdx,
|
|
338
|
+
relPath,
|
|
339
|
+
gitDates,
|
|
340
|
+
builder,
|
|
341
|
+
pageNonce
|
|
342
|
+
);
|
|
343
|
+
const outputPath = join2(DIST_DIR, "docs", `${capturedFile.path}.html`);
|
|
344
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
345
|
+
await writeFile(outputPath, html);
|
|
346
|
+
cache[capturedFile.path] = {
|
|
347
|
+
hash: hashContent(capturedRawMdx),
|
|
348
|
+
mtime: capturedFile.mtime,
|
|
349
|
+
builtAt: Date.now()
|
|
350
|
+
};
|
|
351
|
+
built++;
|
|
352
|
+
} catch (err) {
|
|
353
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
354
|
+
errors.push(msg);
|
|
355
|
+
console.error(`
|
|
356
|
+
\u274C ${msg}
|
|
357
|
+
`);
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
for (let i = 0; i < buildTasks.length; i += CONCURRENCY) {
|
|
362
|
+
await Promise.all(buildTasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
const indexMdxPath = join2(DOCS_DIR, "index.mdx");
|
|
366
|
+
const indexRaw = await readFile(indexMdxPath, "utf-8");
|
|
367
|
+
const indexRelPath = indexMdxPath.replace(PROJECT_ROOT + "/", "");
|
|
368
|
+
const indexHtml = await renderDocsPage(
|
|
369
|
+
docuConfig,
|
|
370
|
+
"",
|
|
371
|
+
indexRaw,
|
|
372
|
+
indexRelPath,
|
|
373
|
+
gitDates,
|
|
374
|
+
builder,
|
|
375
|
+
generateNonce()
|
|
376
|
+
);
|
|
377
|
+
await mkdir(join2(DIST_DIR, "docs"), { recursive: true });
|
|
378
|
+
await writeFile(join2(DIST_DIR, "docs", "index.html"), indexHtml);
|
|
379
|
+
} catch (err) {
|
|
380
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
381
|
+
errors.push(`index.mdx: ${msg}`);
|
|
382
|
+
console.error(`
|
|
383
|
+
\u274C Failed to build index: ${msg}
|
|
384
|
+
`);
|
|
385
|
+
}
|
|
386
|
+
const landingPage = React.createElement(IndexPage);
|
|
387
|
+
const landingFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
388
|
+
const landingHtml = htmlShell({
|
|
389
|
+
title: docuConfig.meta?.title || "DocuBook",
|
|
390
|
+
description: docuConfig.meta?.description || "",
|
|
391
|
+
body: renderToString(landingPage),
|
|
392
|
+
favicon: landingFavicon,
|
|
393
|
+
css: assetManifest.css,
|
|
394
|
+
js: assetManifest.js,
|
|
395
|
+
nonce: generateNonce(),
|
|
396
|
+
themeCss: inlineThemeCss
|
|
397
|
+
});
|
|
398
|
+
await writeFile(join2(DIST_DIR, "index.html"), landingHtml);
|
|
399
|
+
const notFoundPage = React.createElement(
|
|
400
|
+
DocsLayout,
|
|
401
|
+
{ repoUrl: docuConfig.repo?.url },
|
|
402
|
+
React.createElement(NotFoundPage)
|
|
403
|
+
);
|
|
404
|
+
const notFoundFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
405
|
+
const notFoundHtml = htmlShell({
|
|
406
|
+
title: "404 - Not Found",
|
|
407
|
+
description: "",
|
|
408
|
+
body: renderToString(notFoundPage),
|
|
409
|
+
favicon: notFoundFavicon,
|
|
410
|
+
css: assetManifest.css,
|
|
411
|
+
js: assetManifest.js,
|
|
412
|
+
nonce: generateNonce(),
|
|
413
|
+
themeCss: inlineThemeCss
|
|
414
|
+
});
|
|
415
|
+
await writeFile(join2(DIST_DIR, "404.html"), notFoundHtml);
|
|
416
|
+
logger.spinner.stop(
|
|
417
|
+
`Built ${built} pages (${skipped} cached) \x1B[90m(${Math.round(performance.now() - t)}ms)\x1B[0m`
|
|
418
|
+
);
|
|
419
|
+
if (builder) {
|
|
420
|
+
const pages = mdxFiles.map((f) => ({
|
|
421
|
+
slug: f.path,
|
|
422
|
+
title: f.path.split("/").pop() || f.path,
|
|
423
|
+
filePath: join2(DOCS_DIR, f.path),
|
|
424
|
+
outputPath: join2(DIST_DIR, "docs", `${f.path}.html`)
|
|
425
|
+
}));
|
|
426
|
+
await builder.runOnEnd(pages);
|
|
427
|
+
}
|
|
428
|
+
logger.indexStart();
|
|
429
|
+
t = performance.now();
|
|
430
|
+
const indexCount = await generateSearchIndex();
|
|
431
|
+
logger.indexDone(indexCount, Math.round(performance.now() - t));
|
|
432
|
+
logger.routes();
|
|
433
|
+
console.log("");
|
|
434
|
+
const buildSummary = await generateBuildSummary(DIST_DIR);
|
|
435
|
+
if (buildSummary) {
|
|
436
|
+
console.log(buildSummary);
|
|
437
|
+
console.log("");
|
|
438
|
+
}
|
|
439
|
+
await writeCache(cache);
|
|
440
|
+
if (errors.length > 0) {
|
|
441
|
+
console.error(`
|
|
442
|
+
\u274C Build completed with ${errors.length} error(s)
|
|
443
|
+
`);
|
|
444
|
+
process.exit(1);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
async function runBuildCli() {
|
|
448
|
+
try {
|
|
449
|
+
await initSentry();
|
|
450
|
+
await runBuild();
|
|
451
|
+
} catch (err) {
|
|
452
|
+
captureException(err);
|
|
453
|
+
console.error("Build failed:", err);
|
|
454
|
+
process.exit(1);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
export {
|
|
459
|
+
runBuild,
|
|
460
|
+
runBuildCli
|
|
461
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DIST_DIR,
|
|
3
|
+
PROJECT_ROOT
|
|
4
|
+
} from "./chunk-J5NMYSBJ.js";
|
|
5
|
+
|
|
6
|
+
// .docu/node/deploy.shared.ts
|
|
7
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
var WORKFLOW_DIR = join(PROJECT_ROOT, ".github/workflows");
|
|
11
|
+
var WORKFLOW_FILE = join(WORKFLOW_DIR, "deploy.yml");
|
|
12
|
+
async function runDeploy() {
|
|
13
|
+
console.log("\u{1F4E6} Building for production...\n");
|
|
14
|
+
process.env.NODE_ENV = "production";
|
|
15
|
+
const { runBuildCli } = await import("./build.impl-ST63VRTV.js");
|
|
16
|
+
await runBuildCli();
|
|
17
|
+
await writeFile(join(DIST_DIR, ".nojekyll"), "");
|
|
18
|
+
if (!existsSync(WORKFLOW_FILE)) {
|
|
19
|
+
await mkdir(WORKFLOW_DIR, { recursive: true });
|
|
20
|
+
await writeFile(WORKFLOW_FILE, GITHUB_ACTIONS_WORKFLOW);
|
|
21
|
+
console.log("\n\u{1F4C4} Created .github/workflows/deploy.yml");
|
|
22
|
+
}
|
|
23
|
+
console.log("\n\u2705 Ready to deploy!");
|
|
24
|
+
console.log(" Output: .docu/dist/");
|
|
25
|
+
console.log(" Push to GitHub and enable Pages (Settings \u2192 Pages \u2192 Source: GitHub Actions)");
|
|
26
|
+
}
|
|
27
|
+
var GITHUB_ACTIONS_WORKFLOW = `name: Deploy to GitHub Pages
|
|
28
|
+
|
|
29
|
+
on:
|
|
30
|
+
push:
|
|
31
|
+
branches: [main]
|
|
32
|
+
workflow_dispatch:
|
|
33
|
+
|
|
34
|
+
permissions:
|
|
35
|
+
contents: read
|
|
36
|
+
pages: write
|
|
37
|
+
id-token: write
|
|
38
|
+
|
|
39
|
+
concurrency:
|
|
40
|
+
group: "pages"
|
|
41
|
+
cancel-in-progress: false
|
|
42
|
+
|
|
43
|
+
jobs:
|
|
44
|
+
build:
|
|
45
|
+
runs-on: ubuntu-latest
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v4
|
|
48
|
+
with:
|
|
49
|
+
fetch-depth: 0
|
|
50
|
+
|
|
51
|
+
- uses: actions/setup-node@v4
|
|
52
|
+
with:
|
|
53
|
+
node-version: 22
|
|
54
|
+
|
|
55
|
+
- run: npm install
|
|
56
|
+
|
|
57
|
+
- run: npm run build
|
|
58
|
+
|
|
59
|
+
- name: Add .nojekyll
|
|
60
|
+
run: touch .docu/dist/.nojekyll
|
|
61
|
+
|
|
62
|
+
- uses: actions/upload-pages-artifact@v3
|
|
63
|
+
with:
|
|
64
|
+
path: .docu/dist
|
|
65
|
+
|
|
66
|
+
deploy:
|
|
67
|
+
environment:
|
|
68
|
+
name: github-pages
|
|
69
|
+
url: \${{ steps.deployment.outputs.page_url }}
|
|
70
|
+
runs-on: ubuntu-latest
|
|
71
|
+
needs: build
|
|
72
|
+
steps:
|
|
73
|
+
- id: deployment
|
|
74
|
+
uses: actions/deploy-pages@v4
|
|
75
|
+
`;
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
runDeploy
|
|
79
|
+
};
|