summaryrefslogtreecommitdiff
path: root/README.md
blob: 26ccbe956c9c91f04cf308793c4bb47d2e363ef6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
# Docsify: Self-Hosted Setup

A complete guide to self-hosting Docsify with no external CDN dependencies. We follow the [manual creation](https://docsify.js.org/#/quickstart?id=manual-initialization) but download the JavaScript and CSS files locally so we don't have to worry if the domain cdn.jsdelivr.net get seized (who knows what's going to happen in the future). The result is just static files, so it runs on any web server — Apache, nginx, Caddy, or similar.

---

## Quick Start

If you just want a working site, run the bundled script from your document root. It performs every step in this guide automatically: it downloads and version-pins all assets, writes `index.html`, creates starter content, and generates a SHA-256 checksum manifest.

```bash
cd /path/to/your/docroot
bash /path/to/scripts/setup.sh
```

Re-running is safe: it refreshes the vendored assets and regenerates `index.html`, but never overwrites your Markdown files (`README.md`, `_sidebar.md`, or any pages you have added). Everything below explains what the script does and how to perform each step by hand.

---

## Prerequisites

- Any static web server (Apache, nginx, Caddy, or similar)
- `curl` (for downloading assets)

---

## Directory Structure

The final layout this guide produces, relative to your document root:

```
./
├── index.html          ← Docsify entry point
├── README.md           ← Homepage content
├── _sidebar.md         ← Sidebar navigation
├── getting-started.md  ← Example page
└── assets/
    ├── SHA256SUMS       ← SHA-256 of every downloaded asset
    ├── js/
    │   ├── docsify.min.js
    │   ├── search.min.js
    │   ├── docsify-copy-code.min.js
    │   ├── docsify-katex.js
    │   ├── prism-bash.min.js
    │   ├── prism-yaml.min.js
    │   ├── prism-python.min.js
    │   ├── prism-r.min.js
    │   ├── docsify-plugin-flexible-alerts.min.js
    │   ├── docsify-tabs.min.js
    │   ├── docsify-pagination.min.js
    │   ├── medium-zoom.min.js
    │   ├── docsify-sidebar-collapse.min.js
    │   ├── mermaid.min.js
    │   └── docsify-mermaid.js
    └── css/
        ├── vue.css
        ├── katex.min.css
        ├── medium-zoom.css
        ├── sidebar.min.css
        └── fonts/
            └── KaTeX_*.woff2   (20 KaTeX font files)
```

All commands in this guide assume you have already `cd`'d into your document root.

---

## Step 1: Create the Directory Structure

```bash
mkdir -p assets/js
mkdir -p assets/css
```

---

## Step 2: Download Docsify Assets

All files are downloaded from jsDelivr once and served locally thereafter. See all [docsify CDN files](https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/) on jsDelivr.

```bash
# Docsify core
curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/docsify.min.js" \
  -o assets/js/docsify.min.js

# Search plugin
curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/plugins/search.min.js" \
  -o assets/js/search.min.js

# Theme (Vue — clean, light)
curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/themes/vue.css" \
  -o assets/css/vue.css
```

### Alternative Themes

Replace `vue.css` in the command above with any of the following if preferred; see all [themes](https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/themes/).

* buble.css
* dark.css
* dolphin.css
* pure.css
* vue.css

### Syntax Highlighting (Prism)

Docsify **bundles Prism** and highlights a handful of languages out of the box —
`markup`/HTML, `css`, `clike`, and `javascript`. For any other language, download its
Prism component and load it **after** `docsify.min.js` (see Step 3) so it attaches to
Docsify's bundled Prism.

> **Do not download `prism-core.min.js`.** A standalone Prism core loaded after Docsify
> replaces Docsify's own Prism on the page; the language components then attach to the
> wrong instance and silently fail to highlight. You only need the language files below.

This guide adds bash, yaml, python, and r:

```bash
curl -L "https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-bash.min.js" \
  -o assets/js/prism-bash.min.js

curl -L "https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-yaml.min.js" \
  -o assets/js/prism-yaml.min.js

curl -L "https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-python.min.js" \
  -o assets/js/prism-python.min.js

curl -L "https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/prism-r.min.js" \
  -o assets/js/prism-r.min.js
```

To highlight more languages, download additional `prism-<lang>.min.js` files (browse the
[Prism components](https://cdn.jsdelivr.net/npm/prismjs@1.30.0/components/)) and add a matching
`<script>` tag in Step 3. A few Prism languages depend on others — if one does, download
its dependency too (Docsify already provides `clike`, the most common base grammar).

### Copy-to-Clipboard Button

Add a **copy** button to every fenced code block with the
[docsify-copy-code](https://github.com/jperasmus/docsify-copy-code) plugin. Like the
assets above, it is fetched once and served locally thereafter:

```bash
# Copy-to-clipboard plugin
curl -L "https://cdn.jsdelivr.net/npm/docsify-copy-code@3.0.2/dist/docsify-copy-code.min.js" \
  -o assets/js/docsify-copy-code.min.js
```

The plugin injects its own CSS via JavaScript, so there is **no separate CSS file**
to download. Just add its `<script>` tag to `index.html` **after** `docsify.min.js`
(see Step 3). Copying uses `document.execCommand('copy')`, so it works over plain
`http://` as well as `https://`.

It works with no configuration. To customise the button labels, add a `copyCode`
block to the `window.$docsify` object in `index.html`:

```js
copyCode: {
  buttonText: 'Copy to clipboard',
  errorText: 'Error',
  successText: 'Copied'
}
```

### Math (LaTeX via KaTeX)

Render LaTeX math — inline like `$x^2 + y^2 = z^2$` and block like `$$ ... $$` — with the
[docsify-katex](https://github.com/upupming/docsify-katex) plugin. **Pin version 1.4.4**:
it bundles the KaTeX renderer (the 2.x releases are broken). The only extra assets are
KaTeX's stylesheet and the fonts it references.

```bash
# docsify-katex plugin (bundles the KaTeX renderer)
curl -L "https://cdn.jsdelivr.net/npm/docsify-katex@1.4.4/dist/docsify-katex.js" \
  -o assets/js/docsify-katex.js

# KaTeX stylesheet — pin to the version bundled by docsify-katex@1.4.4 (0.11.1)
curl -L "https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css" \
  -o assets/css/katex.min.css

# KaTeX fonts — the stylesheet loads these from ./fonts/, so they must sit beside it.
# Modern browsers use woff2, so only those (20 files) are needed.
mkdir -p assets/css/fonts
for f in $(grep -oE 'fonts/KaTeX_[^)]+\.woff2' assets/css/katex.min.css | sort -u); do
  curl -L "https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/$f" -o "assets/css/$f"
done
```

Add the stylesheet (a `<link>` in `<head>`) and the plugin `<script>` (after
`docsify.min.js`) to `index.html` — see Step 3. KaTeX then renders math automatically,
with no extra configuration.

### Diagrams (Mermaid)

Turn fenced `mermaid` blocks into flowcharts, sequence diagrams, and the like. Mermaid is
one large but self-contained file (~3 MB, no external fonts); the
[docsify-mermaid](https://www.npmjs.com/package/docsify-mermaid) plugin wires it into
Docsify (it uses Mermaid v11's `run()` API).

```bash
# Mermaid renderer (large, self-contained)
curl -L "https://cdn.jsdelivr.net/npm/mermaid@11.15.0/dist/mermaid.min.js" \
  -o assets/js/mermaid.min.js

# docsify-mermaid plugin
curl -L "https://cdn.jsdelivr.net/npm/docsify-mermaid@2.0.1/dist/docsify-mermaid.js" \
  -o assets/js/docsify-mermaid.js
```

Load both after `docsify.min.js` and add `mermaid.initialize({ startOnLoad: false })`
(see Step 3). A fenced block tagged `mermaid` then renders as a diagram:

    ```mermaid
    graph TD; A[Start] --> B{Works?} --> C[Ship];
    ```

### UX Plugins

Five small self-hosted plugins. Each loads after `docsify.min.js`; alerts, tabs, and
pagination inject their own CSS, while image-zoom and sidebar-collapse ship a stylesheet.

```bash
# Callout boxes:  > [!NOTE] / [!TIP] / [!WARNING] / [!ATTENTION]
curl -L "https://cdn.jsdelivr.net/npm/docsify-plugin-flexible-alerts@1.3.0/dist/docsify-plugin-flexible-alerts.min.js" \
  -o assets/js/docsify-plugin-flexible-alerts.min.js

# Tabbed content blocks
curl -L "https://cdn.jsdelivr.net/npm/docsify-tabs@1.6.3/dist/docsify-tabs.min.js" \
  -o assets/js/docsify-tabs.min.js

# Previous/next links in the page footer
curl -L "https://cdn.jsdelivr.net/npm/docsify-pagination@2.10.1/dist/docsify-pagination.min.js" \
  -o assets/js/docsify-pagination.min.js

# Click-to-zoom images (generic library + its stylesheet; wired via a hook in Step 3)
curl -L "https://cdn.jsdelivr.net/npm/medium-zoom@1.1.0/dist/medium-zoom.min.js" \
  -o assets/js/medium-zoom.min.js
curl -L "https://cdn.jsdelivr.net/npm/medium-zoom@1.1.0/dist/style.css" \
  -o assets/css/medium-zoom.css

# Collapsible sidebar (+ its stylesheet)
curl -L "https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse@1.3.5/dist/docsify-sidebar-collapse.min.js" \
  -o assets/js/docsify-sidebar-collapse.min.js
curl -L "https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse@1.3.5/dist/sidebar.min.css" \
  -o assets/css/sidebar.min.css
```

Once wired into `index.html` (Step 3):

- **Alerts** — blockquotes tagged `> [!NOTE]`, `> [!TIP]`, `> [!WARNING]`, or `> [!ATTENTION]`.
- **Tabs** — wrap alternatives between `tabs:start` / `tabs:end` comments (syntax below).
- **Pagination, image zoom, collapsible sidebar** — automatic; no special syntax.

Tab block syntax:

    <!-- tabs:start -->
    #### **Python**
    `print("hi")`
    #### **R**
    `print("hi")`
    <!-- tabs:end -->

---

## Step 3: Create `index.html`

Create `index.html`:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>My Docs</title>
  <link rel="stylesheet" href="assets/css/vue.css">
  <link rel="stylesheet" href="assets/css/katex.min.css">
  <link rel="stylesheet" href="assets/css/sidebar.min.css">
  <link rel="stylesheet" href="assets/css/medium-zoom.css">
</head>
<body>
  <div id="app"></div>
  <script>
    window.$docsify = {
      name: 'My Docs',
      loadSidebar: true,   // enables _sidebar.md
      subMaxLevel: 2,      // auto-generate H2 entries in sidebar
      search: 'auto',      // enables the search plugin
      plugins: [
        // medium-zoom: click an image in the content to enlarge it
        function (hook) {
          hook.doneEach(function () {
            if (window.mediumZoom) mediumZoom('.markdown-section img');
          });
        }
      ]
    }
  </script>
  <script src="assets/js/docsify.min.js"></script>
  <script src="assets/js/search.min.js"></script>
  <script src="assets/js/docsify-copy-code.min.js"></script>
  <script src="assets/js/docsify-katex.js"></script>

  <!-- Extra Prism languages — Docsify bundles Prism core + html/css/js. Load after docsify. -->
  <script src="assets/js/prism-bash.min.js"></script>
  <script src="assets/js/prism-yaml.min.js"></script>
  <script src="assets/js/prism-python.min.js"></script>
  <script src="assets/js/prism-r.min.js"></script>

  <!-- UX plugins (callout boxes, tabs, prev/next pagination, image zoom, collapsible sidebar) -->
  <script src="assets/js/docsify-plugin-flexible-alerts.min.js"></script>
  <script src="assets/js/docsify-tabs.min.js"></script>
  <script src="assets/js/docsify-pagination.min.js"></script>
  <script src="assets/js/medium-zoom.min.js"></script>
  <script src="assets/js/docsify-sidebar-collapse.min.js"></script>

  <!-- Diagrams: Mermaid + docsify integration (disable Mermaid's own auto-run) -->
  <script src="assets/js/mermaid.min.js"></script>
  <script src="assets/js/docsify-mermaid.js"></script>
  <script>mermaid.initialize({ startOnLoad: false });</script>
</body>
</html>
```

> **Note:** Docsify uses hash-based routing by default, producing URLs like
> `/docs/#/page-name`. This requires no web-server configuration whatsoever.

---

## Step 4: Create Boilerplate Content

### Homepage — `README.md`

Docsify uses `README.md` in each directory as its index page, just like GitHub.

Create `README.md`:

```markdown
# Welcome

This is the home page of your documentation site.
Edit `README.md` to replace this content.

## Quick Links

- [Getting Started](getting-started.md)
```

### Sidebar — `_sidebar.md`

The sidebar lists your pages and their navigation structure.

Create `_sidebar.md`:

```markdown
- [Home](/)
- [Getting Started](getting-started.md)
```

Add a new `- [Title](filename.md)` entry here each time you create a new page.

### Example Page — `getting-started.md`

Create `getting-started.md`:

```markdown
# Getting Started

This is an example page. Replace this content with your own documentation.

## Section One

Write your content here using standard Markdown.

## Section Two

Docsify will automatically generate sidebar anchors for H2 headings
when `subMaxLevel: 2` is set in `index.html`.
```

---

## Step 5: Set File Permissions

Since you are creating these files yourself, you already own them. Just ensure they
are readable by your web server's user (e.g. `www-data`, `nginx`, or `caddy`):

```bash
find . -path './.*' -prune -o -type f -exec chmod 644 {} \;
find . -path './.*' -prune -o -type d -exec chmod 755 {} \;
```

The `-path './.*' -prune` clause skips dotfiles and dotdirectories, so if your document
root is a Git repository these commands leave its `.git/` permissions untouched.

---

## Serving the Site

Docsify is just static files, so **any** web server works — Apache, nginx, Caddy, or even
`python3 -m http.server` for a quick local preview. **No server configuration is required:**
Docsify's default hash-based routing (`/#/page-name`) means the browser never sends the
route to the server, so every request is for a file that exists on disk (`index.html`, a
`.md` file, or an asset). There are no rewrite rules to set up — just point the document
root at this directory.

**Apache** — drop the files in the document root; nothing else needed.

**nginx**

```nginx
server {
    listen 80;
    server_name docs.example.com;
    root /var/www/docs;
    location / { try_files $uri $uri/ =404; }
}
```

**Caddy** (also provisions HTTPS automatically)

```caddy
docs.example.com {
    root * /var/www/docs
    file_server
}
```

**Local preview** — run `python3 -m http.server` in this directory and open
`http://localhost:8000/`.

> **Clean URLs (optional):** the only time server config matters is if you switch Docsify
> to history-mode routing (`routerMode: 'history'`) to drop the `#` from URLs. Then you
> need a fallback so unknown paths return `index.html` — Apache `mod_rewrite`, nginx
> `try_files $uri /index.html;`, or Caddy `try_files {path} /index.html`. With the default
> hash routing used in this guide, you need none of it.

---

## Verify the Setup

After completing the steps above, confirm the file layout looks correct:

```bash
# The 20 KaTeX font files are summarised rather than listed individually
find . -not -path '*/\.*' -not -path './assets/css/fonts*' | sort
echo "./assets/css/fonts/  ($(ls -1 assets/css/fonts | wc -l) KaTeX woff2 files)"
```

Expected output:

```
.
./README.md
./_sidebar.md
./assets
./assets/SHA256SUMS
./assets/css
./assets/css/katex.min.css
./assets/css/medium-zoom.css
./assets/css/sidebar.min.css
./assets/css/vue.css
./assets/js
./assets/js/docsify-copy-code.min.js
./assets/js/docsify-katex.js
./assets/js/docsify-mermaid.js
./assets/js/docsify-pagination.min.js
./assets/js/docsify-plugin-flexible-alerts.min.js
./assets/js/docsify-sidebar-collapse.min.js
./assets/js/docsify-tabs.min.js
./assets/js/docsify.min.js
./assets/js/medium-zoom.min.js
./assets/js/mermaid.min.js
./assets/js/prism-bash.min.js
./assets/js/prism-python.min.js
./assets/js/prism-r.min.js
./assets/js/prism-yaml.min.js
./assets/js/search.min.js
./getting-started.md
./index.html
./assets/css/fonts/  (20 KaTeX woff2 files)
```

Then open `http://your-server/docs/` in a browser. You should see the rendered
homepage with a sidebar and search bar — no external requests are made.

---

## Adding New Pages

1. Create a `.md` file in the docs directory (or a subdirectory).
2. Add a corresponding entry to `_sidebar.md`.

Example for a new page `reference.md`:

```markdown
- [Home](/)
- [Getting Started](getting-started.md)
- [Reference](reference.md)
```

For subdirectories, nest entries with indentation:

```markdown
- [Home](/)
- [Getting Started](getting-started.md)
- **Advanced**
  - [Configuration](advanced/configuration.md)
  - [Deployment](advanced/deployment.md)
```

---

## Reproducibility & Resilience

Self-hosting protects your **live** site if jsDelivr ever disappears. To also protect your
ability to **rebuild** it, do two things:

1. **Pin and vendor.** Every asset version is pinned, and the downloaded files are plain
   static assets. Commit the entire `assets/` directory to your repository. You can then
   redeploy — or rebuild on a fresh machine with no network access — without depending on
   jsDelivr at all.

2. **Verify integrity.** `scripts/setup.sh` writes `assets/SHA256SUMS`, a SHA-256 checksum
   of every downloaded file. Commit it alongside `assets/`, then check the assets at any
   time (after a server move, or to detect corruption or tampering):

   ```bash
   (cd assets && sha256sum -c SHA256SUMS)
   ```

   Every file should report `OK`. After re-running `setup.sh` to upgrade, `git diff` on
   `SHA256SUMS` shows exactly which assets changed.

---

## Upgrading Docsify

Since files are self-hosted, upgrades are manual. Re-run the `curl` commands from
Step 2 with a specific version to update:

```bash
# Pin to a specific version (replace 4.13.1 with the target version)
curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/docsify.min.js" \
  -o assets/js/docsify.min.js

curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/lib/plugins/search.min.js" \
  -o assets/js/search.min.js

curl -L "https://cdn.jsdelivr.net/npm/docsify@4.13.1/themes/vue.css" \
  -o assets/css/vue.css
```

Every asset version is pinned — in the Step 2 commands above and in the variables at the
top of `scripts/setup.sh`. The Prism components, copy-code, Mermaid, the UX plugins, and
the math plugin (`docsify-katex@1.4.4` with a matching `katex` stylesheet **and** fonts)
are versioned independently of Docsify, so upgrade each by changing its version number and
re-downloading. Afterwards regenerate `assets/SHA256SUMS` — re-running `scripts/setup.sh`
does this — and re-verify.

Check the [Docsify releases page](https://github.com/docsifyjs/docsify/releases)
for the latest version number before upgrading.

---

## License

Copyright (c) 2026 Dave Tang.

This work, including the documentation in this repository and the
`scripts/setup.sh` helper, is licensed under the
[Creative Commons Attribution 4.0 International License (CC BY 4.0)](https://creativecommons.org/licenses/by/4.0/).
You are free to share and adapt the material for any purpose, even commercially,
provided you give appropriate credit. See [`LICENSE`](LICENSE) for the full legal text.

The third-party assets that `scripts/setup.sh` downloads (Docsify, Prism, KaTeX,
Mermaid, and the plugins) are each distributed under their own licenses by their
respective authors; this license covers only the contents of this repository.