@docubook/flame 1.4.4 → 1.5.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/.docu/lib/build.deno.js +11 -0
- package/.docu/lib/build.impl-7KJ4ZTAJ.js +12 -0
- package/.docu/lib/build.node.js +10 -0
- package/.docu/lib/chunk-7ZEUL6PR.js +383 -0
- package/.docu/lib/chunk-AI7QAMMZ.js +2410 -0
- package/.docu/lib/chunk-E4OIJWCU.js +368 -0
- package/.docu/lib/chunk-IR5TVJOV.js +79 -0
- package/.docu/lib/chunk-J5NMYSBJ.js +59 -0
- package/.docu/lib/chunk-PTRZ2S2C.js +298 -0
- package/.docu/lib/chunk-RE4NGTMT.js +185 -0
- package/.docu/lib/chunk-TE52TIEW.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.deno.ts +7 -0
- package/.docu/node/build.impl.ts +416 -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/hydrate.node.ts +276 -0
- package/.docu/node/hydrate.ts +17 -31
- 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 +99 -14
- package/bin/compile-lib.mjs +67 -0
- package/package.json +9 -7
- 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,368 @@
|
|
|
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-AI7QAMMZ.js";
|
|
17
|
+
import {
|
|
18
|
+
generateNonce,
|
|
19
|
+
scanMdxFiles
|
|
20
|
+
} from "./chunk-RE4NGTMT.js";
|
|
21
|
+
import {
|
|
22
|
+
logger
|
|
23
|
+
} from "./chunk-PTRZ2S2C.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, copyFile } from "node:fs/promises";
|
|
36
|
+
import { existsSync } from "node:fs";
|
|
37
|
+
import { createHash } from "node:crypto";
|
|
38
|
+
import { join, dirname } from "node:path";
|
|
39
|
+
import React from "react";
|
|
40
|
+
import { renderToString } from "react-dom/server";
|
|
41
|
+
function parseArgs() {
|
|
42
|
+
const args = process.argv.slice(2);
|
|
43
|
+
return {
|
|
44
|
+
force: args.includes("--force") || args.includes("-f"),
|
|
45
|
+
clean: args.includes("--clean") || args.includes("-c")
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function hashContent(content) {
|
|
49
|
+
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
50
|
+
}
|
|
51
|
+
async function readCache() {
|
|
52
|
+
try {
|
|
53
|
+
if (existsSync(CACHE_FILE)) {
|
|
54
|
+
const data = await readFile(CACHE_FILE, "utf-8");
|
|
55
|
+
return JSON.parse(data);
|
|
56
|
+
}
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.error("Failed to load build cache:", err.message);
|
|
59
|
+
}
|
|
60
|
+
return {};
|
|
61
|
+
}
|
|
62
|
+
async function writeCache(cache) {
|
|
63
|
+
await writeFile(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
64
|
+
}
|
|
65
|
+
function parseConcurrency() {
|
|
66
|
+
return Math.max(1, parseInt(process.env.BUILD_CONCURRENCY || "4", 10) || 4);
|
|
67
|
+
}
|
|
68
|
+
function shouldRebuild(path, mtime, cache) {
|
|
69
|
+
const cached = cache[path];
|
|
70
|
+
if (!cached) return "yes";
|
|
71
|
+
if (mtime > cached.builtAt) return "hash_check";
|
|
72
|
+
return "no";
|
|
73
|
+
}
|
|
74
|
+
var assetManifest = { js: "client.js", css: "client.css" };
|
|
75
|
+
var inlineThemeCss;
|
|
76
|
+
async function renderDocsPage(docuConfig, slug, rawMdx, filePath, gitDates, builder, nonce) {
|
|
77
|
+
let content = rawMdx;
|
|
78
|
+
if (builder) {
|
|
79
|
+
const transformed = await builder.runOnLoad(filePath, content);
|
|
80
|
+
if (transformed?.contents) {
|
|
81
|
+
content = transformed.contents;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
let result;
|
|
85
|
+
try {
|
|
86
|
+
const remarkPlugins = builder?.collectRemarkPlugins();
|
|
87
|
+
const rehypePlugins = builder?.collectRehypePlugins();
|
|
88
|
+
result = await compileMdx(content, filePath, gitDates, remarkPlugins, rehypePlugins);
|
|
89
|
+
} catch (err) {
|
|
90
|
+
const msg = err instanceof Error ? err.message : "Unknown MDX error";
|
|
91
|
+
throw new Error(`MDX Error in: docs/${slug}.mdx
|
|
92
|
+
${msg}`, { cause: err });
|
|
93
|
+
}
|
|
94
|
+
let frontmatter = result.frontmatter;
|
|
95
|
+
if (builder) {
|
|
96
|
+
frontmatter = await builder.runTransformFrontmatterChain(frontmatter, {
|
|
97
|
+
slug,
|
|
98
|
+
filePath,
|
|
99
|
+
content
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
const title = (typeof frontmatter.title === "string" ? frontmatter.title : "") || slug || "Docs";
|
|
103
|
+
const description = typeof frontmatter.description === "string" ? frontmatter.description : "";
|
|
104
|
+
const slugParts = slug ? slug.split("/") : [];
|
|
105
|
+
const page = React.createElement(
|
|
106
|
+
DocsLayout,
|
|
107
|
+
{ repoUrl: docuConfig.repo?.url },
|
|
108
|
+
React.createElement(DocsPage, {
|
|
109
|
+
slug: slugParts,
|
|
110
|
+
title,
|
|
111
|
+
description,
|
|
112
|
+
date: frontmatter.date || void 0,
|
|
113
|
+
content: result.content,
|
|
114
|
+
tocs: result.tocs,
|
|
115
|
+
filePath,
|
|
116
|
+
repoUrl: docuConfig.repo?.url,
|
|
117
|
+
compiledSource: result.compiledSource
|
|
118
|
+
})
|
|
119
|
+
);
|
|
120
|
+
const body = renderToString(page);
|
|
121
|
+
const ctx = { slug, filePath, frontmatter, content, config: docuConfig };
|
|
122
|
+
const headExtra = builder?.collectHead(ctx);
|
|
123
|
+
const bodyExtra = builder?.collectBody(ctx);
|
|
124
|
+
const depth = slug ? slug.split("/").length : 1;
|
|
125
|
+
const favicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
126
|
+
let html = htmlShell({
|
|
127
|
+
title,
|
|
128
|
+
description,
|
|
129
|
+
body,
|
|
130
|
+
favicon,
|
|
131
|
+
css: assetManifest.css,
|
|
132
|
+
js: assetManifest.js,
|
|
133
|
+
nonce,
|
|
134
|
+
themeCss: inlineThemeCss,
|
|
135
|
+
depth,
|
|
136
|
+
headExtra,
|
|
137
|
+
bodyExtra
|
|
138
|
+
});
|
|
139
|
+
if (builder) {
|
|
140
|
+
html = await builder.runTransformHtmlChain(html, ctx);
|
|
141
|
+
}
|
|
142
|
+
return html;
|
|
143
|
+
}
|
|
144
|
+
async function copyDirectoryRecursive(src, dest) {
|
|
145
|
+
if (!existsSync(src)) return;
|
|
146
|
+
await mkdir(dest, { recursive: true });
|
|
147
|
+
const entries = await readdir(src, { withFileTypes: true });
|
|
148
|
+
for (const entry of entries) {
|
|
149
|
+
const srcPath = join(src, entry.name);
|
|
150
|
+
const destPath = join(dest, entry.name);
|
|
151
|
+
if (entry.isDirectory()) {
|
|
152
|
+
await copyDirectoryRecursive(srcPath, destPath);
|
|
153
|
+
} else {
|
|
154
|
+
await copyFile(srcPath, destPath);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function runBuild() {
|
|
159
|
+
const docuConfig = loadDocuConfig();
|
|
160
|
+
const args = parseArgs();
|
|
161
|
+
logger.buildStart();
|
|
162
|
+
if (args.clean) {
|
|
163
|
+
const { rm } = await import("node:fs/promises");
|
|
164
|
+
try {
|
|
165
|
+
await rm(DIST_DIR, { recursive: true, force: true });
|
|
166
|
+
} catch (err) {
|
|
167
|
+
console.error("Failed to clean dist directory:", err.message);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
await mkdir(DIST_DIR, { recursive: true });
|
|
171
|
+
await mkdir(ASSETS_DIR, { recursive: true });
|
|
172
|
+
await copyDirectoryRecursive(DOCS_ASSETS_DIR, join(DIST_DIR, "docs", "assets"));
|
|
173
|
+
const mdxFiles = await scanMdxFiles(DOCS_DIR);
|
|
174
|
+
const cache = args.force ? {} : await readCache();
|
|
175
|
+
let built = 0;
|
|
176
|
+
let skipped = 0;
|
|
177
|
+
logger.bundleStart();
|
|
178
|
+
let t = performance.now();
|
|
179
|
+
assetManifest = await buildClientBundle();
|
|
180
|
+
logger.bundleDone(Math.round(performance.now() - t));
|
|
181
|
+
inlineThemeCss = computeInlineThemeCss();
|
|
182
|
+
const lastManifest = cache["__assets__"];
|
|
183
|
+
const assetsChanged = !lastManifest || lastManifest.hash !== `${assetManifest.js}:${assetManifest.css}`;
|
|
184
|
+
if (assetsChanged) {
|
|
185
|
+
cache["__assets__"] = {
|
|
186
|
+
hash: `${assetManifest.js}:${assetManifest.css}`,
|
|
187
|
+
mtime: 0,
|
|
188
|
+
builtAt: Date.now()
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
const pluginsConfig = docuConfig.plugins ?? [];
|
|
192
|
+
const builder = pluginsConfig.length > 0 ? new BuildPluginBuilder(docuConfig) : null;
|
|
193
|
+
if (builder) {
|
|
194
|
+
const plugins = await loadPlugins(pluginsConfig);
|
|
195
|
+
for (const plugin of plugins) {
|
|
196
|
+
await plugin.setup(builder);
|
|
197
|
+
}
|
|
198
|
+
await builder.runOnStart();
|
|
199
|
+
}
|
|
200
|
+
logger.spinner.start("Building pages...");
|
|
201
|
+
t = performance.now();
|
|
202
|
+
const allRelPaths = mdxFiles.map((f) => f.absPath.replace(PROJECT_ROOT + "/", ""));
|
|
203
|
+
const indexMdxFull = join(DOCS_DIR, "index.mdx");
|
|
204
|
+
if (existsSync(indexMdxFull)) {
|
|
205
|
+
allRelPaths.push(indexMdxFull.replace(PROJECT_ROOT + "/", ""));
|
|
206
|
+
}
|
|
207
|
+
const gitDates = await getGitLastModifiedBatch(allRelPaths);
|
|
208
|
+
const CONCURRENCY = parseConcurrency();
|
|
209
|
+
const buildTasks = [];
|
|
210
|
+
const errors = [];
|
|
211
|
+
for (const file of mdxFiles) {
|
|
212
|
+
const rebuildDecision = shouldRebuild(file.path, file.mtime, cache);
|
|
213
|
+
if (rebuildDecision === "no") {
|
|
214
|
+
const outputPath = join(DIST_DIR, "docs", `${file.path}.html`);
|
|
215
|
+
if (existsSync(outputPath) && !assetsChanged) {
|
|
216
|
+
skipped++;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
let rawMdx;
|
|
221
|
+
try {
|
|
222
|
+
rawMdx = await readFile(file.absPath, "utf-8");
|
|
223
|
+
} catch (err) {
|
|
224
|
+
if (err.code !== "ENOENT") throw err;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (rebuildDecision === "hash_check") {
|
|
228
|
+
const contentHash = hashContent(rawMdx);
|
|
229
|
+
const cached = cache[file.path];
|
|
230
|
+
if (cached && cached.hash === contentHash) {
|
|
231
|
+
if (!assetsChanged) {
|
|
232
|
+
const outputPath = join(DIST_DIR, "docs", `${file.path}.html`);
|
|
233
|
+
if (existsSync(outputPath)) {
|
|
234
|
+
cache[file.path] = { ...cached, mtime: file.mtime, builtAt: Date.now() };
|
|
235
|
+
skipped++;
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
const relPath = file.absPath.replace(PROJECT_ROOT + "/", "");
|
|
242
|
+
const capturedRawMdx = rawMdx;
|
|
243
|
+
const capturedFile = file;
|
|
244
|
+
buildTasks.push(async () => {
|
|
245
|
+
try {
|
|
246
|
+
const pageNonce = generateNonce();
|
|
247
|
+
const html = await renderDocsPage(
|
|
248
|
+
docuConfig,
|
|
249
|
+
capturedFile.path,
|
|
250
|
+
capturedRawMdx,
|
|
251
|
+
relPath,
|
|
252
|
+
gitDates,
|
|
253
|
+
builder,
|
|
254
|
+
pageNonce
|
|
255
|
+
);
|
|
256
|
+
const outputPath = join(DIST_DIR, "docs", `${capturedFile.path}.html`);
|
|
257
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
258
|
+
await writeFile(outputPath, html);
|
|
259
|
+
cache[capturedFile.path] = {
|
|
260
|
+
hash: hashContent(capturedRawMdx),
|
|
261
|
+
mtime: capturedFile.mtime,
|
|
262
|
+
builtAt: Date.now()
|
|
263
|
+
};
|
|
264
|
+
built++;
|
|
265
|
+
} catch (err) {
|
|
266
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
267
|
+
errors.push(msg);
|
|
268
|
+
console.error(`
|
|
269
|
+
\u274C ${msg}
|
|
270
|
+
`);
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
for (let i = 0; i < buildTasks.length; i += CONCURRENCY) {
|
|
275
|
+
await Promise.all(buildTasks.slice(i, i + CONCURRENCY).map((fn) => fn()));
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
const indexMdxPath = join(DOCS_DIR, "index.mdx");
|
|
279
|
+
const indexRaw = await readFile(indexMdxPath, "utf-8");
|
|
280
|
+
const indexRelPath = indexMdxPath.replace(PROJECT_ROOT + "/", "");
|
|
281
|
+
const indexHtml = await renderDocsPage(
|
|
282
|
+
docuConfig,
|
|
283
|
+
"",
|
|
284
|
+
indexRaw,
|
|
285
|
+
indexRelPath,
|
|
286
|
+
gitDates,
|
|
287
|
+
builder,
|
|
288
|
+
generateNonce()
|
|
289
|
+
);
|
|
290
|
+
await mkdir(join(DIST_DIR, "docs"), { recursive: true });
|
|
291
|
+
await writeFile(join(DIST_DIR, "docs", "index.html"), indexHtml);
|
|
292
|
+
} catch (err) {
|
|
293
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
294
|
+
errors.push(`index.mdx: ${msg}`);
|
|
295
|
+
console.error(`
|
|
296
|
+
\u274C Failed to build index: ${msg}
|
|
297
|
+
`);
|
|
298
|
+
}
|
|
299
|
+
const landingPage = React.createElement(IndexPage);
|
|
300
|
+
const landingFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
301
|
+
const landingHtml = htmlShell({
|
|
302
|
+
title: docuConfig.meta?.title || "DocuBook",
|
|
303
|
+
description: docuConfig.meta?.description || "",
|
|
304
|
+
body: renderToString(landingPage),
|
|
305
|
+
favicon: landingFavicon,
|
|
306
|
+
css: assetManifest.css,
|
|
307
|
+
js: assetManifest.js,
|
|
308
|
+
nonce: generateNonce(),
|
|
309
|
+
themeCss: inlineThemeCss
|
|
310
|
+
});
|
|
311
|
+
await writeFile(join(DIST_DIR, "index.html"), landingHtml);
|
|
312
|
+
const notFoundPage = React.createElement(
|
|
313
|
+
DocsLayout,
|
|
314
|
+
{ repoUrl: docuConfig.repo?.url },
|
|
315
|
+
React.createElement(NotFoundPage)
|
|
316
|
+
);
|
|
317
|
+
const notFoundFavicon = docuConfig.meta?.favicon || "/docs/assets/images/favicon.ico";
|
|
318
|
+
const notFoundHtml = htmlShell({
|
|
319
|
+
title: "404 - Not Found",
|
|
320
|
+
description: "",
|
|
321
|
+
body: renderToString(notFoundPage),
|
|
322
|
+
favicon: notFoundFavicon,
|
|
323
|
+
css: assetManifest.css,
|
|
324
|
+
js: assetManifest.js,
|
|
325
|
+
nonce: generateNonce(),
|
|
326
|
+
themeCss: inlineThemeCss
|
|
327
|
+
});
|
|
328
|
+
await writeFile(join(DIST_DIR, "404.html"), notFoundHtml);
|
|
329
|
+
logger.spinner.stop(
|
|
330
|
+
`Built ${built} pages (${skipped} cached) \x1B[90m(${Math.round(performance.now() - t)}ms)\x1B[0m`
|
|
331
|
+
);
|
|
332
|
+
if (builder) {
|
|
333
|
+
const pages = mdxFiles.map((f) => ({
|
|
334
|
+
slug: f.path,
|
|
335
|
+
title: f.path.split("/").pop() || f.path,
|
|
336
|
+
filePath: join(DOCS_DIR, f.path),
|
|
337
|
+
outputPath: join(DIST_DIR, "docs", `${f.path}.html`)
|
|
338
|
+
}));
|
|
339
|
+
await builder.runOnEnd(pages);
|
|
340
|
+
}
|
|
341
|
+
logger.indexStart();
|
|
342
|
+
t = performance.now();
|
|
343
|
+
const indexCount = await generateSearchIndex();
|
|
344
|
+
logger.indexDone(indexCount, Math.round(performance.now() - t));
|
|
345
|
+
logger.routes();
|
|
346
|
+
await writeCache(cache);
|
|
347
|
+
if (errors.length > 0) {
|
|
348
|
+
console.error(`
|
|
349
|
+
\u274C Build completed with ${errors.length} error(s)
|
|
350
|
+
`);
|
|
351
|
+
process.exit(1);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
async function runBuildCli() {
|
|
355
|
+
try {
|
|
356
|
+
await initSentry();
|
|
357
|
+
await runBuild();
|
|
358
|
+
} catch (err) {
|
|
359
|
+
captureException(err);
|
|
360
|
+
console.error("Build failed:", err);
|
|
361
|
+
process.exit(1);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
export {
|
|
366
|
+
runBuild,
|
|
367
|
+
runBuildCli
|
|
368
|
+
};
|
|
@@ -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-7KJ4ZTAJ.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
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// .docu/node/paths.ts
|
|
2
|
+
import { resolve, join } from "node:path";
|
|
3
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { readdir, rm, unlink } from "node:fs/promises";
|
|
5
|
+
var FRAMEWORK_ROOT = resolve(import.meta.dirname, "../..");
|
|
6
|
+
var PROJECT_ROOT = process.cwd();
|
|
7
|
+
var PAGES_DIR = join(FRAMEWORK_ROOT, ".docu/pages");
|
|
8
|
+
var STYLES_DIR = join(FRAMEWORK_ROOT, ".docu/styles");
|
|
9
|
+
var nodeDir = join(FRAMEWORK_ROOT, ".docu/node");
|
|
10
|
+
var libDir = join(FRAMEWORK_ROOT, ".docu/lib");
|
|
11
|
+
var LIB_DIR = existsSync(nodeDir) ? nodeDir : libDir;
|
|
12
|
+
var DIST_DIR = join(PROJECT_ROOT, ".docu/dist");
|
|
13
|
+
var ASSETS_DIR = join(DIST_DIR, "assets");
|
|
14
|
+
var CACHE_FILE = join(PROJECT_ROOT, ".docu/build-cache.json");
|
|
15
|
+
var DOCS_DIR = join(PROJECT_ROOT, "docs");
|
|
16
|
+
var DOCS_ASSETS_DIR = join(PROJECT_ROOT, "docs/assets");
|
|
17
|
+
var DOCU_CONFIG_PATH = join(PROJECT_ROOT, "docu.json");
|
|
18
|
+
var _config = null;
|
|
19
|
+
async function cleanOldBundles() {
|
|
20
|
+
try {
|
|
21
|
+
const files = await readdir(ASSETS_DIR);
|
|
22
|
+
for (const file of files) {
|
|
23
|
+
if (file.startsWith("client.") || file.startsWith("client-")) {
|
|
24
|
+
await unlink(join(ASSETS_DIR, file));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err.code !== "ENOENT") {
|
|
29
|
+
console.error("Failed to clean old bundles:", err.message);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
await rm(join(ASSETS_DIR, "chunks"), { recursive: true, force: true });
|
|
34
|
+
} catch (err) {
|
|
35
|
+
console.error("Failed to clean old chunks:", err.message);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function loadDocuConfig() {
|
|
39
|
+
if (_config) return _config;
|
|
40
|
+
if (!existsSync(DOCU_CONFIG_PATH)) {
|
|
41
|
+
throw new Error(`docu.json not found at ${DOCU_CONFIG_PATH}`);
|
|
42
|
+
}
|
|
43
|
+
_config = JSON.parse(readFileSync(DOCU_CONFIG_PATH, "utf-8"));
|
|
44
|
+
return _config;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export {
|
|
48
|
+
FRAMEWORK_ROOT,
|
|
49
|
+
PROJECT_ROOT,
|
|
50
|
+
STYLES_DIR,
|
|
51
|
+
LIB_DIR,
|
|
52
|
+
DIST_DIR,
|
|
53
|
+
ASSETS_DIR,
|
|
54
|
+
CACHE_FILE,
|
|
55
|
+
DOCS_DIR,
|
|
56
|
+
DOCS_ASSETS_DIR,
|
|
57
|
+
cleanOldBundles,
|
|
58
|
+
loadDocuConfig
|
|
59
|
+
};
|