nimbi-cms 1.0.5 → 1.0.7

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 CHANGED
@@ -27,7 +27,8 @@ The code lives at [https://github.com/AbelVM/nimbiCMS](https://github.com/AbelVM
27
27
  - Client-side rendering of [GitHub‑flavored Markdown](https://github.github.com/gfm/) via [marked.js](https://marked.js.org/), no need for site compilation
28
28
  - No Jekyll, no Hugo, no CI at all
29
29
  - Perfect for static servers (GitHub Pages, S3, etc.)
30
- - Optional client-side search box built from headings and excerpts (enabled by default).
30
+ - **FAST**: this site, the site of the project, contains more than 1200 Markdown documents (almost 3000 references) and it's indexed in a blink!
31
+ - Client-side search box built from headings and excerpts (enabled by default).
31
32
  - Reading time estimation
32
33
  - Code is organized into small modules to ease maintenance and testing.
33
34
  - Sticky per-page, dynamically generated TOC.
@@ -38,6 +39,8 @@ The code lives at [https://github.com/AbelVM/nimbiCMS](https://github.com/AbelVM
38
39
  - Image preview modal with zoom controls, wheel zoom, drag pan, double-click to zoom, and touch pinch support.
39
40
  - Syntax highlighting using [highlight.js](https://highlightjs.org/) — languages are auto-registered when detected.
40
41
  - Simple theming (light/dark), Bulma and hightlight.js customization options.
42
+ - Feeding support: [RSS 2.0](https://www.rssboard.org/rss-specification) at `/?rss` and [ATOM 1.0](https://www.rfc-editor.org/rfc/rfc4287) at `/?atom`
43
+ - Dynamic sitemap at `/?sitemap`
41
44
  - Simplified deliverables: regardless all the dynamic imports, the bundle is kept in one JS file and one CSS file
42
45
  - Bundle is compact size
43
46
  - JS file: 243.74 kB, gzipped 70.62 kB (for UMD bundle)
@@ -47,6 +50,17 @@ The code lives at [https://github.com/AbelVM/nimbiCMS](https://github.com/AbelVM
47
50
  - Fully typed and [documented](docs/README.md)
48
51
  - [MIT licensed](LICENSE.md)
49
52
 
53
+ ### Runtime sitemap & feeds
54
+
55
+ nimbiCMS exposes client-side endpoints that generate sitemaps and feeds at runtime:
56
+
57
+ - Endpoints: `/?sitemap` (also cosmetic `#/?sitemap` and path forms like `/sitemap` or `/sitemap.xml`) — returns an XML sitemap that uses canonical `?page=` URLs.
58
+ - `/?rss` and `/?atom` (also `#/?rss`, `#/?atom`, and path forms `/rss`, `/rss.xml`, `/atom`, `/atom.xml`) — return RSS 2.0 and Atom 1.0 feeds respectively.
59
+
60
+ Limitations & crawler advice
61
+ - These endpoints are generated client-side; servers cannot set the HTTP `Content-Type` header for the generated XML. The implementation uses Blob/data URL fallbacks to present XML in browsers, but this is not guaranteed to satisfy all crawlers.
62
+ - For reliable crawler indexing prefer a server-generated `sitemap.xml` (build-time) and list it in `robots.txt`. Use the runtime endpoints for development convenience or for crawlers that execute JavaScript.
63
+
50
64
  ## Installation
51
65
 
52
66
  ### From npm
@@ -154,27 +168,41 @@ Drop `.md` and/or `.html` files into your content directory. No build step is ne
154
168
 
155
169
  **Required files**
156
170
 
157
- - `_home.md` — required by default. You can override this with the `homePage` option to use a different `.md` or `.html` file as the home page.
158
-
159
- ```javascript
160
- initCMS({ el: '#app', homePage: 'index.html' })
161
- ```
162
-
163
171
  - `_navigation.md` — renders into the navbar; use Markdown links. Example nav markup:
164
172
 
165
173
  ```markdown
166
- [Home](_home.md)
174
+ [Home](home.md)
167
175
  [Blog](blog.md)
168
176
  [About](about.md)
169
177
  ```
170
178
 
179
+ -- `home page` — by default the library will use the first link found in `_navigation.md` when present. If no suitable link is found, the runtime will not automatically probe or fall back to `_home.md`; set the `homePage` option to explicitly select a page (for example `index.html`).
180
+
181
+ ```javascript
182
+ initCMS({ el: '#app', homePage: 'index.html' })
183
+ ```
184
+
171
185
  - `_404.md` — optional fallback for 404 responses. When the server responds to a requested `.md` path with an HTML document (e.g., an SPA fallback serving `index.html`), the CMS treats that as a missing markdown page and will attempt to load `/_404.md` from the configured content base so a proper 404 page can be rendered instead of the site's index HTML.
172
186
 
173
187
  ```javascript
174
188
  initCMS({ el: '#app', notFoundPage: '_404.md' })
175
189
  ```
176
190
 
177
- Links are converted to hash‑based navigation (`?page=…`), preserving anchors and URL passed parameters
191
+ ### URL schemes cosmetic vs canonical
192
+
193
+ nimbiCMS supports two coexisting URL schemas so that user-facing navigation can be friendly while SEO remains stable:
194
+
195
+ - Cosmetic (user-facing): `/#/slug[#anchor][?params]` — preferred for visible navigation, TOC links, and search results. Example: `https://example.com/#/blog/my-post#comments?lang=fr`
196
+ - Canonical (SEO / internal): `/?page=slug[#anchor][&params]` — used for canonical `<link>` tags, internal fetches, and sitemaps so indexing stays consistent. Example: `https://example.com/?page=blog/my-post#comments&lang=fr`
197
+
198
+ Behavior notes:
199
+
200
+ - The UI prefers the cosmetic `/#/slug` form for links, but the library emits canonical URLs using the `?page=` form (for example in `<link rel="canonical">`) to keep SEO and indexing stable.
201
+ - Anchors and query parameters are preserved and placed in the correct order: the anchor follows the slug, and parameters are appended after the anchor.
202
+ - Internal fetches (including worker-based requests) use canonical `?page=` URLs so paths remain predictable on static hosts.
203
+ - Because the cosmetic form relies on client-side routing, crawlers that do not execute JavaScript may require a server-side `sitemap.xml` or server-side routing for full indexing coverage.
204
+
205
+ This behavior is covered by the test-suite (see the canonical-link and URL handling tests).
178
206
 
179
207
  ## Options
180
208
 
@@ -187,6 +215,7 @@ Links are converted to hash‑based navigation (`?page=…`), preserving anchors
187
215
  | `el` | `string` \ `Element` | required | CSS selector or DOM element used as the mount target. |
188
216
  | `contentPath` | `string` | `/content` | URL path to the content folder serving `.md`/`.html` files; normalized to a relative path with trailing slash. |
189
217
  | `allowUrlPathOverrides` | `boolean` | `false` | Opt-in: when `true`, `contentPath`, `homePage`, `notFoundPage`, and `navigationPage` may be overridden using URL params. |
218
+ | `debugLevel` | `0 \|1 \| 2 \| 3` | `0` | Initial logging verbosity: `0`=disabled, `1`=errors, `2`=errors+warnings, `3`=all messages. |
190
219
 
191
220
  ### Indexing and Search
192
221
 
@@ -197,14 +226,16 @@ Links are converted to hash‑based navigation (`?page=…`), preserving anchors
197
226
  | `indexDepth` | `1 \| 2 \| 3` | `1` | How deep headings are indexed (H1, H2, H3). |
198
227
  | `noIndexing` | `string[]` | — | Paths (relative) to exclude from discovery and indexing. |
199
228
  | `skipRootReadme` | `boolean` | `false` | When `true`, skip link discovery inside a repository-root `README.md`. |
229
+ | `manifest` | `Record<string,string>` | `null` | Optional in-memory content manifest mapping absolute paths (for example `/content/page.md`) to raw page text. When provided the runtime pre-seeds `allMarkdownPaths` and slug mappings and avoids network discovery; this is commonly used by build-time tooling that inlines page sources into a bundle. The init routine also honors a global `__NIMBI_CMS_MANIFEST__` if present. |
200
230
 
201
231
  ### Routing and Pages
202
232
 
203
233
  | Option | Type | Default | Description |
204
234
  |---|---:|:---:|---|
205
- | `homePage` | `string` | `'_home.md'` | Path for the site home page (`.md` or `.html`). |
206
- | `notFoundPage` | `string` | `'_404.md'` | Path for the not-found page (`.md` or `.html`). |
207
235
  | `navigationPage` | `string` | `'_navigation.md'` | Path for the navigation markdown used to build the navbar (`.md` or `.html`). |
236
+ | `homePage` | `string` | `first link of navigationPage` | Path for the site home page (`.md` or `.html`). |
237
+ | `notFoundPage` | `string\|null` | `null` | Path for the not-found page (`.md` or `.html`). When unset (`null`) the runtime renders a small inline "Not Found" message linking to the configured `homePage` instead of attempting to fetch `'_404.md'`. |
238
+ | `exposeSitemap` | `boolean` | `true` | When `true` the client exposes a runtime sitemap at `/sitemap.xml` and `/sitemap.html`. The sitemap is generated at runtime (no build-time generation) and emits canonical `?page=` URLs (for example `/?page=blog/my-post`) while the UI preserves cosmetic `/#/slug` navigation. Requires SPA fallback (the server must serve `index.html` for `/sitemap*` requests). Disable with `initCMS({ exposeSitemap: false })`. For broad crawler coverage prefer generating a server-side `sitemap.xml` and listing it in `robots.txt`. You can also get an XML sitemap at `/?sitemap` endpoint. |
208
239
 
209
240
  > Note: All these files must be within `contentPath`
210
241
 
@@ -231,6 +262,8 @@ Links are converted to hash‑based navigation (`?page=…`), preserving anchors
231
262
  | `cacheTtlMinutes` | `number` | `5` | TTL for slug-resolution cache entries (minutes). Set `0` to disable expiration. |
232
263
  | `cacheMaxEntries` | `number` | — | Maximum entries in the router resolution cache. |
233
264
  | `crawlMaxQueue` | `number` | `1000` | Upper bound on directories queued during breadth-first crawl (0 disables the guard). |
265
+ | `fetchConcurrency` | `number | 'auto'` | `'auto'` | Limits the number of simultaneous network fetches used for probing external HTML, building the search index, and slug resolution. Accepts a positive integer or `'auto'` (default). When `'auto'`, nimbiCMS derives a safe concurrency from `navigator.hardwareConcurrency` and caps it at `5`. Set to `1` to serialize requests. |
266
+ | `negativeFetchCacheTTL` | `number` | `60000` | Milliseconds to keep negative (failed) fetch responses in cache to avoid repeated failing requests. Default `60000` (1 minute). Set to `0` to disable negative caching. |
234
267
 
235
268
  ### Advanced and Extensions
236
269
 
@@ -256,6 +289,15 @@ import { getVersion } from 'nimbi-cms'
256
289
  getVersion().then(v => console.log('nimbiCMS version', v))
257
290
  ```
258
291
 
292
+ ### Debugging
293
+
294
+ - `setDebugLevel(level)` — adjust runtime logging verbosity programmatically. `level` is a number `0..3` where `0` disables messages, `1` enables errors, `2` enables errors and warnings, and `3` enables info/log messages. Example:
295
+
296
+ ```js
297
+ import { setDebugLevel } from 'nimbi-cms'
298
+ setDebugLevel(2)
299
+ ```
300
+
259
301
  ### Hooks (extension points)
260
302
 
261
303
  These helpers let you hook into internal rendering and navigation without forking the source.
@@ -479,6 +521,26 @@ initCMS({ el: '#app', allowUrlPathOverrides: true })
479
521
 
480
522
  > Note: enabling `allowUrlPathOverrides` still runs client-side validation; if an unsafe value is supplied the call to `initCMS()` will throw a `TypeError`. Prefer passing `contentPath`, `homePage`, and `notFoundPage` directly in the `options` object from secure script code rather than relying on URL query parameters.
481
523
 
524
+ ### Runtime sitemap (dynamic)
525
+
526
+ When enabled (default `true`) nimbiCMS can expose a runtime-generated sitemap intended for crawlers and bots that execute JavaScript. The runtime sitemap is available at:
527
+
528
+ - `/sitemap.xml` — XML sitemap using canonical `?page=` URLs
529
+ - `/sitemap.html` — optional simple HTML listing (not a full UI)
530
+
531
+ Key notes:
532
+
533
+ - Runtime-only: the sitemap is built in the browser from discovered content paths; nothing is generated at build time.
534
+ - Canonical URLs: the sitemap emits `?page=...` canonical URLs (for SEO and indexing) while the SPA UI keeps cosmetic `/#/slug` links for user navigation.
535
+ - SPA fallback required: your static host must serve `index.html` for requests to `/sitemap.xml` or `/sitemap.html` so the client-side handler can render the sitemap.
536
+ - Disabled when needed: opt out by passing `exposeSitemap: false` to `initCMS()`:
537
+
538
+ ```js
539
+ initCMS({ el: '#app', exposeSitemap: false })
540
+ ```
541
+
542
+ For widest crawler compatibility (search engines that don't execute JavaScript reliably) prefer generating and serving a server-side `sitemap.xml` and listing it in `robots.txt`. The runtime sitemap is a convenience for JS-aware crawlers and for environments where generating a sitemap at build time is not possible.
543
+
482
544
  ## Available Bulmaswatch themes
483
545
 
484
546
  The list of available Bulma themes is
@@ -492,7 +554,7 @@ Keep in mind that some themes do not play well with certain color schemas.
492
554
 
493
555
  ## Using with GitHub Pages and the GitHub file editor
494
556
 
495
- Nimbi CMS works well with GitHub Pages and the built-in GitHub web file editor. Minimal steps:
557
+ nimbiCMS works well with GitHub Pages and the built-in GitHub web file editor. Minimal steps:
496
558
 
497
559
  - Enable GitHub Pages for the repository (Settings → Pages) and choose the branch/folder you want to publish (e.g., `gh-pages` or `main` / `/docs`).
498
560
  - If your content includes underscore-prefixed files (for example `_navigation.md` or `_home.md`), GitHub's Jekyll processor will ignore them by default. Add an empty `.nojekyll` file at the repository root to disable Jekyll so those files are served
@@ -504,7 +566,7 @@ Editing content via the GitHub web editor:
504
566
  1. Open the repository on [GitHub](https://github.com) and navigate to the `content/` folder (or your chosen `contentPath`).
505
567
  2. Click any `.md` file, then click the pencil icon to edit the file in the browser.
506
568
  3. Make changes and commit them directly to the branch. The published site will receive the updates on the next Pages build (or immediately if you host the `dist` on the same branch).
507
- 4. Refresh the site to see the updated content. Nimbi CMS loads content at runtime, so browser refresh shows the latest files.
569
+ 4. Refresh the site to see the updated content. nimbiCMS loads content at runtime, so browser refresh shows the latest files.
508
570
 
509
571
  Tips:
510
572
  - Add or update `content/_navigation.md` to control the navigation bar; the nav is re-built when pages are crawled.
@@ -519,7 +581,6 @@ If you find a bug, have a feature request or a question, just [open an issue](ht
519
581
  ### Content not loading / 404 pages
520
582
  - Verify `contentPath` is correct and matches the directory containing your `.md` files.
521
583
  - Ensure your static server is serving those files (a 404 is often because the content folder isn’t published or the path is wrong).
522
- - If you’re using `homePage`/`notFoundPage`, confirm those files exist and are reachable (the default is `_home.md` and `_404.md`).
523
584
 
524
585
  ### Styles not appearing / Bulma missing
525
586
  - Ensure `dist/nimbi-cms.css` is loaded alongside `dist/nimbi-cms.js`.
@@ -527,4 +588,19 @@ If you find a bug, have a feature request or a question, just [open an issue](ht
527
588
  - If using a Bulmaswatch theme, verify the theme name is correct (see `Available Bulmaswatch themes`).
528
589
 
529
590
  ### Scripts failing / no mount element
530
- - Make sure the mount element exists (`<div id="app"></div>`) and `initCMS({ el: '#app' })` uses the correct selector.
591
+ - Make sure the mount element exists (`<div id="app"></div>`) and `initCMS({ el: '#app' })` uses the correct selector.
592
+
593
+ ### I get a console error!
594
+
595
+ One of the features of `nimbiCMS` is folder crawling for enhanced indexing
596
+ performance, so it's going to try and fetch your `contentPath` folder just in
597
+ case your server response is an HTML listing the files in the folder. If your
598
+ server has this functionality disabled, which is quite common, it will send back a
599
+ `404` response that will trigger an error in the dev console of your browser, but
600
+ no worries, it's an expected one and breaks nothing. Your console might looks like
601
+ this when this happens
602
+
603
+ ```shell
604
+ nimbi-cms.js:71 GET https://example.com/contentfolder/ 404 (Not Found)
605
+ nimbi-cms.js:71 [slugManager] crawlAllMarkdown: directory fetch non-ok {url: 'https://example.com/contentfolder/', status: 404}
606
+ ```