defuss-ssg 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +289 -0
- package/dist/cli.cjs +47 -0
- package/dist/cli.mjs +46 -0
- package/dist/components/index.cjs +27 -0
- package/dist/components/index.d.cts +10 -0
- package/dist/components/index.d.mts +10 -0
- package/dist/components/index.mjs +25 -0
- package/dist/index.cjs +28 -0
- package/dist/index.d.cts +25 -0
- package/dist/index.d.mts +25 -0
- package/dist/index.mjs +17 -0
- package/dist/plugins/index.cjs +8 -0
- package/dist/plugins/index.d.cts +7 -0
- package/dist/plugins/index.d.mts +7 -0
- package/dist/plugins/index.mjs +2 -0
- package/dist/runtime.cjs +26 -0
- package/dist/runtime.d.cts +3 -0
- package/dist/runtime.d.mts +3 -0
- package/dist/runtime.mjs +24 -0
- package/dist/serve-BaOtT5p7.cjs +374 -0
- package/dist/serve-COHw7ASj.mjs +366 -0
- package/dist/tailwind-C4AuHybm.cjs +14 -0
- package/dist/tailwind-DV23JSh-.mjs +12 -0
- package/dist/types-D1n7GtYH.d.ts +101 -0
- package/package.json +98 -0
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import chokidar from 'chokidar';
|
|
2
|
+
import express from 'express';
|
|
3
|
+
import serveStatic from 'serve-static';
|
|
4
|
+
import { join, resolve, dirname, sep } from 'node:path';
|
|
5
|
+
import { existsSync, rmdirSync, mkdirSync } from 'node:fs';
|
|
6
|
+
import esbuild from 'esbuild';
|
|
7
|
+
import remarkFrontmatter from 'remark-frontmatter';
|
|
8
|
+
import rehypeKatex from 'rehype-katex';
|
|
9
|
+
import remarkMath from 'remark-math';
|
|
10
|
+
import remarkMdxFrontmatter from 'remark-mdx-frontmatter';
|
|
11
|
+
import { t as tailwindPlugin } from './tailwind-DV23JSh-.mjs';
|
|
12
|
+
import mdx from '@mdx-js/esbuild';
|
|
13
|
+
import glob from 'fast-glob';
|
|
14
|
+
import { getBrowserGlobals, getDocument, renderSync, renderToString } from 'defuss/server';
|
|
15
|
+
import { cp, readFile, writeFile } from 'node:fs/promises';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
|
|
18
|
+
const remarkPlugins = [
|
|
19
|
+
// Parse both YAML and TOML (or omit options to default to YAML)
|
|
20
|
+
[remarkFrontmatter, ["yaml", "toml"]],
|
|
21
|
+
// Export each key as an ESM binding: export const title = "…"
|
|
22
|
+
[remarkMdxFrontmatter, { name: "meta" }],
|
|
23
|
+
// Convert $…$ and $$…$$ into math nodes for KaTeX
|
|
24
|
+
remarkMath
|
|
25
|
+
];
|
|
26
|
+
const rehypePlugins = [
|
|
27
|
+
//rehypeMdxTitle,
|
|
28
|
+
rehypeKatex
|
|
29
|
+
];
|
|
30
|
+
|
|
31
|
+
const readConfig = async (projectDir, debug) => {
|
|
32
|
+
const configPath = join(projectDir, "config.ts");
|
|
33
|
+
let config = {};
|
|
34
|
+
if (existsSync(configPath)) {
|
|
35
|
+
if (debug) {
|
|
36
|
+
console.log(`Using config from ${configPath}`);
|
|
37
|
+
}
|
|
38
|
+
const result = await esbuild.build({
|
|
39
|
+
entryPoints: [configPath],
|
|
40
|
+
format: "esm",
|
|
41
|
+
bundle: true,
|
|
42
|
+
target: ["esnext"],
|
|
43
|
+
write: false
|
|
44
|
+
});
|
|
45
|
+
const code = result.outputFiles[0].text;
|
|
46
|
+
const encoded = Buffer.from(code).toString("base64");
|
|
47
|
+
const dataUrl = `data:text/javascript;base64,${encoded}`;
|
|
48
|
+
const module = await import(dataUrl);
|
|
49
|
+
config = module.default;
|
|
50
|
+
}
|
|
51
|
+
config.pages = config.pages || configDefaults.pages;
|
|
52
|
+
config.output = config.output || configDefaults.output;
|
|
53
|
+
config.components = config.components || configDefaults.components;
|
|
54
|
+
config.assets = config.assets || configDefaults.assets;
|
|
55
|
+
config.plugins = config.plugins || configDefaults.plugins;
|
|
56
|
+
config.tmp = config.tmp || configDefaults.tmp;
|
|
57
|
+
config.remarkPlugins = config.remarkPlugins || configDefaults.remarkPlugins;
|
|
58
|
+
config.rehypePlugins = config.rehypePlugins || configDefaults.rehypePlugins;
|
|
59
|
+
return config;
|
|
60
|
+
};
|
|
61
|
+
const configDefaults = {
|
|
62
|
+
pages: "pages",
|
|
63
|
+
output: "dist",
|
|
64
|
+
components: "components",
|
|
65
|
+
assets: "assets",
|
|
66
|
+
tmp: ".ssg-temp",
|
|
67
|
+
plugins: [tailwindPlugin],
|
|
68
|
+
remarkPlugins,
|
|
69
|
+
rehypePlugins
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
73
|
+
const __dirname = dirname(__filename);
|
|
74
|
+
const build = async ({
|
|
75
|
+
projectDir,
|
|
76
|
+
debug = false,
|
|
77
|
+
mode = "build"
|
|
78
|
+
}) => {
|
|
79
|
+
const startTime = performance.now();
|
|
80
|
+
const config = await readConfig(projectDir, debug);
|
|
81
|
+
if (debug) {
|
|
82
|
+
console.log("PRE config", config);
|
|
83
|
+
}
|
|
84
|
+
if (debug) {
|
|
85
|
+
console.log("Using config:", config);
|
|
86
|
+
}
|
|
87
|
+
const inputPagesDir = join(projectDir, config.pages);
|
|
88
|
+
const inputComponentsDir = join(projectDir, config.components);
|
|
89
|
+
const inputAssetsDir = join(projectDir, config.assets);
|
|
90
|
+
const tmpPagesDir = join(config.tmp, config.pages);
|
|
91
|
+
const tmpComponentsDir = join(config.tmp, config.components);
|
|
92
|
+
const outputProjectDir = join(projectDir, config.output);
|
|
93
|
+
const outputPagesDir = join(projectDir, config.output, config.pages);
|
|
94
|
+
const outputComponentsDir = join(
|
|
95
|
+
projectDir,
|
|
96
|
+
config.output,
|
|
97
|
+
config.components
|
|
98
|
+
);
|
|
99
|
+
const outputAssetsDir = join(projectDir, config.output, config.assets);
|
|
100
|
+
if (debug) {
|
|
101
|
+
console.log("Input pages dir:", inputPagesDir);
|
|
102
|
+
console.log("Input components dir:", inputComponentsDir);
|
|
103
|
+
console.log("Input assets dir:", inputAssetsDir);
|
|
104
|
+
console.log("Temp pages dir:", tmpPagesDir);
|
|
105
|
+
console.log("Temp components dir:", tmpComponentsDir);
|
|
106
|
+
console.log("Output pages dir:", outputPagesDir);
|
|
107
|
+
console.log("Output components dir:", outputComponentsDir);
|
|
108
|
+
console.log("Output assets dir:", outputAssetsDir);
|
|
109
|
+
}
|
|
110
|
+
if (!existsSync(inputPagesDir)) {
|
|
111
|
+
throw new Error(`Input pages directory does not exist: ${inputPagesDir}`);
|
|
112
|
+
} else if (debug) {
|
|
113
|
+
console.log(`Input pages directory exists: ${inputPagesDir}`);
|
|
114
|
+
}
|
|
115
|
+
if (!existsSync(inputComponentsDir)) {
|
|
116
|
+
console.warn(
|
|
117
|
+
`There is no components directory: ${inputComponentsDir}. You may not be able to use any custom components.`
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
if (!existsSync(inputAssetsDir)) {
|
|
121
|
+
console.warn(
|
|
122
|
+
`There is no assets directory: ${inputAssetsDir}. You may not be able to serve any custom assets.`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
for (const plugin of config.plugins || []) {
|
|
126
|
+
if (plugin.phase === "pre" && (plugin.mode === mode || plugin.mode === "both")) {
|
|
127
|
+
if (debug) {
|
|
128
|
+
console.log(`Running pre-plugin: ${plugin.name}`);
|
|
129
|
+
}
|
|
130
|
+
await plugin.fn(projectDir, config);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (existsSync(config.tmp)) {
|
|
134
|
+
if (debug) {
|
|
135
|
+
console.log(`Removing existing temp folder: ${config.tmp}`);
|
|
136
|
+
}
|
|
137
|
+
rmdirSync(config.tmp, { recursive: true });
|
|
138
|
+
}
|
|
139
|
+
await cp(projectDir, config.tmp, {
|
|
140
|
+
recursive: true,
|
|
141
|
+
filter: (src) => {
|
|
142
|
+
const relative = src.replace(join(projectDir, ""), "");
|
|
143
|
+
if (relative.startsWith(join("assets", "")) || relative.startsWith(join("node_modules", ""))) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
await cp(
|
|
150
|
+
// because of this the packaging of defuss-ssg must be done with "files" including the "components" folder
|
|
151
|
+
// in a built situation, __dirname is the dist folder of defuss-ssg
|
|
152
|
+
resolve(join(__dirname, "components", "index.mjs")),
|
|
153
|
+
// dist folder
|
|
154
|
+
join(tmpComponentsDir, "hydrate.tsx")
|
|
155
|
+
// a valid JS is always a valid TS file
|
|
156
|
+
);
|
|
157
|
+
await cp(
|
|
158
|
+
// because of this the packaging of defuss-ssg must be done with "files" including the "runtime" file
|
|
159
|
+
// in a built situation, __dirname is the dist folder of defuss-ssg
|
|
160
|
+
resolve(join(__dirname, "runtime.mjs")),
|
|
161
|
+
// dist folder
|
|
162
|
+
join(tmpComponentsDir, "runtime.ts")
|
|
163
|
+
// a valid JS is always a valid TS file
|
|
164
|
+
);
|
|
165
|
+
await esbuild.build({
|
|
166
|
+
entryPoints: [join(tmpPagesDir, "**/*.mdx")],
|
|
167
|
+
format: "esm",
|
|
168
|
+
bundle: true,
|
|
169
|
+
sourcemap: true,
|
|
170
|
+
target: ["esnext"],
|
|
171
|
+
outdir: tmpPagesDir,
|
|
172
|
+
plugins: [
|
|
173
|
+
mdx({
|
|
174
|
+
// using the defuss jsxImportSource so that the output code contains JSX runtime calls
|
|
175
|
+
// and can be rendered to HTML here on the server (in Node.js).
|
|
176
|
+
jsxImportSource: "defuss",
|
|
177
|
+
// We also use any remark/rehype plugins specified in the config file.
|
|
178
|
+
remarkPlugins: config.remarkPlugins,
|
|
179
|
+
rehypePlugins: config.rehypePlugins
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
});
|
|
183
|
+
await esbuild.build({
|
|
184
|
+
entryPoints: [
|
|
185
|
+
join(tmpComponentsDir, "**/*.tsx"),
|
|
186
|
+
join(tmpComponentsDir, "**/*.ts")
|
|
187
|
+
],
|
|
188
|
+
format: "esm",
|
|
189
|
+
bundle: true,
|
|
190
|
+
// making sure we can do code splitting for shared dependencies (e.g. defuss lib)
|
|
191
|
+
splitting: true,
|
|
192
|
+
target: ["esnext"],
|
|
193
|
+
outdir: tmpComponentsDir
|
|
194
|
+
});
|
|
195
|
+
const outputFiles = await glob.async(join(tmpPagesDir, "**/*.js"));
|
|
196
|
+
if (!existsSync(outputProjectDir)) {
|
|
197
|
+
mkdirSync(outputProjectDir, { recursive: true });
|
|
198
|
+
}
|
|
199
|
+
for (const outputFile of outputFiles) {
|
|
200
|
+
const outputHtmlFilePath = outputFile.replace(".js", ".html");
|
|
201
|
+
const relativeOutputHtmlFilePath = outputHtmlFilePath.replace(
|
|
202
|
+
`${tmpPagesDir}${sep}`,
|
|
203
|
+
""
|
|
204
|
+
);
|
|
205
|
+
if (debug) {
|
|
206
|
+
console.log("Processing output file (JS):", outputFile);
|
|
207
|
+
console.log("Output HTML file path:", outputHtmlFilePath);
|
|
208
|
+
console.log("Relative output HTML path:", relativeOutputHtmlFilePath);
|
|
209
|
+
}
|
|
210
|
+
const code = await readFile(outputFile, "utf-8");
|
|
211
|
+
const encoded = Buffer.from(code).toString("base64");
|
|
212
|
+
const dataUrl = `data:text/javascript;base64,${encoded}`;
|
|
213
|
+
const exports = await import(dataUrl);
|
|
214
|
+
if (debug) {
|
|
215
|
+
console.log("exports", exports);
|
|
216
|
+
}
|
|
217
|
+
let vdom = exports.default(exports);
|
|
218
|
+
for (const plugin of config.plugins || []) {
|
|
219
|
+
if (plugin.phase === "page-vdom" && (plugin.mode === mode || plugin.mode === "both")) {
|
|
220
|
+
if (debug) {
|
|
221
|
+
console.log(`Running page-vdom plugin: ${plugin.name}`);
|
|
222
|
+
}
|
|
223
|
+
vdom = await plugin.fn(
|
|
224
|
+
vdom,
|
|
225
|
+
relativeOutputHtmlFilePath,
|
|
226
|
+
projectDir,
|
|
227
|
+
config
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const browserGlobals = getBrowserGlobals();
|
|
232
|
+
const document = getDocument(false, browserGlobals);
|
|
233
|
+
browserGlobals.document = document;
|
|
234
|
+
let el = renderSync(vdom, document.documentElement, {
|
|
235
|
+
browserGlobals
|
|
236
|
+
});
|
|
237
|
+
for (const plugin of config.plugins || []) {
|
|
238
|
+
if (plugin.phase === "page-dom" && (plugin.mode === mode || plugin.mode === "both")) {
|
|
239
|
+
if (debug) {
|
|
240
|
+
console.log(`Running page-dom plugin: ${plugin.name}`);
|
|
241
|
+
}
|
|
242
|
+
el = await plugin.fn(
|
|
243
|
+
el,
|
|
244
|
+
relativeOutputHtmlFilePath,
|
|
245
|
+
projectDir,
|
|
246
|
+
config
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
let html = renderToString(el);
|
|
251
|
+
for (const plugin of config.plugins || []) {
|
|
252
|
+
if (plugin.phase === "page-html" && (plugin.mode === mode || plugin.mode === "both")) {
|
|
253
|
+
if (debug) {
|
|
254
|
+
console.log(`Running page-html plugin: ${plugin.name}`);
|
|
255
|
+
}
|
|
256
|
+
html = await plugin.fn(
|
|
257
|
+
html,
|
|
258
|
+
relativeOutputHtmlFilePath,
|
|
259
|
+
projectDir,
|
|
260
|
+
config
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
if (debug) {
|
|
265
|
+
console.log("Writing HTML file", outputHtmlFilePath);
|
|
266
|
+
}
|
|
267
|
+
if (debug) {
|
|
268
|
+
console.log("Relative HTML path:", relativeOutputHtmlFilePath);
|
|
269
|
+
}
|
|
270
|
+
const finalOutputFile = join(
|
|
271
|
+
projectDir,
|
|
272
|
+
config.output,
|
|
273
|
+
relativeOutputHtmlFilePath
|
|
274
|
+
);
|
|
275
|
+
if (debug) {
|
|
276
|
+
console.log("Full HTML output path:", finalOutputFile);
|
|
277
|
+
}
|
|
278
|
+
const finalOutputDir = dirname(finalOutputFile);
|
|
279
|
+
if (!existsSync(finalOutputDir)) {
|
|
280
|
+
mkdirSync(finalOutputDir, { recursive: true });
|
|
281
|
+
}
|
|
282
|
+
await writeFile(finalOutputFile, html);
|
|
283
|
+
}
|
|
284
|
+
await cp(tmpComponentsDir, outputComponentsDir, { recursive: true });
|
|
285
|
+
await cp(inputAssetsDir, outputAssetsDir, { recursive: true });
|
|
286
|
+
for (const plugin of config.plugins || []) {
|
|
287
|
+
if (plugin.phase === "post" && (plugin.mode === mode || plugin.mode === "both")) {
|
|
288
|
+
if (debug) {
|
|
289
|
+
console.log(`Running post-plugin: ${plugin.name}`);
|
|
290
|
+
}
|
|
291
|
+
await plugin.fn(projectDir, config);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (!debug) {
|
|
295
|
+
rmdirSync(config.tmp, { recursive: true });
|
|
296
|
+
}
|
|
297
|
+
const endTime = performance.now();
|
|
298
|
+
const totalTime = (endTime - startTime) / 1e3;
|
|
299
|
+
console.log(`Build completed in ${totalTime.toFixed(2)} seconds.`);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const serve = async ({ projectDir, debug = false }) => {
|
|
303
|
+
const config = await readConfig(projectDir, debug);
|
|
304
|
+
const outputDir = join(projectDir, config.output);
|
|
305
|
+
const pagesDir = join(projectDir, config.pages);
|
|
306
|
+
const componentsDir = join(projectDir, config.components);
|
|
307
|
+
const assetsDir = join(projectDir, config.assets);
|
|
308
|
+
await build({ projectDir, debug, mode: "serve" });
|
|
309
|
+
const app = express();
|
|
310
|
+
const port = 3e3;
|
|
311
|
+
app.use(serveStatic(outputDir));
|
|
312
|
+
app.listen(port, () => {
|
|
313
|
+
console.log(`Server running at http://localhost:${port}`);
|
|
314
|
+
});
|
|
315
|
+
let isBuilding = false;
|
|
316
|
+
let pendingBuild = false;
|
|
317
|
+
const triggerBuild = async () => {
|
|
318
|
+
if (isBuilding) {
|
|
319
|
+
pendingBuild = true;
|
|
320
|
+
if (debug) {
|
|
321
|
+
console.log("Build scheduled after current one completes");
|
|
322
|
+
}
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
isBuilding = true;
|
|
326
|
+
try {
|
|
327
|
+
await build({ projectDir, debug, mode: "serve" });
|
|
328
|
+
} finally {
|
|
329
|
+
isBuilding = false;
|
|
330
|
+
if (pendingBuild) {
|
|
331
|
+
pendingBuild = false;
|
|
332
|
+
if (debug) {
|
|
333
|
+
console.log("Running pending build");
|
|
334
|
+
}
|
|
335
|
+
await triggerBuild();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const watcher = chokidar.watch([pagesDir, componentsDir, assetsDir], {
|
|
340
|
+
ignored: /(^|[\/\\])\../,
|
|
341
|
+
// Ignore dotfiles
|
|
342
|
+
persistent: true,
|
|
343
|
+
ignoreInitial: true
|
|
344
|
+
// Ignore initial add events
|
|
345
|
+
});
|
|
346
|
+
watcher.on("change", async (path) => {
|
|
347
|
+
if (debug) {
|
|
348
|
+
console.log(`File changed: ${path}`);
|
|
349
|
+
}
|
|
350
|
+
await triggerBuild();
|
|
351
|
+
});
|
|
352
|
+
watcher.on("add", async (path) => {
|
|
353
|
+
if (debug) {
|
|
354
|
+
console.log(`File added: ${path}`);
|
|
355
|
+
}
|
|
356
|
+
await triggerBuild();
|
|
357
|
+
});
|
|
358
|
+
watcher.on("unlink", async (path) => {
|
|
359
|
+
if (debug) {
|
|
360
|
+
console.log(`File removed: ${path}`);
|
|
361
|
+
}
|
|
362
|
+
await triggerBuild();
|
|
363
|
+
});
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
export { rehypePlugins as a, readConfig as b, configDefaults as c, build as d, remarkPlugins as r, serve as s };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node_path = require('node:path');
|
|
4
|
+
|
|
5
|
+
const tailwindPlugin = {
|
|
6
|
+
name: "tailwind",
|
|
7
|
+
mode: "both",
|
|
8
|
+
phase: "post",
|
|
9
|
+
fn: async (projectDir, { tmp }) => {
|
|
10
|
+
console.log("Tailwind CSS plugin running... 1 DIR:", node_path.join(projectDir));
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.tailwindPlugin = tailwindPlugin;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
2
|
+
|
|
3
|
+
const tailwindPlugin = {
|
|
4
|
+
name: "tailwind",
|
|
5
|
+
mode: "both",
|
|
6
|
+
phase: "post",
|
|
7
|
+
fn: async (projectDir, { tmp }) => {
|
|
8
|
+
console.log("Tailwind CSS plugin running... 1 DIR:", join(projectDir));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export { tailwindPlugin as t };
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Options } from '@mdx-js/esbuild';
|
|
2
|
+
import { VNode } from 'defuss/server';
|
|
3
|
+
|
|
4
|
+
type RemarkPlugins = Options["remarkPlugins"];
|
|
5
|
+
type RehypePlugins = Options["rehypePlugins"];
|
|
6
|
+
type PluginFnPageHtml = (html: string, relativeOutputHtmlFilePath: string, projectDir: string, config: SsgConfig) => Promise<string> | string;
|
|
7
|
+
type PluginFnPageVdom = (vdom: VNode, relativeOutputHtmlFilePath: string, projectDir: string, config: SsgConfig) => Promise<VNode> | VNode;
|
|
8
|
+
type PluginFnPageDom = (dom: HTMLElement, relativeOutputHtmlFilePath: string, projectDir: string, config: SsgConfig) => Promise<HTMLElement> | HTMLElement;
|
|
9
|
+
type PluginFnPrePost = (projectDir: string, config: SsgConfig) => Promise<void> | void;
|
|
10
|
+
type BuildMode = "serve" | "build" | "both";
|
|
11
|
+
interface BuildOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Enable debug logging during the build process
|
|
14
|
+
* Defaults to false
|
|
15
|
+
*/
|
|
16
|
+
debug?: boolean;
|
|
17
|
+
/**
|
|
18
|
+
* The root directory of the project to build
|
|
19
|
+
* No default - this must be provided
|
|
20
|
+
*/
|
|
21
|
+
projectDir: string;
|
|
22
|
+
/**
|
|
23
|
+
* The mode in which to run the build: "serve" for development server mode,
|
|
24
|
+
* "build" for static site generation mode;
|
|
25
|
+
* Defaults to "build"
|
|
26
|
+
*/
|
|
27
|
+
mode: Omit<BuildMode, "both">;
|
|
28
|
+
}
|
|
29
|
+
type PluginFn = PluginFnPageHtml | PluginFnPageVdom | PluginFnPageDom | PluginFnPrePost;
|
|
30
|
+
/**
|
|
31
|
+
* Plugin interface for extending the SSG build process
|
|
32
|
+
*/
|
|
33
|
+
interface SsgPlugin<T = PluginFn> {
|
|
34
|
+
/**
|
|
35
|
+
* The name of the plugin
|
|
36
|
+
*/
|
|
37
|
+
name: string;
|
|
38
|
+
/**
|
|
39
|
+
* When to run the plugin: "pre" before the build starts, "post" after the build completes
|
|
40
|
+
* "page-vdom" after the VDOM for each page is created, before rendering to DOM
|
|
41
|
+
* "page-dom" after the DOM for each page is created, before serializing to HTML
|
|
42
|
+
* "page-html" after the HTML for each page is created, before writing to disk
|
|
43
|
+
*/
|
|
44
|
+
phase: "pre" | "page-vdom" | "page-dom" | "page-html" | "post";
|
|
45
|
+
/**
|
|
46
|
+
* The mode(s) in which the plugin should run: "serve" for development server mode,
|
|
47
|
+
* "build" for static site generation mode, or "both" for both modes
|
|
48
|
+
* Defaults to "both"
|
|
49
|
+
*/
|
|
50
|
+
mode: BuildMode;
|
|
51
|
+
/**
|
|
52
|
+
* The plugin function to execute
|
|
53
|
+
* @param config The current SsgConfig object
|
|
54
|
+
*/
|
|
55
|
+
fn: T;
|
|
56
|
+
}
|
|
57
|
+
interface SsgConfig {
|
|
58
|
+
/**
|
|
59
|
+
* Input directory containing page files (e.g., MDX files)
|
|
60
|
+
* Defaults to "pages"
|
|
61
|
+
*/
|
|
62
|
+
pages: string;
|
|
63
|
+
/**
|
|
64
|
+
* Output directory for generated static site files
|
|
65
|
+
* Defaults to "dist"
|
|
66
|
+
*/
|
|
67
|
+
output: string;
|
|
68
|
+
/**
|
|
69
|
+
* Directory containing reusable components (e.g., defuss components)
|
|
70
|
+
* Defaults to "components"
|
|
71
|
+
*/
|
|
72
|
+
components: string;
|
|
73
|
+
/**
|
|
74
|
+
* Directory containing static assets (e.g., images, fonts)
|
|
75
|
+
* Defaults to "assets"
|
|
76
|
+
*/
|
|
77
|
+
assets: string;
|
|
78
|
+
/**
|
|
79
|
+
* Temporary working directory for build process
|
|
80
|
+
* Defaults to ".ssg-temp"
|
|
81
|
+
*/
|
|
82
|
+
tmp: string;
|
|
83
|
+
/**
|
|
84
|
+
* Optional list of plugins to extend the build process
|
|
85
|
+
*/
|
|
86
|
+
plugins: Array<SsgPlugin>;
|
|
87
|
+
/**
|
|
88
|
+
* Remark plugins to use for MDX processing
|
|
89
|
+
* You can import the default set from "defuss-ssg" and extend it
|
|
90
|
+
* like this: import { remarkPlugins as defaultRemarkPlugins } from "defuss-ssg"
|
|
91
|
+
*/
|
|
92
|
+
remarkPlugins: Options["remarkPlugins"];
|
|
93
|
+
/**
|
|
94
|
+
* Rehype plugins to use for MDX processing
|
|
95
|
+
* You can import the default set from "defuss-ssg" and extend it
|
|
96
|
+
* like this: import { rehypePlugins as defaultRehypePlugins } from "defuss-ssg"
|
|
97
|
+
*/
|
|
98
|
+
rehypePlugins: Options["rehypePlugins"];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type { BuildOptions as B, PluginFnPageHtml as P, RemarkPlugins as R, SsgConfig as S, RehypePlugins as a, PluginFnPageVdom as b, PluginFnPageDom as c, PluginFnPrePost as d, BuildMode as e, PluginFn as f, SsgPlugin as g };
|
package/package.json
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "defuss-ssg",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"bin": "./dist/cli.mjs",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"description": "A simple static site generator (SSG) built with defuss.",
|
|
11
|
+
"keywords": ["ssg", "static", "site", "generator", "defuss"],
|
|
12
|
+
"repository": {
|
|
13
|
+
"url": "git+https://github.com/kyr0/defuss.git",
|
|
14
|
+
"type": "git"
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"clean": "rm -rf ./dist && rm -rf ./node_modules/.pnpm",
|
|
18
|
+
"pretest": "pnpm run build",
|
|
19
|
+
"prebuild": "pnpm run clean",
|
|
20
|
+
"build": "pkgroll",
|
|
21
|
+
"cli-build": "node ./dist/cli.mjs build",
|
|
22
|
+
"cli-serve": "node ./dist/cli.mjs serve",
|
|
23
|
+
"test": "vitest --run --coverage"
|
|
24
|
+
},
|
|
25
|
+
"author": "Aron Homberg <info@aron-homberg.de>",
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"require": {
|
|
30
|
+
"types": "./dist/index.d.cts",
|
|
31
|
+
"default": "./dist/index.cjs"
|
|
32
|
+
},
|
|
33
|
+
"import": {
|
|
34
|
+
"types": "./dist/index.d.mts",
|
|
35
|
+
"default": "./dist/index.mjs"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"./components": {
|
|
39
|
+
"require": {
|
|
40
|
+
"types": "./dist/components/index.d.cts",
|
|
41
|
+
"default": "./dist/components/index.cjs"
|
|
42
|
+
},
|
|
43
|
+
"import": {
|
|
44
|
+
"types": "./dist/components/index.d.mts",
|
|
45
|
+
"default": "./dist/components/index.mjs"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"./runtime": {
|
|
49
|
+
"require": {
|
|
50
|
+
"types": "./dist/runtime.d.cts",
|
|
51
|
+
"default": "./dist/runtime.cjs"
|
|
52
|
+
},
|
|
53
|
+
"import": {
|
|
54
|
+
"types": "./dist/runtime.d.mts",
|
|
55
|
+
"default": "./dist/runtime.mjs"
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"./plugins": {
|
|
59
|
+
"require": {
|
|
60
|
+
"types": "./dist/plugins/index.d.cts",
|
|
61
|
+
"default": "./dist/plugins/index.cjs"
|
|
62
|
+
},
|
|
63
|
+
"import": {
|
|
64
|
+
"types": "./dist/plugins/index.d.mts",
|
|
65
|
+
"default": "./dist/plugins/index.mjs"
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"main": "./dist/index.cjs",
|
|
70
|
+
"module": "./dist/index.mjs",
|
|
71
|
+
"types": "./dist/index.d.cts",
|
|
72
|
+
"files": ["dist"],
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": "^18.17.1 || ^20.3.0 || >=21.0.0"
|
|
75
|
+
},
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"express": "^5.1.0",
|
|
78
|
+
"serve-static": "^2.2.0",
|
|
79
|
+
"chokidar": "^4.0.3",
|
|
80
|
+
"@mdx-js/esbuild": "^3.1.1",
|
|
81
|
+
"esbuild": "^0.25.9",
|
|
82
|
+
"rehype-mdx-title": "^3.2.0",
|
|
83
|
+
"rehype-katex": "^7.0.1",
|
|
84
|
+
"remark-math": "^6.0.0",
|
|
85
|
+
"remark-frontmatter": "^5.0.0",
|
|
86
|
+
"remark-mdx-frontmatter": "^5.2.0",
|
|
87
|
+
"fast-glob": "^3.3.3",
|
|
88
|
+
"@types/express": "^5.0.3",
|
|
89
|
+
"@types/serve-static": "^1.15.8",
|
|
90
|
+
"defuss": "^2.1.1",
|
|
91
|
+
"defuss-runtime": "^1.2.0"
|
|
92
|
+
},
|
|
93
|
+
"devDependencies": {
|
|
94
|
+
"pkgroll": "^2.5.1",
|
|
95
|
+
"typescript": "^5.6.3",
|
|
96
|
+
"happy-dom": "^15.11.7"
|
|
97
|
+
}
|
|
98
|
+
}
|