defuss-ssg 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { v as validateProjectDir, b as build, s as serve } from './serve-BR2MS6bN.mjs';
3
- import { join, resolve } from 'node:path';
2
+ import { v as validateProjectDir, b as build, s as serve } from './serve-CMNixAKF.mjs';
3
+ import { join, dirname, resolve } from 'node:path';
4
4
  import { existsSync, readFileSync } from 'node:fs';
5
5
  import { spawn } from 'node:child_process';
6
6
  import 'chokidar';
@@ -22,6 +22,54 @@ import 'node:fs/promises';
22
22
  import 'node:url';
23
23
  import 'node:module';
24
24
 
25
+ const canResolve = (dep, dir) => {
26
+ let current = dir;
27
+ while (true) {
28
+ if (existsSync(join(current, "node_modules", dep))) return true;
29
+ const parent = dirname(current);
30
+ if (parent === current) break;
31
+ current = parent;
32
+ }
33
+ return false;
34
+ };
35
+ const runInstall = (cmd, args, cwd, env) => new Promise((resolve, reject) => {
36
+ const child = spawn(cmd, args, {
37
+ cwd,
38
+ shell: true,
39
+ stdio: ["inherit", "pipe", "pipe"],
40
+ env: env ?? process.env
41
+ });
42
+ const lastLines = [];
43
+ let printedLines = 0;
44
+ const pushLine = (line) => {
45
+ lastLines.push(line);
46
+ if (lastLines.length > 3) lastLines.shift();
47
+ if (process.stdout.isTTY) {
48
+ for (let i = 0; i < printedLines; i++) {
49
+ process.stdout.write("\x1B[1A\x1B[2K");
50
+ }
51
+ for (const l of lastLines) {
52
+ process.stdout.write(`${l}
53
+ `);
54
+ }
55
+ printedLines = lastLines.length;
56
+ } else {
57
+ process.stdout.write(`${line}
58
+ `);
59
+ }
60
+ };
61
+ const handleData = (chunk) => {
62
+ const lines = chunk.toString().split(/\r\n|\n|\r/).filter((l) => l.trim().length > 0);
63
+ for (const line of lines) pushLine(line);
64
+ };
65
+ child.stdout?.on("data", handleData);
66
+ child.stderr?.on("data", handleData);
67
+ child.on("error", reject);
68
+ child.on("close", (code) => {
69
+ if (code === 0) resolve();
70
+ else reject(new Error(`${cmd} ${args.join(" ")} exited with code ${code ?? "unknown"}`));
71
+ });
72
+ });
25
73
  const setup = async (projectDir) => {
26
74
  const projectDirStatus = validateProjectDir(projectDir);
27
75
  if (projectDirStatus.code !== "OK") return projectDirStatus;
@@ -50,69 +98,78 @@ const setup = async (projectDir) => {
50
98
  message: `Unsupported package manager: ${pm}`
51
99
  };
52
100
  }
101
+ const allDeps = {
102
+ ...packageJson.dependencies,
103
+ ...packageJson.devDependencies
104
+ };
105
+ const depNames = Object.keys(allDeps).filter(
106
+ (d) => d !== "defuss-ssg"
107
+ // skip self-reference (we're already running)
108
+ );
109
+ const allResolvable = depNames.length === 0 || depNames.every((d) => canResolve(d, projectDir));
110
+ if (allResolvable) {
111
+ console.log(
112
+ `All dependencies already available \u2014 skipping install.`
113
+ );
114
+ return { code: "OK", message: "Setup completed (deps already available)" };
115
+ }
53
116
  console.log(`Setting up project in ${projectDir} using ${pm}...`);
54
- try {
55
- await new Promise((resolve, reject) => {
56
- const child = spawn(pm, ["install"], {
57
- cwd: projectDir,
58
- shell: true,
59
- stdio: ["inherit", "pipe", "pipe"]
117
+ if (pm === "bun") {
118
+ try {
119
+ await new Promise((resolve, reject) => {
120
+ const child = spawn(pm, ["pm", "trust", "esbuild"], {
121
+ cwd: projectDir,
122
+ shell: true,
123
+ stdio: "ignore",
124
+ env: { ...process.env, BUN_WORKSPACE_ROOT: projectDir }
125
+ });
126
+ child.on("error", reject);
127
+ child.on("close", () => resolve());
60
128
  });
61
- const lastLines = [];
62
- let printedLines = 0;
63
- const pushLine = (line) => {
64
- lastLines.push(line);
65
- if (lastLines.length > 3) lastLines.shift();
66
- if (process.stdout.isTTY) {
67
- for (let i = 0; i < printedLines; i++) {
68
- process.stdout.write("\x1B[1A\x1B[2K");
69
- }
70
- for (const l of lastLines) {
71
- process.stdout.write(`${l}
72
- `);
73
- }
74
- printedLines = lastLines.length;
75
- } else {
76
- process.stdout.write(`${line}
77
- `);
78
- }
79
- };
80
- const handleData = (chunk) => {
81
- const lines = chunk.toString().split(/\r\n|\n|\r/).filter((l) => l.trim().length > 0);
82
- for (const line of lines) {
83
- pushLine(line);
84
- }
85
- };
86
- child.stdout?.on("data", handleData);
87
- child.stderr?.on("data", handleData);
88
- child.on("error", reject);
89
- child.on("close", (code) => {
90
- if (code === 0) {
91
- resolve();
92
- } else {
93
- reject(
94
- new Error(
95
- `${pm} install exited with code ${code ?? "unknown"}`
96
- )
97
- );
98
- }
99
- });
100
- });
129
+ } catch {
130
+ }
131
+ }
132
+ try {
133
+ const bunEnv = { ...process.env, BUN_WORKSPACE_ROOT: projectDir };
134
+ await runInstall(
135
+ pm,
136
+ ["install", "--linker", "isolated"],
137
+ projectDir,
138
+ pm === "bun" ? bunEnv : void 0
139
+ );
101
140
  console.log("Dependencies installed successfully.");
102
141
  } catch (error) {
103
- return {
104
- code: "INSTALL_FAILED",
105
- message: `Failed to install dependencies: ${error.message}`
106
- };
142
+ if (pm === "bun") {
143
+ console.warn(
144
+ `Warning: ${error.message}
145
+ Falling back to npm install...`
146
+ );
147
+ try {
148
+ await runInstall("npm", ["install"], projectDir);
149
+ console.log("Dependencies installed successfully via npm.");
150
+ } catch (npmError) {
151
+ console.warn(
152
+ `Warning: npm install also failed: ${npmError.message}
153
+ Continuing anyway \u2014 dependencies may already be available.`
154
+ );
155
+ }
156
+ } else {
157
+ console.warn(
158
+ `Warning: ${error.message}
159
+ Continuing anyway \u2014 dependencies may already be available.`
160
+ );
161
+ }
107
162
  }
108
163
  return { code: "OK", message: "Setup completed successfully" };
109
164
  };
110
165
 
111
166
  (async () => {
112
167
  const args = process.argv.slice(2);
113
- const command = args[0];
114
- const folder = args[1];
115
- const usage = "Usage: defuss-ssg <build|serve> <folder>";
168
+ const debug = args.includes("--debug") || args.includes("-d");
169
+ const positional = args.filter((a) => !a.startsWith("-"));
170
+ const command = positional[0];
171
+ const folder = positional[1];
172
+ const usage = "Usage: defuss-ssg <build|serve> <folder> [--debug]";
116
173
  if (!command || !folder) {
117
174
  console.error(usage);
118
175
  process.exit(1);
@@ -123,14 +180,14 @@ const setup = async (projectDir) => {
123
180
  console.log(`Building ${folder}...`);
124
181
  await build({
125
182
  projectDir,
126
- debug: true,
183
+ debug,
127
184
  mode: "build"
128
185
  });
129
186
  } else if (command === "serve") {
130
187
  console.log(`Serving ${folder}...`);
131
188
  await serve({
132
189
  projectDir,
133
- debug: true});
190
+ debug});
134
191
  } else {
135
192
  console.error(usage);
136
193
  process.exit(1);
package/dist/index.cjs CHANGED
@@ -208,15 +208,13 @@ const __dirname$1 = node_path.dirname(__filename$1);
208
208
  const build = async ({
209
209
  projectDir,
210
210
  debug = false,
211
- mode = "build"
211
+ mode = "build",
212
+ changedFile
212
213
  }) => {
213
214
  const projectDirStatus = validateProjectDir(projectDir);
214
215
  if (projectDirStatus.code !== "OK") return projectDirStatus;
215
216
  const startTime = performance.now();
216
217
  const config = await readConfig(projectDir, debug);
217
- if (debug) {
218
- console.log("PRE config", config);
219
- }
220
218
  if (debug) {
221
219
  console.log("Using config:", config);
222
220
  }
@@ -245,193 +243,213 @@ const build = async ({
245
243
  }
246
244
  if (!node_fs.existsSync(inputPagesDir)) {
247
245
  throw new Error(`Input pages directory does not exist: ${inputPagesDir}`);
248
- } else if (debug) {
249
- console.log(`Input pages directory exists: ${inputPagesDir}`);
250
246
  }
251
- if (!node_fs.existsSync(inputComponentsDir)) {
252
- console.warn(
253
- `There is no components directory: ${inputComponentsDir}. You may not be able to use any custom components.`
254
- );
255
- }
256
- if (!node_fs.existsSync(inputAssetsDir)) {
257
- console.warn(
258
- `There is no assets directory: ${inputAssetsDir}. You may not be able to serve any custom assets.`
259
- );
247
+ let changeKind = "full";
248
+ let changedRelative = "";
249
+ if (changedFile) {
250
+ changedRelative = changedFile.startsWith(projectDir) ? changedFile.slice(projectDir.length).replace(/^\//, "") : changedFile;
251
+ if (changedRelative.startsWith(config.pages + node_path.sep) || changedRelative.startsWith(config.pages + "/")) {
252
+ changeKind = "page";
253
+ } else if (changedRelative.startsWith(config.components + node_path.sep) || changedRelative.startsWith(config.components + "/")) {
254
+ changeKind = "component";
255
+ } else if (changedRelative.startsWith(config.assets + node_path.sep) || changedRelative.startsWith(config.assets + "/")) {
256
+ changeKind = "asset";
257
+ } else if (changedRelative === "config.ts" || changedRelative === "config.js") {
258
+ changeKind = "config";
259
+ }
260
+ if (debug) {
261
+ console.log(`Incremental build \u2014 changeKind: ${changeKind}, file: ${changedRelative}`);
262
+ }
260
263
  }
261
- for (const plugin of config.plugins || []) {
262
- if (plugin.phase === "pre" && (plugin.mode === mode || plugin.mode === "both")) {
263
- if (debug) {
264
- console.log(`Running pre-plugin: ${plugin.name}`);
264
+ const isFullBuild = changeKind === "full" || changeKind === "config";
265
+ const tempExists = node_fs.existsSync(config.tmp);
266
+ if (isFullBuild) {
267
+ for (const plugin of config.plugins || []) {
268
+ if (plugin.phase === "pre" && (plugin.mode === mode || plugin.mode === "both")) {
269
+ if (debug) {
270
+ console.log(`Running pre-plugin: ${plugin.name}`);
271
+ }
272
+ await plugin.fn(projectDir, config);
265
273
  }
266
- await plugin.fn(projectDir, config);
267
274
  }
268
275
  }
269
- if (node_fs.existsSync(config.tmp)) {
270
- if (debug) {
271
- console.log(`Removing existing temp folder: ${config.tmp}`);
276
+ if (isFullBuild || !tempExists) {
277
+ if (tempExists) {
278
+ node_fs.rmSync(config.tmp, { recursive: true });
272
279
  }
273
- node_fs.rmSync(config.tmp, { recursive: true });
274
- }
275
- await promises.cp(projectDir, config.tmp, {
276
- recursive: true,
277
- filter: (src) => {
278
- const relative = src.replace(node_path.join(projectDir, ""), "");
279
- if (relative.startsWith(node_path.join("assets", "")) || relative.startsWith(node_path.join("node_modules", ""))) {
280
- return false;
280
+ await promises.cp(projectDir, config.tmp, {
281
+ recursive: true,
282
+ filter: (src) => {
283
+ const relative = src.replace(node_path.join(projectDir, ""), "");
284
+ if (relative.startsWith(node_path.join("assets", "")) || relative.startsWith(node_path.join("node_modules", ""))) {
285
+ return false;
286
+ }
287
+ return true;
281
288
  }
282
- return true;
289
+ });
290
+ } else {
291
+ const srcFile = node_path.join(projectDir, changedRelative);
292
+ const destFile = node_path.join(config.tmp, changedRelative);
293
+ const destDir = node_path.dirname(destFile);
294
+ if (!node_fs.existsSync(destDir)) {
295
+ node_fs.mkdirSync(destDir, { recursive: true });
283
296
  }
284
- });
297
+ if (node_fs.existsSync(srcFile)) {
298
+ await promises.cp(srcFile, destFile);
299
+ }
300
+ }
285
301
  await promises.cp(
286
- // in a built situation, __dirname is the dist folder of defuss-ssg
287
302
  node_path.resolve(node_path.join(__dirname$1, "components", "index.mjs")),
288
303
  node_path.join(tmpComponentsDir, "hydrate.tsx")
289
- // any valid JS is always a valid TS file
290
304
  );
291
305
  await promises.cp(
292
- // in a built situation, __dirname is the dist folder of defuss-ssg
293
306
  node_path.resolve(node_path.join(__dirname$1, "runtime.mjs")),
294
307
  node_path.join(tmpComponentsDir, "runtime.ts")
295
- // any valid JS is always a valid TS file
296
308
  );
297
- await esbuild.build({
298
- entryPoints: [node_path.join(tmpPagesDir, "**/*.mdx")],
299
- format: "esm",
300
- bundle: true,
301
- sourcemap: true,
302
- jsxDev: true,
303
- target: ["esnext"],
304
- outdir: tmpPagesDir,
305
- plugins: [
306
- mdx({
307
- // using the defuss jsxImportSource so that the output code contains JSX runtime calls
308
- // and can be rendered to HTML here on the server (in Node.js).
309
- jsxImportSource: "defuss",
310
- development: true,
311
- // We also use any remark/rehype plugins specified in the config file.
312
- remarkPlugins: config.remarkPlugins,
313
- rehypePlugins: config.rehypePlugins
314
- })
315
- ]
316
- });
317
- await esbuild.build({
318
- entryPoints: [
319
- node_path.join(tmpComponentsDir, "**/*.tsx"),
320
- node_path.join(tmpComponentsDir, "**/*.ts")
321
- ],
322
- format: "esm",
323
- bundle: true,
324
- // making sure we can do code splitting for shared dependencies (e.g. defuss lib)
325
- splitting: true,
326
- target: ["esnext"],
327
- outdir: tmpComponentsDir
328
- });
329
- const outputFiles = await glob.async(node_path.join(tmpPagesDir, "**/*.js"));
330
- if (!node_fs.existsSync(outputProjectDir)) {
331
- node_fs.mkdirSync(outputProjectDir, { recursive: true });
309
+ if (changeKind !== "asset") {
310
+ const pageEntryPoints = changeKind === "page" ? [node_path.join(config.tmp, changedRelative)] : [node_path.join(tmpPagesDir, "**/*.mdx")];
311
+ await esbuild.build({
312
+ entryPoints: pageEntryPoints,
313
+ format: "esm",
314
+ bundle: true,
315
+ sourcemap: true,
316
+ jsxDev: true,
317
+ target: ["esnext"],
318
+ outdir: tmpPagesDir,
319
+ plugins: [
320
+ mdx({
321
+ jsxImportSource: "defuss",
322
+ development: true,
323
+ remarkPlugins: config.remarkPlugins,
324
+ rehypePlugins: config.rehypePlugins
325
+ })
326
+ ]
327
+ });
332
328
  }
333
- for (const outputFile of outputFiles) {
334
- const outputHtmlFilePath = outputFile.replace(".js", ".html");
335
- const relativeOutputHtmlFilePath = outputHtmlFilePath.replace(
336
- `${tmpPagesDir}${node_path.sep}`,
337
- ""
338
- );
339
- if (debug) {
340
- console.log("Processing output file (JS):", outputFile);
341
- console.log("Output HTML file path:", outputHtmlFilePath);
342
- console.log("Relative output HTML path:", relativeOutputHtmlFilePath);
329
+ if (isFullBuild || changeKind === "component") {
330
+ await esbuild.build({
331
+ entryPoints: [
332
+ node_path.join(tmpComponentsDir, "**/*.tsx"),
333
+ node_path.join(tmpComponentsDir, "**/*.ts")
334
+ ],
335
+ format: "esm",
336
+ bundle: true,
337
+ splitting: true,
338
+ target: ["esnext"],
339
+ outdir: tmpComponentsDir
340
+ });
341
+ }
342
+ if (changeKind !== "asset") {
343
+ let outputFiles;
344
+ if (changeKind === "page") {
345
+ const jsFile = node_path.join(config.tmp, changedRelative.replace(/\.mdx$/, ".js"));
346
+ outputFiles = node_fs.existsSync(jsFile) ? [jsFile] : [];
347
+ } else {
348
+ outputFiles = await glob.async(node_path.join(tmpPagesDir, "**/*.js"));
343
349
  }
344
- const code = await promises.readFile(outputFile, "utf-8");
345
- const encoded = Buffer.from(code).toString("base64");
346
- const dataUrl = `data:text/javascript;base64,${encoded}`;
347
- const exports$1 = await import(dataUrl);
348
- if (debug) {
349
- console.log("exports", exports$1);
350
+ if (!node_fs.existsSync(outputProjectDir)) {
351
+ node_fs.mkdirSync(outputProjectDir, { recursive: true });
350
352
  }
351
- let vdom = exports$1.default(exports$1);
352
- for (const plugin of config.plugins || []) {
353
- if (plugin.phase === "page-vdom" && (plugin.mode === mode || plugin.mode === "both")) {
354
- if (debug) {
355
- console.log(`Running page-vdom plugin: ${plugin.name}`);
353
+ for (const outputFile of outputFiles) {
354
+ const outputHtmlFilePath = outputFile.replace(".js", ".html");
355
+ const relativeOutputHtmlFilePath = outputHtmlFilePath.replace(
356
+ `${tmpPagesDir}${node_path.sep}`,
357
+ ""
358
+ );
359
+ if (debug) {
360
+ console.log("Processing output file (JS):", outputFile);
361
+ console.log("Relative output HTML path:", relativeOutputHtmlFilePath);
362
+ }
363
+ const code = await promises.readFile(outputFile, "utf-8");
364
+ const encoded = Buffer.from(code).toString("base64");
365
+ const dataUrl = `data:text/javascript;base64,${encoded}`;
366
+ const exports$1 = await import(dataUrl);
367
+ if (debug) {
368
+ console.log("exports", exports$1);
369
+ }
370
+ let vdom = exports$1.default(exports$1);
371
+ for (const plugin of config.plugins || []) {
372
+ if (plugin.phase === "page-vdom" && (plugin.mode === mode || plugin.mode === "both")) {
373
+ if (debug) {
374
+ console.log(`Running page-vdom plugin: ${plugin.name}`);
375
+ }
376
+ vdom = await plugin.fn(
377
+ vdom,
378
+ relativeOutputHtmlFilePath,
379
+ projectDir,
380
+ config,
381
+ exports$1
382
+ );
356
383
  }
357
- vdom = await plugin.fn(
358
- vdom,
359
- relativeOutputHtmlFilePath,
360
- projectDir,
361
- config,
362
- exports$1
363
- );
364
384
  }
365
- }
366
- const browserGlobals = server.getBrowserGlobals();
367
- const document = server.getDocument(false, browserGlobals);
368
- browserGlobals.document = document;
369
- let el = server.renderSync(vdom, document.documentElement, {
370
- browserGlobals
371
- });
372
- for (const plugin of config.plugins || []) {
373
- if (plugin.phase === "page-dom" && (plugin.mode === mode || plugin.mode === "both")) {
374
- if (debug) {
375
- console.log(`Running page-dom plugin: ${plugin.name}`);
385
+ const browserGlobals = server.getBrowserGlobals();
386
+ const document = server.getDocument(false, browserGlobals);
387
+ browserGlobals.document = document;
388
+ let el = server.renderSync(vdom, document.documentElement, {
389
+ browserGlobals
390
+ });
391
+ for (const plugin of config.plugins || []) {
392
+ if (plugin.phase === "page-dom" && (plugin.mode === mode || plugin.mode === "both")) {
393
+ if (debug) {
394
+ console.log(`Running page-dom plugin: ${plugin.name}`);
395
+ }
396
+ el = await plugin.fn(
397
+ el,
398
+ relativeOutputHtmlFilePath,
399
+ projectDir,
400
+ config
401
+ );
376
402
  }
377
- el = await plugin.fn(
378
- el,
379
- relativeOutputHtmlFilePath,
380
- projectDir,
381
- config
382
- );
383
403
  }
384
- }
385
- let html = server.renderToString(el);
386
- for (const plugin of config.plugins || []) {
387
- if (plugin.phase === "page-html" && (plugin.mode === mode || plugin.mode === "both")) {
388
- if (debug) {
389
- console.log(`Running page-html plugin: ${plugin.name}`);
404
+ let html = server.renderToString(el);
405
+ for (const plugin of config.plugins || []) {
406
+ if (plugin.phase === "page-html" && (plugin.mode === mode || plugin.mode === "both")) {
407
+ if (debug) {
408
+ console.log(`Running page-html plugin: ${plugin.name}`);
409
+ }
410
+ html = await plugin.fn(
411
+ html,
412
+ relativeOutputHtmlFilePath,
413
+ projectDir,
414
+ config
415
+ );
390
416
  }
391
- html = await plugin.fn(
392
- html,
393
- relativeOutputHtmlFilePath,
394
- projectDir,
395
- config
396
- );
397
417
  }
418
+ const finalOutputFile = node_path.join(
419
+ projectDir,
420
+ config.output,
421
+ relativeOutputHtmlFilePath
422
+ );
423
+ const finalOutputDir = node_path.dirname(finalOutputFile);
424
+ if (!node_fs.existsSync(finalOutputDir)) {
425
+ node_fs.mkdirSync(finalOutputDir, { recursive: true });
426
+ }
427
+ await promises.writeFile(finalOutputFile, html);
398
428
  }
399
- if (debug) {
400
- console.log("Writing HTML file", outputHtmlFilePath);
401
- }
402
- if (debug) {
403
- console.log("Relative HTML path:", relativeOutputHtmlFilePath);
404
- }
405
- const finalOutputFile = node_path.join(
406
- projectDir,
407
- config.output,
408
- relativeOutputHtmlFilePath
409
- );
410
- if (debug) {
411
- console.log("Full HTML output path:", finalOutputFile);
412
- }
413
- const finalOutputDir = node_path.dirname(finalOutputFile);
414
- if (!node_fs.existsSync(finalOutputDir)) {
415
- node_fs.mkdirSync(finalOutputDir, { recursive: true });
416
- }
417
- await promises.writeFile(finalOutputFile, html);
418
429
  }
419
- await promises.cp(tmpComponentsDir, outputComponentsDir, { recursive: true });
420
- await promises.cp(inputAssetsDir, outputAssetsDir, { recursive: true });
421
- for (const plugin of config.plugins || []) {
422
- if (plugin.phase === "post" && (plugin.mode === mode || plugin.mode === "both")) {
423
- if (debug) {
424
- console.log(`Running post-plugin: ${plugin.name}`);
430
+ if (isFullBuild || changeKind === "component") {
431
+ await promises.cp(tmpComponentsDir, outputComponentsDir, { recursive: true });
432
+ }
433
+ if (isFullBuild || changeKind === "asset") {
434
+ await promises.cp(inputAssetsDir, outputAssetsDir, { recursive: true });
435
+ }
436
+ if (isFullBuild || changeKind === "component") {
437
+ for (const plugin of config.plugins || []) {
438
+ if (plugin.phase === "post" && (plugin.mode === mode || plugin.mode === "both")) {
439
+ if (debug) {
440
+ console.log(`Running post-plugin: ${plugin.name}`);
441
+ }
442
+ await plugin.fn(projectDir, config);
425
443
  }
426
- await plugin.fn(projectDir, config);
427
444
  }
428
445
  }
429
- if (!debug) {
446
+ if (mode === "build" && !debug) {
430
447
  node_fs.rmSync(config.tmp, { recursive: true });
431
448
  }
432
449
  const endTime = performance.now();
433
450
  const totalTime = (endTime - startTime) / 1e3;
434
- console.log(`Build completed in ${totalTime.toFixed(2)} seconds.`);
451
+ const label = isFullBuild ? "Full build" : `Incremental build (${changeKind}: ${changedRelative})`;
452
+ console.log(`${label} completed in ${totalTime.toFixed(2)} seconds.`);
435
453
  return { code: "OK", message: "Build completed successfully" };
436
454
  };
437
455
 
@@ -494,10 +512,10 @@ const serve = async ({
494
512
  path: "/livereload"
495
513
  });
496
514
  let isBuilding = false;
497
- let pendingBuild = false;
515
+ let pendingBuild = null;
498
516
  const triggerBuild = async (filePath) => {
499
517
  if (isBuilding) {
500
- pendingBuild = true;
518
+ pendingBuild = filePath;
501
519
  if (debug) {
502
520
  console.log("Build scheduled after current one completes");
503
521
  }
@@ -505,7 +523,7 @@ const serve = async ({
505
523
  }
506
524
  isBuilding = true;
507
525
  try {
508
- await build({ projectDir, debug, mode: "serve" });
526
+ await build({ projectDir, debug, mode: "serve", changedFile: filePath });
509
527
  liveReloadServer.clients.forEach((client) => {
510
528
  if (client.readyState === 1) {
511
529
  client.send(
@@ -521,11 +539,12 @@ const serve = async ({
521
539
  } finally {
522
540
  isBuilding = false;
523
541
  if (pendingBuild) {
524
- pendingBuild = false;
542
+ const pending = pendingBuild;
543
+ pendingBuild = null;
525
544
  if (debug) {
526
545
  console.log("Running pending build");
527
546
  }
528
- await triggerBuild(filePath);
547
+ await triggerBuild(pending);
529
548
  }
530
549
  }
531
550
  };
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RehypePlugins, a as RemarkPlugins, S as SsgConfig, B as BuildOptions, b as Status } from './types-BhV8wSVk.cjs';
2
- export { c as BuildMode, P as PluginFn, d as PluginFnPageDom, e as PluginFnPageHtml, f as PluginFnPageVdom, g as PluginFnPrePost, h as SsgPlugin, i as StatusCode } from './types-BhV8wSVk.cjs';
1
+ import { R as RehypePlugins, a as RemarkPlugins, S as SsgConfig, B as BuildOptions, b as Status } from './types-C0p7aCdN.cjs';
2
+ export { c as BuildMode, P as PluginFn, d as PluginFnPageDom, e as PluginFnPageHtml, f as PluginFnPageVdom, g as PluginFnPrePost, h as SsgPlugin, i as StatusCode } from './types-C0p7aCdN.cjs';
3
3
  import '@mdx-js/esbuild';
4
4
  import 'defuss/server';
5
5
 
@@ -19,7 +19,7 @@ declare const configDefaults: SsgConfig;
19
19
  * A single, complete build process for a static site project.
20
20
  * @param projectDir The root directory of the project to build
21
21
  */
22
- declare const build: ({ projectDir, debug, mode, }: BuildOptions) => Promise<Status>;
22
+ declare const build: ({ projectDir, debug, mode, changedFile, }: BuildOptions) => Promise<Status>;
23
23
 
24
24
  /**
25
25
  * A simple static file server to serve the generated static site from the output folder.
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { R as RehypePlugins, a as RemarkPlugins, S as SsgConfig, B as BuildOptions, b as Status } from './types-BhV8wSVk.mjs';
2
- export { c as BuildMode, P as PluginFn, d as PluginFnPageDom, e as PluginFnPageHtml, f as PluginFnPageVdom, g as PluginFnPrePost, h as SsgPlugin, i as StatusCode } from './types-BhV8wSVk.mjs';
1
+ import { R as RehypePlugins, a as RemarkPlugins, S as SsgConfig, B as BuildOptions, b as Status } from './types-C0p7aCdN.mjs';
2
+ export { c as BuildMode, P as PluginFn, d as PluginFnPageDom, e as PluginFnPageHtml, f as PluginFnPageVdom, g as PluginFnPrePost, h as SsgPlugin, i as StatusCode } from './types-C0p7aCdN.mjs';
3
3
  import '@mdx-js/esbuild';
4
4
  import 'defuss/server';
5
5
 
@@ -19,7 +19,7 @@ declare const configDefaults: SsgConfig;
19
19
  * A single, complete build process for a static site project.
20
20
  * @param projectDir The root directory of the project to build
21
21
  */
22
- declare const build: ({ projectDir, debug, mode, }: BuildOptions) => Promise<Status>;
22
+ declare const build: ({ projectDir, debug, mode, changedFile, }: BuildOptions) => Promise<Status>;
23
23
 
24
24
  /**
25
25
  * A simple static file server to serve the generated static site from the output folder.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export { b as build, c as configDefaults, r as readConfig, a as rehypePlugins, d as remarkPlugins, s as serve } from './serve-BR2MS6bN.mjs';
1
+ export { b as build, c as configDefaults, r as readConfig, a as rehypePlugins, d as remarkPlugins, s as serve } from './serve-CMNixAKF.mjs';
2
2
  import 'chokidar';
3
3
  import 'ultimate-express';
4
4
  import 'node:path';
@@ -1,4 +1,4 @@
1
- import { h as SsgPlugin, g as PluginFnPrePost } from '../types-BhV8wSVk.cjs';
1
+ import { h as SsgPlugin, g as PluginFnPrePost } from '../types-C0p7aCdN.cjs';
2
2
  import '@mdx-js/esbuild';
3
3
  import 'defuss/server';
4
4
 
@@ -1,4 +1,4 @@
1
- import { h as SsgPlugin, g as PluginFnPrePost } from '../types-BhV8wSVk.mjs';
1
+ import { h as SsgPlugin, g as PluginFnPrePost } from '../types-C0p7aCdN.mjs';
2
2
  import '@mdx-js/esbuild';
3
3
  import 'defuss/server';
4
4
 
@@ -1,6 +1,6 @@
1
1
  import chokidar from 'chokidar';
2
2
  import express from 'ultimate-express';
3
- import { join, sep, resolve, dirname } from 'node:path';
3
+ import { join, sep, dirname, resolve } from 'node:path';
4
4
  import { existsSync, statSync, rmSync, mkdirSync } from 'node:fs';
5
5
  import esbuild from 'esbuild';
6
6
  import rehypeKatex from 'rehype-katex';
@@ -205,15 +205,13 @@ const __dirname$1 = dirname(__filename$1);
205
205
  const build = async ({
206
206
  projectDir,
207
207
  debug = false,
208
- mode = "build"
208
+ mode = "build",
209
+ changedFile
209
210
  }) => {
210
211
  const projectDirStatus = validateProjectDir(projectDir);
211
212
  if (projectDirStatus.code !== "OK") return projectDirStatus;
212
213
  const startTime = performance.now();
213
214
  const config = await readConfig(projectDir, debug);
214
- if (debug) {
215
- console.log("PRE config", config);
216
- }
217
215
  if (debug) {
218
216
  console.log("Using config:", config);
219
217
  }
@@ -242,193 +240,213 @@ const build = async ({
242
240
  }
243
241
  if (!existsSync(inputPagesDir)) {
244
242
  throw new Error(`Input pages directory does not exist: ${inputPagesDir}`);
245
- } else if (debug) {
246
- console.log(`Input pages directory exists: ${inputPagesDir}`);
247
243
  }
248
- if (!existsSync(inputComponentsDir)) {
249
- console.warn(
250
- `There is no components directory: ${inputComponentsDir}. You may not be able to use any custom components.`
251
- );
252
- }
253
- if (!existsSync(inputAssetsDir)) {
254
- console.warn(
255
- `There is no assets directory: ${inputAssetsDir}. You may not be able to serve any custom assets.`
256
- );
244
+ let changeKind = "full";
245
+ let changedRelative = "";
246
+ if (changedFile) {
247
+ changedRelative = changedFile.startsWith(projectDir) ? changedFile.slice(projectDir.length).replace(/^\//, "") : changedFile;
248
+ if (changedRelative.startsWith(config.pages + sep) || changedRelative.startsWith(config.pages + "/")) {
249
+ changeKind = "page";
250
+ } else if (changedRelative.startsWith(config.components + sep) || changedRelative.startsWith(config.components + "/")) {
251
+ changeKind = "component";
252
+ } else if (changedRelative.startsWith(config.assets + sep) || changedRelative.startsWith(config.assets + "/")) {
253
+ changeKind = "asset";
254
+ } else if (changedRelative === "config.ts" || changedRelative === "config.js") {
255
+ changeKind = "config";
256
+ }
257
+ if (debug) {
258
+ console.log(`Incremental build \u2014 changeKind: ${changeKind}, file: ${changedRelative}`);
259
+ }
257
260
  }
258
- for (const plugin of config.plugins || []) {
259
- if (plugin.phase === "pre" && (plugin.mode === mode || plugin.mode === "both")) {
260
- if (debug) {
261
- console.log(`Running pre-plugin: ${plugin.name}`);
261
+ const isFullBuild = changeKind === "full" || changeKind === "config";
262
+ const tempExists = existsSync(config.tmp);
263
+ if (isFullBuild) {
264
+ for (const plugin of config.plugins || []) {
265
+ if (plugin.phase === "pre" && (plugin.mode === mode || plugin.mode === "both")) {
266
+ if (debug) {
267
+ console.log(`Running pre-plugin: ${plugin.name}`);
268
+ }
269
+ await plugin.fn(projectDir, config);
262
270
  }
263
- await plugin.fn(projectDir, config);
264
271
  }
265
272
  }
266
- if (existsSync(config.tmp)) {
267
- if (debug) {
268
- console.log(`Removing existing temp folder: ${config.tmp}`);
273
+ if (isFullBuild || !tempExists) {
274
+ if (tempExists) {
275
+ rmSync(config.tmp, { recursive: true });
269
276
  }
270
- rmSync(config.tmp, { recursive: true });
271
- }
272
- await cp(projectDir, config.tmp, {
273
- recursive: true,
274
- filter: (src) => {
275
- const relative = src.replace(join(projectDir, ""), "");
276
- if (relative.startsWith(join("assets", "")) || relative.startsWith(join("node_modules", ""))) {
277
- return false;
277
+ await cp(projectDir, config.tmp, {
278
+ recursive: true,
279
+ filter: (src) => {
280
+ const relative = src.replace(join(projectDir, ""), "");
281
+ if (relative.startsWith(join("assets", "")) || relative.startsWith(join("node_modules", ""))) {
282
+ return false;
283
+ }
284
+ return true;
278
285
  }
279
- return true;
286
+ });
287
+ } else {
288
+ const srcFile = join(projectDir, changedRelative);
289
+ const destFile = join(config.tmp, changedRelative);
290
+ const destDir = dirname(destFile);
291
+ if (!existsSync(destDir)) {
292
+ mkdirSync(destDir, { recursive: true });
280
293
  }
281
- });
294
+ if (existsSync(srcFile)) {
295
+ await cp(srcFile, destFile);
296
+ }
297
+ }
282
298
  await cp(
283
- // in a built situation, __dirname is the dist folder of defuss-ssg
284
299
  resolve(join(__dirname$1, "components", "index.mjs")),
285
300
  join(tmpComponentsDir, "hydrate.tsx")
286
- // any valid JS is always a valid TS file
287
301
  );
288
302
  await cp(
289
- // in a built situation, __dirname is the dist folder of defuss-ssg
290
303
  resolve(join(__dirname$1, "runtime.mjs")),
291
304
  join(tmpComponentsDir, "runtime.ts")
292
- // any valid JS is always a valid TS file
293
305
  );
294
- await esbuild.build({
295
- entryPoints: [join(tmpPagesDir, "**/*.mdx")],
296
- format: "esm",
297
- bundle: true,
298
- sourcemap: true,
299
- jsxDev: true,
300
- target: ["esnext"],
301
- outdir: tmpPagesDir,
302
- plugins: [
303
- mdx({
304
- // using the defuss jsxImportSource so that the output code contains JSX runtime calls
305
- // and can be rendered to HTML here on the server (in Node.js).
306
- jsxImportSource: "defuss",
307
- development: true,
308
- // We also use any remark/rehype plugins specified in the config file.
309
- remarkPlugins: config.remarkPlugins,
310
- rehypePlugins: config.rehypePlugins
311
- })
312
- ]
313
- });
314
- await esbuild.build({
315
- entryPoints: [
316
- join(tmpComponentsDir, "**/*.tsx"),
317
- join(tmpComponentsDir, "**/*.ts")
318
- ],
319
- format: "esm",
320
- bundle: true,
321
- // making sure we can do code splitting for shared dependencies (e.g. defuss lib)
322
- splitting: true,
323
- target: ["esnext"],
324
- outdir: tmpComponentsDir
325
- });
326
- const outputFiles = await glob.async(join(tmpPagesDir, "**/*.js"));
327
- if (!existsSync(outputProjectDir)) {
328
- mkdirSync(outputProjectDir, { recursive: true });
306
+ if (changeKind !== "asset") {
307
+ const pageEntryPoints = changeKind === "page" ? [join(config.tmp, changedRelative)] : [join(tmpPagesDir, "**/*.mdx")];
308
+ await esbuild.build({
309
+ entryPoints: pageEntryPoints,
310
+ format: "esm",
311
+ bundle: true,
312
+ sourcemap: true,
313
+ jsxDev: true,
314
+ target: ["esnext"],
315
+ outdir: tmpPagesDir,
316
+ plugins: [
317
+ mdx({
318
+ jsxImportSource: "defuss",
319
+ development: true,
320
+ remarkPlugins: config.remarkPlugins,
321
+ rehypePlugins: config.rehypePlugins
322
+ })
323
+ ]
324
+ });
329
325
  }
330
- for (const outputFile of outputFiles) {
331
- const outputHtmlFilePath = outputFile.replace(".js", ".html");
332
- const relativeOutputHtmlFilePath = outputHtmlFilePath.replace(
333
- `${tmpPagesDir}${sep}`,
334
- ""
335
- );
336
- if (debug) {
337
- console.log("Processing output file (JS):", outputFile);
338
- console.log("Output HTML file path:", outputHtmlFilePath);
339
- console.log("Relative output HTML path:", relativeOutputHtmlFilePath);
326
+ if (isFullBuild || changeKind === "component") {
327
+ await esbuild.build({
328
+ entryPoints: [
329
+ join(tmpComponentsDir, "**/*.tsx"),
330
+ join(tmpComponentsDir, "**/*.ts")
331
+ ],
332
+ format: "esm",
333
+ bundle: true,
334
+ splitting: true,
335
+ target: ["esnext"],
336
+ outdir: tmpComponentsDir
337
+ });
338
+ }
339
+ if (changeKind !== "asset") {
340
+ let outputFiles;
341
+ if (changeKind === "page") {
342
+ const jsFile = join(config.tmp, changedRelative.replace(/\.mdx$/, ".js"));
343
+ outputFiles = existsSync(jsFile) ? [jsFile] : [];
344
+ } else {
345
+ outputFiles = await glob.async(join(tmpPagesDir, "**/*.js"));
340
346
  }
341
- const code = await readFile(outputFile, "utf-8");
342
- const encoded = Buffer.from(code).toString("base64");
343
- const dataUrl = `data:text/javascript;base64,${encoded}`;
344
- const exports$1 = await import(dataUrl);
345
- if (debug) {
346
- console.log("exports", exports$1);
347
+ if (!existsSync(outputProjectDir)) {
348
+ mkdirSync(outputProjectDir, { recursive: true });
347
349
  }
348
- let vdom = exports$1.default(exports$1);
349
- for (const plugin of config.plugins || []) {
350
- if (plugin.phase === "page-vdom" && (plugin.mode === mode || plugin.mode === "both")) {
351
- if (debug) {
352
- console.log(`Running page-vdom plugin: ${plugin.name}`);
350
+ for (const outputFile of outputFiles) {
351
+ const outputHtmlFilePath = outputFile.replace(".js", ".html");
352
+ const relativeOutputHtmlFilePath = outputHtmlFilePath.replace(
353
+ `${tmpPagesDir}${sep}`,
354
+ ""
355
+ );
356
+ if (debug) {
357
+ console.log("Processing output file (JS):", outputFile);
358
+ console.log("Relative output HTML path:", relativeOutputHtmlFilePath);
359
+ }
360
+ const code = await readFile(outputFile, "utf-8");
361
+ const encoded = Buffer.from(code).toString("base64");
362
+ const dataUrl = `data:text/javascript;base64,${encoded}`;
363
+ const exports$1 = await import(dataUrl);
364
+ if (debug) {
365
+ console.log("exports", exports$1);
366
+ }
367
+ let vdom = exports$1.default(exports$1);
368
+ for (const plugin of config.plugins || []) {
369
+ if (plugin.phase === "page-vdom" && (plugin.mode === mode || plugin.mode === "both")) {
370
+ if (debug) {
371
+ console.log(`Running page-vdom plugin: ${plugin.name}`);
372
+ }
373
+ vdom = await plugin.fn(
374
+ vdom,
375
+ relativeOutputHtmlFilePath,
376
+ projectDir,
377
+ config,
378
+ exports$1
379
+ );
353
380
  }
354
- vdom = await plugin.fn(
355
- vdom,
356
- relativeOutputHtmlFilePath,
357
- projectDir,
358
- config,
359
- exports$1
360
- );
361
381
  }
362
- }
363
- const browserGlobals = getBrowserGlobals();
364
- const document = getDocument(false, browserGlobals);
365
- browserGlobals.document = document;
366
- let el = renderSync(vdom, document.documentElement, {
367
- browserGlobals
368
- });
369
- for (const plugin of config.plugins || []) {
370
- if (plugin.phase === "page-dom" && (plugin.mode === mode || plugin.mode === "both")) {
371
- if (debug) {
372
- console.log(`Running page-dom plugin: ${plugin.name}`);
382
+ const browserGlobals = getBrowserGlobals();
383
+ const document = getDocument(false, browserGlobals);
384
+ browserGlobals.document = document;
385
+ let el = renderSync(vdom, document.documentElement, {
386
+ browserGlobals
387
+ });
388
+ for (const plugin of config.plugins || []) {
389
+ if (plugin.phase === "page-dom" && (plugin.mode === mode || plugin.mode === "both")) {
390
+ if (debug) {
391
+ console.log(`Running page-dom plugin: ${plugin.name}`);
392
+ }
393
+ el = await plugin.fn(
394
+ el,
395
+ relativeOutputHtmlFilePath,
396
+ projectDir,
397
+ config
398
+ );
373
399
  }
374
- el = await plugin.fn(
375
- el,
376
- relativeOutputHtmlFilePath,
377
- projectDir,
378
- config
379
- );
380
400
  }
381
- }
382
- let html = renderToString(el);
383
- for (const plugin of config.plugins || []) {
384
- if (plugin.phase === "page-html" && (plugin.mode === mode || plugin.mode === "both")) {
385
- if (debug) {
386
- console.log(`Running page-html plugin: ${plugin.name}`);
401
+ let html = renderToString(el);
402
+ for (const plugin of config.plugins || []) {
403
+ if (plugin.phase === "page-html" && (plugin.mode === mode || plugin.mode === "both")) {
404
+ if (debug) {
405
+ console.log(`Running page-html plugin: ${plugin.name}`);
406
+ }
407
+ html = await plugin.fn(
408
+ html,
409
+ relativeOutputHtmlFilePath,
410
+ projectDir,
411
+ config
412
+ );
387
413
  }
388
- html = await plugin.fn(
389
- html,
390
- relativeOutputHtmlFilePath,
391
- projectDir,
392
- config
393
- );
394
414
  }
415
+ const finalOutputFile = join(
416
+ projectDir,
417
+ config.output,
418
+ relativeOutputHtmlFilePath
419
+ );
420
+ const finalOutputDir = dirname(finalOutputFile);
421
+ if (!existsSync(finalOutputDir)) {
422
+ mkdirSync(finalOutputDir, { recursive: true });
423
+ }
424
+ await writeFile(finalOutputFile, html);
395
425
  }
396
- if (debug) {
397
- console.log("Writing HTML file", outputHtmlFilePath);
398
- }
399
- if (debug) {
400
- console.log("Relative HTML path:", relativeOutputHtmlFilePath);
401
- }
402
- const finalOutputFile = join(
403
- projectDir,
404
- config.output,
405
- relativeOutputHtmlFilePath
406
- );
407
- if (debug) {
408
- console.log("Full HTML output path:", finalOutputFile);
409
- }
410
- const finalOutputDir = dirname(finalOutputFile);
411
- if (!existsSync(finalOutputDir)) {
412
- mkdirSync(finalOutputDir, { recursive: true });
413
- }
414
- await writeFile(finalOutputFile, html);
415
426
  }
416
- await cp(tmpComponentsDir, outputComponentsDir, { recursive: true });
417
- await cp(inputAssetsDir, outputAssetsDir, { recursive: true });
418
- for (const plugin of config.plugins || []) {
419
- if (plugin.phase === "post" && (plugin.mode === mode || plugin.mode === "both")) {
420
- if (debug) {
421
- console.log(`Running post-plugin: ${plugin.name}`);
427
+ if (isFullBuild || changeKind === "component") {
428
+ await cp(tmpComponentsDir, outputComponentsDir, { recursive: true });
429
+ }
430
+ if (isFullBuild || changeKind === "asset") {
431
+ await cp(inputAssetsDir, outputAssetsDir, { recursive: true });
432
+ }
433
+ if (isFullBuild || changeKind === "component") {
434
+ for (const plugin of config.plugins || []) {
435
+ if (plugin.phase === "post" && (plugin.mode === mode || plugin.mode === "both")) {
436
+ if (debug) {
437
+ console.log(`Running post-plugin: ${plugin.name}`);
438
+ }
439
+ await plugin.fn(projectDir, config);
422
440
  }
423
- await plugin.fn(projectDir, config);
424
441
  }
425
442
  }
426
- if (!debug) {
443
+ if (mode === "build" && !debug) {
427
444
  rmSync(config.tmp, { recursive: true });
428
445
  }
429
446
  const endTime = performance.now();
430
447
  const totalTime = (endTime - startTime) / 1e3;
431
- console.log(`Build completed in ${totalTime.toFixed(2)} seconds.`);
448
+ const label = isFullBuild ? "Full build" : `Incremental build (${changeKind}: ${changedRelative})`;
449
+ console.log(`${label} completed in ${totalTime.toFixed(2)} seconds.`);
432
450
  return { code: "OK", message: "Build completed successfully" };
433
451
  };
434
452
 
@@ -491,10 +509,10 @@ const serve = async ({
491
509
  path: "/livereload"
492
510
  });
493
511
  let isBuilding = false;
494
- let pendingBuild = false;
512
+ let pendingBuild = null;
495
513
  const triggerBuild = async (filePath) => {
496
514
  if (isBuilding) {
497
- pendingBuild = true;
515
+ pendingBuild = filePath;
498
516
  if (debug) {
499
517
  console.log("Build scheduled after current one completes");
500
518
  }
@@ -502,7 +520,7 @@ const serve = async ({
502
520
  }
503
521
  isBuilding = true;
504
522
  try {
505
- await build({ projectDir, debug, mode: "serve" });
523
+ await build({ projectDir, debug, mode: "serve", changedFile: filePath });
506
524
  liveReloadServer.clients.forEach((client) => {
507
525
  if (client.readyState === 1) {
508
526
  client.send(
@@ -518,11 +536,12 @@ const serve = async ({
518
536
  } finally {
519
537
  isBuilding = false;
520
538
  if (pendingBuild) {
521
- pendingBuild = false;
539
+ const pending = pendingBuild;
540
+ pendingBuild = null;
522
541
  if (debug) {
523
542
  console.log("Running pending build");
524
543
  }
525
- await triggerBuild(filePath);
544
+ await triggerBuild(pending);
526
545
  }
527
546
  }
528
547
  };
@@ -30,6 +30,12 @@ interface BuildOptions {
30
30
  * Defaults to "build"
31
31
  */
32
32
  mode: Omit<BuildMode, "both">;
33
+ /**
34
+ * When set, only the changed file is rebuilt instead of the entire project.
35
+ * This is used by the dev server for incremental rebuilds.
36
+ * The path should be absolute.
37
+ */
38
+ changedFile?: string;
33
39
  }
34
40
  type PluginFn = PluginFnPageHtml | PluginFnPageVdom | PluginFnPageDom | PluginFnPrePost;
35
41
  /**
@@ -30,6 +30,12 @@ interface BuildOptions {
30
30
  * Defaults to "build"
31
31
  */
32
32
  mode: Omit<BuildMode, "both">;
33
+ /**
34
+ * When set, only the changed file is rebuilt instead of the entire project.
35
+ * This is used by the dev server for incremental rebuilds.
36
+ * The path should be absolute.
37
+ */
38
+ changedFile?: string;
33
39
  }
34
40
  type PluginFn = PluginFnPageHtml | PluginFnPageVdom | PluginFnPageDom | PluginFnPrePost;
35
41
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "defuss-ssg",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -26,8 +26,8 @@
26
26
  "pretest": "bun run build",
27
27
  "prebuild": "bun run clean",
28
28
  "build": "pkgroll",
29
- "cli-build": "node ./dist/cli.mjs build ./example",
30
- "cli-serve": "node ./dist/cli.mjs serve ./example",
29
+ "cli-build": "node ./dist/cli.mjs build ../../example-ssg/",
30
+ "cli-serve": "node ./dist/cli.mjs serve ../../example-ssg/",
31
31
  "test": "echo 'No tests available'",
32
32
  "bench": "npx autocannon -p 32 -w 8 -c 200 -d 20 -m POST -H \"content-type: application/json\" -b '{\"hello\":\"world\"}' http://127.0.0.1:3000/body",
33
33
  "start": "tsx src/dynamic.ts",
@@ -90,7 +90,7 @@
90
90
  "@mdx-js/esbuild": "^3.1.1",
91
91
  "@types/ws": "^8.18.1",
92
92
  "chokidar": "^5.0.0",
93
- "defuss": "^3.1.0",
93
+ "defuss": "^3.2.0",
94
94
  "esbuild": "^0.27.3",
95
95
  "ultimate-express": "^2.0.17",
96
96
  "ultimate-ws": "^2.0.7",