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 ADDED
@@ -0,0 +1,289 @@
1
+ <h1 align="center">
2
+
3
+ <img src="assets/defuss_mascott.png" width="100px" />
4
+
5
+ <p align="center">
6
+ <code>defuss-ssg</code>
7
+ </p>
8
+
9
+ <sup align="center">
10
+
11
+ Simple Static Site Generator (SSG) for defuss - with support for Markdown, MDX, and Jinja2 templates
12
+
13
+ </sup>
14
+
15
+ </h1>
16
+
17
+ <h3 align="center">
18
+ Usage
19
+ </h3>
20
+
21
+ Simply generate a static site from a content directory to an output directory with full `defuss`-MDX (GFM + Frontmatter) support:
22
+
23
+ ```bash
24
+ npx defuss-ssg build ./folder
25
+ ```
26
+
27
+ Or install globally or locally in a project:
28
+
29
+ ```bash
30
+ npm install -g defuss-ssg
31
+ ```
32
+
33
+ And then run (in an NPM script or globally):
34
+
35
+ <h4>One-time builds</h4>
36
+
37
+ ```bash
38
+ defuss-ssg build ./folder
39
+ ```
40
+
41
+ <h4>Serve-mode with automatic re-build on change</h4>
42
+
43
+ ```bash
44
+ defuss-ssg serve ./folder
45
+ ```
46
+
47
+ This starts a local server at http://localhost:3000 and watches for changes in:
48
+
49
+ - `pages/` directory
50
+ - `components/` directory
51
+ - `assets/` directory
52
+
53
+ Changes trigger automatic rebuilds, with the last change always taking priority to prevent build queueing issues.
54
+
55
+ <h4>Programmatic API</h4>
56
+
57
+ Advanced users may want to use the library programmatically:
58
+
59
+ ```typescript
60
+ import { build, serve } from "defuss-ssg";
61
+
62
+ (async () => {
63
+ // One-time build
64
+ await build({
65
+ projectDir: "./my-site",
66
+ debug: true,
67
+ });
68
+
69
+ // Or serve with auto-rebuild
70
+ await serve({
71
+ projectDir: "./my-site",
72
+ debug: true,
73
+ });
74
+ })();
75
+ ```
76
+
77
+ <h3 align="center">
78
+ Overview
79
+ </h3>
80
+
81
+ > `defuss-ssg` is a CLI tool and library for building static websites using modern JavaScript/TypeScript and `defuss`. It reads content files (Markdown, MDX) from a specified directory, processes them with MDX plugins, compiles components with esbuild, and outputs fully static HTML sites ready for deployment.
82
+
83
+ > It supports a plugin system for extending the build process at various phases (pre-build, post-build, page-level transformations), automatic file watching and rebuilding in serve mode, and seamless integration with defuss components for interactive features.
84
+
85
+ <h3 align="center">
86
+
87
+ Features
88
+
89
+ </h3>
90
+
91
+ - **MDX Support**: Full Markdown + JSX support with frontmatter parsing
92
+ - **Component Integration**: Use defuss components in your MDX files
93
+ - **Plugin System**: Extend the build process with custom plugins at multiple phases
94
+ - **Fast Compilation**: Powered by esbuild for quick builds and hot reloading
95
+ - **Serve Mode**: Built-in development server with file watching and auto-rebuild
96
+ - **TypeScript Ready**: Full TypeScript support for components and configuration
97
+ - **Asset Handling**: Automatic copying of static assets to output directory
98
+ - **Flexible Configuration**: Configurable via TypeScript config file with sensible defaults
99
+
100
+ <h3 align="center">
101
+
102
+ Example site project structure
103
+
104
+ </h3>
105
+
106
+ Create a project structure like this:
107
+
108
+ ```typescript
109
+ my-site/
110
+ ├── pages/
111
+ │ ├── index.mdx
112
+ │ └── blog/
113
+ │ └── hello-world.mdx
114
+ ├── components/
115
+ │ └── button.tsx
116
+ ├── assets/
117
+ │ └── styles.css
118
+ └── config.ts
119
+ ```
120
+ Then run `defuss-ssg build ./my-site` and a `dist` folder will be created with the complete static build.
121
+
122
+ <h3 align="center">
123
+
124
+ Config file
125
+
126
+ </h3>
127
+
128
+ You can customize the paths and behaviour of the build process, by creating a simple `config.ts` file in the project folder.
129
+
130
+ ##### Example `config.ts` file
131
+
132
+ ```typescript
133
+ import { remarkPlugins, rehypePlugins } from "defuss-ssg";
134
+
135
+ export default {
136
+ pages: "pages",
137
+ output: "dist",
138
+ components: "components",
139
+ assets: "assets",
140
+ remarkPlugins: [...remarkPlugins], // default remark plugins
141
+ rehypePlugins: [...rehypePlugins], // default rehype plugins
142
+ plugins: [],
143
+ };
144
+ ```
145
+
146
+ You may add any `remark` and `rehype` plugin of your choice. See the `MDX` documentation for more informations on Remark and Rehype.
147
+
148
+ `defuss-ssg` plugins can be registered via the `plugins` array and are executed in order of registration, in each build phase.
149
+
150
+ ##### Example MDX page (`pages/index.mdx`)
151
+
152
+ ```mdx
153
+ ---
154
+ title: Home Page
155
+ ---
156
+
157
+ import Button from "../components/button.js"
158
+
159
+ # Welcome to my site
160
+
161
+ This is a **markdown** page with JSX components.
162
+
163
+ <Button>Click me</Button>
164
+ ```
165
+
166
+ ##### Example Button component (`components/button.tsx`)
167
+
168
+ Components are imported as `.js` but saved as `.tsx`:
169
+
170
+ ```typescript
171
+ export const Button = ({ label }: { label: string }) => {
172
+ return (
173
+ <button type="button" onClick={() => alert("Button clicked!")}>
174
+ {label}
175
+ </button>
176
+ );
177
+ };
178
+ ```
179
+
180
+
181
+ <h3 align="center">
182
+
183
+ Plugin System
184
+
185
+ </h3>
186
+
187
+ Extend the build process with plugins that run at different phases:
188
+
189
+ ```typescript
190
+ import { rule, transval, access } from 'defuss-transval';
191
+
192
+ type UserData = {
193
+ user: {
194
+ profile: {
195
+ name: string;
196
+ email: string;
197
+ settings: {
198
+ theme: 'light' | 'dark';
199
+ notifications: boolean;
200
+ };
201
+ };
202
+ posts: Array<{
203
+ title: string;
204
+ published: boolean;
205
+ import { SsgPlugin } from "defuss-ssg";
206
+
207
+ const myPlugin: SsgPlugin = {
208
+ name: "my-plugin",
209
+ phase: "page-html", // "pre" | "post" | "page-vdom" | "page-dom" | "page-html"
210
+ fn: (html, relativePath, config) => {
211
+ // Modify HTML before writing
212
+ return html.replace("old-text", "new-text");
213
+ },
214
+ };
215
+
216
+ export default {
217
+ plugins: [myPlugin],
218
+ // ... other config
219
+ };
220
+ ```
221
+
222
+ Available plugin phases:
223
+
224
+ - **pre**: Before build starts
225
+ - **page-vdom**: After VDOM creation for each page
226
+ - **page-dom**: After DOM rendering for each page
227
+ - **page-html**: After HTML serialization for each page
228
+ - **post**: After build completes
229
+
230
+
231
+ <h3 align="center">
232
+
233
+ MDX Features
234
+
235
+ </h3>
236
+
237
+ `defuss-ssg` supports full MDX with `defuss` components and common GFM Markdown features:
238
+
239
+ - **Frontmatter**: YAML/TOML metadata extraction - the `meta` object holds frontmatter data - use e.g. `{ meta.title }` for page title defined in frontmatter like this:
240
+ ```mdx
241
+ ---
242
+ title: My Page
243
+ ---
244
+ ```
245
+
246
+ - **JSX Components**: Use `defuss` components in your content
247
+ - **Math Support**: KaTeX rendering with `$...$` and `$$...$$`
248
+ - **Custom Plugins**: Extend MDX processing with remark/rehype plugins
249
+
250
+ <h3 align="center">
251
+
252
+ Build Process
253
+
254
+ </h3>
255
+
256
+ The build process follows these steps:
257
+
258
+ 1. **Copy Project**: Copy all files to temporary directory
259
+ 2. **Compile MDX**: Process MDX files to ESM JavaScript
260
+ 3. **Compile Components**: Bundle components with esbuild
261
+ 4. **Evaluate Pages**: Run page functions to generate VDOM
262
+ 5. **Render HTML**: Convert VDOM to HTML using defuss/server
263
+ 6. **Run Plugins**: Execute plugins at various phases
264
+ 7. **Copy Assets**: Copy static assets to output
265
+ 8. **Clean Up**: Remove temporary files (unless debug mode)
266
+
267
+ <h3 align="center">
268
+
269
+ CLI Reference
270
+
271
+ </h3>
272
+
273
+ ```bash
274
+ defuss-ssg <command> <folder>
275
+
276
+ Commands:
277
+ build <folder> Build the static site
278
+ serve <folder> Serve with auto-rebuild on changes
279
+ ```
280
+
281
+ <p align="center">
282
+
283
+ <img src="https://raw.githubusercontent.com/kyr0/defuss/refs/heads/main/assets/defuss_comic.png" width="400px" />
284
+
285
+ </p>
286
+
287
+ <p align="center">
288
+ <i><b>Come visit us on <code>defuss</code> Island!</b></i>
289
+ </p>
package/dist/cli.cjs ADDED
@@ -0,0 +1,47 @@
1
+ 'use strict';
2
+
3
+ var serve = require('./serve-BaOtT5p7.cjs');
4
+ var node_path = require('node:path');
5
+ require('chokidar');
6
+ require('express');
7
+ require('serve-static');
8
+ require('node:fs');
9
+ require('esbuild');
10
+ require('remark-frontmatter');
11
+ require('rehype-katex');
12
+ require('remark-math');
13
+ require('remark-mdx-frontmatter');
14
+ require('./tailwind-C4AuHybm.cjs');
15
+ require('@mdx-js/esbuild');
16
+ require('fast-glob');
17
+ require('defuss/server');
18
+ require('node:fs/promises');
19
+ require('node:url');
20
+
21
+ (async () => {
22
+ const args = process.argv.slice(2);
23
+ const command = args[0];
24
+ const folder = args[1];
25
+ const usage = "Usage: defuss-ssg <build|serve> <folder>";
26
+ if (!command || !folder) {
27
+ console.error(usage);
28
+ process.exit(1);
29
+ }
30
+ const projectDir = node_path.resolve(folder);
31
+ if (command === "build") {
32
+ console.log(`Building ${folder}...`);
33
+ await serve.build({
34
+ projectDir,
35
+ debug: true,
36
+ mode: "build"
37
+ });
38
+ } else if (command === "serve") {
39
+ console.log(`Serving ${folder}...`);
40
+ await serve.serve({
41
+ projectDir,
42
+ debug: true});
43
+ } else {
44
+ console.error(usage);
45
+ process.exit(1);
46
+ }
47
+ })();
package/dist/cli.mjs ADDED
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+ import { d as build, s as serve } from './serve-COHw7ASj.mjs';
3
+ import { resolve } from 'node:path';
4
+ import 'chokidar';
5
+ import 'express';
6
+ import 'serve-static';
7
+ import 'node:fs';
8
+ import 'esbuild';
9
+ import 'remark-frontmatter';
10
+ import 'rehype-katex';
11
+ import 'remark-math';
12
+ import 'remark-mdx-frontmatter';
13
+ import './tailwind-DV23JSh-.mjs';
14
+ import '@mdx-js/esbuild';
15
+ import 'fast-glob';
16
+ import 'defuss/server';
17
+ import 'node:fs/promises';
18
+ import 'node:url';
19
+
20
+ (async () => {
21
+ const args = process.argv.slice(2);
22
+ const command = args[0];
23
+ const folder = args[1];
24
+ const usage = "Usage: defuss-ssg <build|serve> <folder>";
25
+ if (!command || !folder) {
26
+ console.error(usage);
27
+ process.exit(1);
28
+ }
29
+ const projectDir = resolve(folder);
30
+ if (command === "build") {
31
+ console.log(`Building ${folder}...`);
32
+ await build({
33
+ projectDir,
34
+ debug: true,
35
+ mode: "build"
36
+ });
37
+ } else if (command === "serve") {
38
+ console.log(`Serving ${folder}...`);
39
+ await serve({
40
+ projectDir,
41
+ debug: true});
42
+ } else {
43
+ console.error(usage);
44
+ process.exit(1);
45
+ }
46
+ })();
@@ -0,0 +1,27 @@
1
+ 'use strict';
2
+
3
+ var jsxRuntime = require('defuss/jsx-runtime');
4
+
5
+ function Hydrate({
6
+ module,
7
+ exportName = "default",
8
+ props = {},
9
+ children
10
+ }) {
11
+ const id = `dh_${Math.random().toString(36).slice(2)}`;
12
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
13
+ children,
14
+ /* @__PURE__ */ jsxRuntime.jsx(
15
+ "div",
16
+ {
17
+ "data-hydrate": true,
18
+ "data-module": module,
19
+ "data-export": exportName,
20
+ "data-props-id": id
21
+ }
22
+ ),
23
+ /* @__PURE__ */ jsxRuntime.jsx("script", { type: "application/json", id, children: JSON.stringify(props) })
24
+ ] });
25
+ }
26
+
27
+ exports.Hydrate = Hydrate;
@@ -0,0 +1,10 @@
1
+ import { Props } from 'defuss';
2
+
3
+ interface HydrateProps extends Props {
4
+ module: string;
5
+ exportName?: string;
6
+ props?: Record<string, any>;
7
+ }
8
+ declare function Hydrate({ module, exportName, props, children, }: HydrateProps): any;
9
+
10
+ export { Hydrate, type HydrateProps };
@@ -0,0 +1,10 @@
1
+ import { Props } from 'defuss';
2
+
3
+ interface HydrateProps extends Props {
4
+ module: string;
5
+ exportName?: string;
6
+ props?: Record<string, any>;
7
+ }
8
+ declare function Hydrate({ module, exportName, props, children, }: HydrateProps): any;
9
+
10
+ export { Hydrate, type HydrateProps };
@@ -0,0 +1,25 @@
1
+ import { jsxs, Fragment, jsx } from 'defuss/jsx-runtime';
2
+
3
+ function Hydrate({
4
+ module,
5
+ exportName = "default",
6
+ props = {},
7
+ children
8
+ }) {
9
+ const id = `dh_${Math.random().toString(36).slice(2)}`;
10
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
11
+ children,
12
+ /* @__PURE__ */ jsx(
13
+ "div",
14
+ {
15
+ "data-hydrate": true,
16
+ "data-module": module,
17
+ "data-export": exportName,
18
+ "data-props-id": id
19
+ }
20
+ ),
21
+ /* @__PURE__ */ jsx("script", { type: "application/json", id, children: JSON.stringify(props) })
22
+ ] });
23
+ }
24
+
25
+ export { Hydrate };
package/dist/index.cjs ADDED
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var serve = require('./serve-BaOtT5p7.cjs');
4
+ require('chokidar');
5
+ require('express');
6
+ require('serve-static');
7
+ require('node:path');
8
+ require('node:fs');
9
+ require('esbuild');
10
+ require('remark-frontmatter');
11
+ require('rehype-katex');
12
+ require('remark-math');
13
+ require('remark-mdx-frontmatter');
14
+ require('./tailwind-C4AuHybm.cjs');
15
+ require('@mdx-js/esbuild');
16
+ require('fast-glob');
17
+ require('defuss/server');
18
+ require('node:fs/promises');
19
+ require('node:url');
20
+
21
+
22
+
23
+ exports.build = serve.build;
24
+ exports.configDefaults = serve.configDefaults;
25
+ exports.readConfig = serve.readConfig;
26
+ exports.rehypePlugins = serve.rehypePlugins;
27
+ exports.remarkPlugins = serve.remarkPlugins;
28
+ exports.serve = serve.serve;
@@ -0,0 +1,25 @@
1
+ import { R as RemarkPlugins, a as RehypePlugins, S as SsgConfig, B as BuildOptions } from './types-D1n7GtYH.js';
2
+ export { e as BuildMode, f as PluginFn, c as PluginFnPageDom, P as PluginFnPageHtml, b as PluginFnPageVdom, d as PluginFnPrePost, g as SsgPlugin } from './types-D1n7GtYH.js';
3
+ import '@mdx-js/esbuild';
4
+ import 'defuss/server';
5
+
6
+ declare const remarkPlugins: RemarkPlugins;
7
+ declare const rehypePlugins: RehypePlugins;
8
+
9
+ declare const readConfig: (projectDir: string, debug: boolean) => Promise<SsgConfig>;
10
+ declare const configDefaults: SsgConfig;
11
+
12
+ /**
13
+ * A single, complete build process for a static site project.
14
+ * @param projectDir The root directory of the project to build
15
+ */
16
+ declare const build: ({ projectDir, debug, mode, }: BuildOptions) => Promise<void>;
17
+
18
+ /**
19
+ * A simple static file server to serve the generated static site from the output folder.
20
+ * Also watches the input, components and assets folders for changes and rebuilds the site on-the-fly.
21
+ * @param projectDir The root directory of the project to build
22
+ */
23
+ declare const serve: ({ projectDir, debug }: BuildOptions) => Promise<void>;
24
+
25
+ export { BuildOptions, RehypePlugins, RemarkPlugins, SsgConfig, build, configDefaults, readConfig, rehypePlugins, remarkPlugins, serve };
@@ -0,0 +1,25 @@
1
+ import { R as RemarkPlugins, a as RehypePlugins, S as SsgConfig, B as BuildOptions } from './types-D1n7GtYH.js';
2
+ export { e as BuildMode, f as PluginFn, c as PluginFnPageDom, P as PluginFnPageHtml, b as PluginFnPageVdom, d as PluginFnPrePost, g as SsgPlugin } from './types-D1n7GtYH.js';
3
+ import '@mdx-js/esbuild';
4
+ import 'defuss/server';
5
+
6
+ declare const remarkPlugins: RemarkPlugins;
7
+ declare const rehypePlugins: RehypePlugins;
8
+
9
+ declare const readConfig: (projectDir: string, debug: boolean) => Promise<SsgConfig>;
10
+ declare const configDefaults: SsgConfig;
11
+
12
+ /**
13
+ * A single, complete build process for a static site project.
14
+ * @param projectDir The root directory of the project to build
15
+ */
16
+ declare const build: ({ projectDir, debug, mode, }: BuildOptions) => Promise<void>;
17
+
18
+ /**
19
+ * A simple static file server to serve the generated static site from the output folder.
20
+ * Also watches the input, components and assets folders for changes and rebuilds the site on-the-fly.
21
+ * @param projectDir The root directory of the project to build
22
+ */
23
+ declare const serve: ({ projectDir, debug }: BuildOptions) => Promise<void>;
24
+
25
+ export { BuildOptions, RehypePlugins, RemarkPlugins, SsgConfig, build, configDefaults, readConfig, rehypePlugins, remarkPlugins, serve };
package/dist/index.mjs ADDED
@@ -0,0 +1,17 @@
1
+ export { d as build, c as configDefaults, b as readConfig, a as rehypePlugins, r as remarkPlugins, s as serve } from './serve-COHw7ASj.mjs';
2
+ import 'chokidar';
3
+ import 'express';
4
+ import 'serve-static';
5
+ import 'node:path';
6
+ import 'node:fs';
7
+ import 'esbuild';
8
+ import 'remark-frontmatter';
9
+ import 'rehype-katex';
10
+ import 'remark-math';
11
+ import 'remark-mdx-frontmatter';
12
+ import './tailwind-DV23JSh-.mjs';
13
+ import '@mdx-js/esbuild';
14
+ import 'fast-glob';
15
+ import 'defuss/server';
16
+ import 'node:fs/promises';
17
+ import 'node:url';
@@ -0,0 +1,8 @@
1
+ 'use strict';
2
+
3
+ var tailwind = require('../tailwind-C4AuHybm.cjs');
4
+ require('node:path');
5
+
6
+
7
+
8
+ exports.tailwindPlugin = tailwind.tailwindPlugin;
@@ -0,0 +1,7 @@
1
+ import { g as SsgPlugin, d as PluginFnPrePost } from '../types-D1n7GtYH.js';
2
+ import '@mdx-js/esbuild';
3
+ import 'defuss/server';
4
+
5
+ declare const tailwindPlugin: SsgPlugin<PluginFnPrePost>;
6
+
7
+ export { tailwindPlugin };
@@ -0,0 +1,7 @@
1
+ import { g as SsgPlugin, d as PluginFnPrePost } from '../types-D1n7GtYH.js';
2
+ import '@mdx-js/esbuild';
3
+ import 'defuss/server';
4
+
5
+ declare const tailwindPlugin: SsgPlugin<PluginFnPrePost>;
6
+
7
+ export { tailwindPlugin };
@@ -0,0 +1,2 @@
1
+ export { t as tailwindPlugin } from '../tailwind-DV23JSh-.mjs';
2
+ import 'node:path';
@@ -0,0 +1,26 @@
1
+ 'use strict';
2
+
3
+ var defuss = require('defuss');
4
+ require('defuss/client');
5
+
6
+ async function hydrateIslands() {
7
+ const nodes = defuss.$("[data-hydrate]");
8
+ await Promise.all(
9
+ Array.from(nodes).map(async (el) => {
10
+ const modPath = el.dataset.module;
11
+ const exportKey = el.dataset.export || "default";
12
+ const propsId = el.dataset.propsId;
13
+ JSON.parse(
14
+ document.getElementById(propsId).textContent || "{}"
15
+ );
16
+ const mod = await import(
17
+ /* @vite-ignore */
18
+ modPath
19
+ );
20
+ mod[exportKey];
21
+ el.previousElementSibling;
22
+ })
23
+ );
24
+ }
25
+
26
+ exports.hydrateIslands = hydrateIslands;
@@ -0,0 +1,3 @@
1
+ declare function hydrateIslands(): Promise<void>;
2
+
3
+ export { hydrateIslands };
@@ -0,0 +1,3 @@
1
+ declare function hydrateIslands(): Promise<void>;
2
+
3
+ export { hydrateIslands };
@@ -0,0 +1,24 @@
1
+ import { $ } from 'defuss';
2
+ import 'defuss/client';
3
+
4
+ async function hydrateIslands() {
5
+ const nodes = $("[data-hydrate]");
6
+ await Promise.all(
7
+ Array.from(nodes).map(async (el) => {
8
+ const modPath = el.dataset.module;
9
+ const exportKey = el.dataset.export || "default";
10
+ const propsId = el.dataset.propsId;
11
+ JSON.parse(
12
+ document.getElementById(propsId).textContent || "{}"
13
+ );
14
+ const mod = await import(
15
+ /* @vite-ignore */
16
+ modPath
17
+ );
18
+ mod[exportKey];
19
+ el.previousElementSibling;
20
+ })
21
+ );
22
+ }
23
+
24
+ export { hydrateIslands };