# Obsidian 公开库从 Docsify 改为 Docute 最近把 Obsidian 公开库从 Docsify 折腾为了 Docute。 ## 缘起 大概是 2022 年 9 月,我使用 Obsidian Remotely Save + 对象存储静态网站托管 + Docsify 搭建了一个公开库。也放了一些静态网站,后来一些文件也被用于博客网站的数据源。 这其中,Docsify 只需要一个 index.html 和一些 markdown 文件就可以部署为网站。需要做的就是一些索引工作。这之前,我使用的是 Zoottelkeeper 生成索引链接。这其实并不能完全符合我的要求,但是也不想自己折腾插件,于是也就这样了。 2024-02-21 又看到了 Docute ,顺手把 Docsify 改为 Docute 。效果 https://note.ftls.xyz/#/ ## Docute ### Docute 介绍 Docute https://docute.egoist.dev/zh/ 官网的话是 > Docute 本质上就是一个 JavaScript 文件,它可以获取 Markdown 文件并将它们呈现为单页面应用。 它完全由运行时驱动,因此并不涉及服务端组件,这就意味着没有构建过程。你只需创建一个 HTML 文件和一堆 Markdown 文档,你的网站就差不多完成了! > Docsify 和 Docute 几乎相同,但具有不同的 UI 和不同的使用方式。 Docute(60kB)比 Docisfy(20kB)大 3 倍,因为我们使用了 Vue,Vue Router 和 Vuex,而 Docsify 使用的是 vanilla JavaScript。 实际上这个大小数据已经过时了,Docute 现在 200kb+ 。 如果自己写的自己需要的功能,大概会小一些。 虽然 200kb 很大,但我今天才发现我用的 Docsify icon 就 60kb+ ![](https://cdn.ftls.xyz/images/2024/02/docsify-favicon.ico) ### 侧边栏 Docute 功能上很多都是打包好的,js 比 Docisfy 大,配置项却比 Docisfy 少,倒是也够用了。使用上最大的区别是侧边栏生成方式不同,Docsify 使用的是 `.md` 文件渲染。并且似乎在内部修改了渲染 markdown list 的方法,在 index.html 重新定义渲染方法会导致侧边栏没有 css 效果。 不过问题不大,我也不用侧边栏,只是一个文档站点。正好 Docute 没有这个问题。 不过使用 js 对象, Zoottelkeeper 的插件生成的文件是满足不了 Docute 的需求了。于是我选择了 RunJS 插件生成文件,来为 Docute 提供侧边栏。 在 Obsidian 中一个 .md 文件中写入下面代码,根目录创建 `sidebar.md`。然后带点侧边 JS 图标,运行 List 就行了。程序会读取 markdown 文件,并把最后对象写入文件,给 Docute 使用。 `sidebar.md` 虽然是 markdown 文件,但是确实是 JSON 内容,写成 markdown 是为了在 Obsidian 就可以观察到变化。 RunJS 是调用的 Obsidian 的 API ,Obsidian 文件列出,创建,修改 API 参考 https://docs.obsidian.md/Reference/TypeScript+API/Vault ````md ```js RunJS="List" new Notice("生成索引文件"); // import * as obsidian from 'obsidian'; const runJS = this; let pagesFile = []; let journalsFiles = []; let ZKFiles = []; this.app.vault.getMarkdownFiles().map((file) => { if(file.path.startsWith("pages/")) { pagesFile.push({ title : file.path.replace("pages/","").replace(".md",""), link : "/"+file.path.slice(0,file.path.length-3), }); } if(file.path.startsWith("journals/")) { journalsFiles.push({ title : file.path.replace("journals/","").replace(".md",""), link : "/"+file.path.slice(0,file.path.length-3), }); } if(file.path.startsWith("ZK/")) { ZKFiles.push({ title : file.path.replace("ZK/","").replace(".md",""), link : "/"+file.path.slice(0,file.path.length-3), }); } // new Notice(file.path); // result += file.path + "\n"; }) let obj = [ { title: "Pages", children: pagesFile }, { title: "Journals", children: journalsFiles }, { title: "ZK", children: ZKFiles } ] const xxxx = this.app.vault.getAbstractFileByPath("sidebar.md"); this.app.vault.modify(xxxx, JSON.stringify(obj)).then(res => { new Notice("Finish!"); }) ``` ```` Obsidian 库根目录下的 index.html 为 ```html 笔记
``` 这样每次创建 .md 文件,RunJS 运行下 List,Remotely Save 同步到对象存储,网站刷新一下就能看到了。 ### 时间顺序 后面我把侧边栏按照创建时间排序,使最新的在上面。 ```js let files = this.app.vault.getMarkdownFiles(); files.sort((a,b) => { //new Notice(a.stat.ctime - b.stat.ctime); return b.stat.ctime - a.stat.ctime; }); files.map((file) => {}) ``` ### sw.js 然后我又加上了 sw.js 。不过 Docute 文档里的离线支持,使用的 Google 服务我打不开。用的还是 Docsify 之前的 sw.js ```js if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw-docsify.js') } ``` ```js /* =========================================================== * docsify sw.js * =========================================================== * Copyright 2016 @huxpro * Licensed under Apache 2.0 * Register service worker. * ========================================================== */ const RUNTIME = 'docsify' const HOSTNAME_WHITELIST = [ self.location.hostname, 'fonts.gstatic.com', 'fonts.googleapis.com', 'cdn.jsdelivr.net' ] // The Util Function to hack URLs of intercepted requests const getFixedUrl = (req) => { var now = Date.now() var url = new URL(req.url) // 1. fixed http URL // Just keep syncing with location.protocol // fetch(httpURL) belongs to active mixed content. // And fetch(httpRequest) is not supported yet. url.protocol = self.location.protocol // 2. add query for caching-busting. // Github Pages served with Cache-Control: max-age=600 // max-age on mutable content is error-prone, with SW life of bugs can even extend. // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string. // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190 if (url.hostname === self.location.hostname) { url.search += (url.search ? '&' : '?') + 'cache-bust=' + now } return url.href } /** * @Lifecycle Activate * New one activated when old isnt being used. * * waitUntil(): activating ====> activated */ self.addEventListener('activate', event => { event.waitUntil(self.clients.claim()) }) /** * @Functional Fetch * All network requests are being intercepted here. * * void respondWith(Promise r) */ self.addEventListener('fetch', event => { // Skip some of cross-origin requests, like those for Google Analytics. if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) { // Stale-while-revalidate // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1 const cached = caches.match(event.request) const fixedUrl = getFixedUrl(event.request) const fetched = fetch(fixedUrl, { cache: 'no-store' }) const fetchedCopy = fetched.then(resp => resp.clone()) // Call respondWith() with whatever we get first. // If the fetch fails (e.g disconnected), wait for the cache. // If there’s nothing in cache, wait for the fetch. // If neither yields a response, return offline pages. event.respondWith( Promise.race([fetched.catch(_ => cached), cached]) .then(resp => resp || fetched) .catch(_ => { /* eat any errors */ }) ) // Update the cache with the version we fetched (only for ok status) event.waitUntil( Promise.all([fetchedCopy, caches.open(RUNTIME)]) .then(([response, cache]) => response.ok && cache.put(event.request, response)) .catch(_ => { /* eat any errors */ }) ) } }) ``` ## 总结 大概就是这些。另外,我这 BearBlog 学到一种用 Emoji 表情作为 icon 的代码,如下: ```html ``` 放在 HTML `` 里面就行了。 Docute 看起来还不错,UI 挺耐看的。不过可能哪天我又换成 Docsify 了,或者其他什么。 Docute 侧边栏是不支持多级目录的,也就是 children 层数有限,就想起了 [Naive UI 树](https://www.naiveui.com/zh-CN/os-theme/components/tree) 看着不错了。我之前就觉得 Naive UI 确实很好看来着,可能哪天用 Naive UI 写一个类似的东西。