分享思源代码片段调试技巧

前言

思源的代码片段很强大,有了它你几乎可以无所不能。

但,你是不是也感受到了一点点烦恼?输入框不仅小,还每次调试都要先打开设置,再粘贴到输入框中。

如果你是开发者,频繁的打开和调试,你是不是开始感到有些心累?有没有一种办法,不需要频繁的打开也能进行调试预览呢?

答案是肯定的。

我在不断的打开与关闭的痛苦中摸索出了一些办法。

探索之路

先说 css

css 调试最简单的方式就是在右侧样式这里修改了

image.png

但这种修改方式还是有点麻烦,而且不小心刷新了页面,刚才改的样式全没了。

但你有没有注意到,如果点右上角的 + 号,然后在点击 inspector-stylesheet,你会发现会进入一个样式文件编辑界面。image.png

image.png

在这里同样能编辑样式,而且操作起来比在右侧方便多了。

但可惜的是,这里编写的 css 同样不能持久化,刷新同样会消失。

但你可以在每次重大操作后进行右键另存为。

image.png

但这同样很不方便,有没有能实时预览又能持久化的方法呢?

当然有,请参考下面的终极大招。

再说 js

js 最简单的方法就是控制台执行命令了,但这和 css 右侧调整样式一样非常不方便。

如果输入大量文本,还是碍手碍脚的,有没有办法...?有。

打开源代码,找到代码段选项卡,按照下图新建代码段即可。

image.png

然后,修改好后,在列表上右键运行即可

image.png

也可选中某一段右键在控制台运行

image.png

代码段中的代码可以保存和持久化。

但,怎么加载时运行呢?

代码段无法加载时运行。

请参考下面的终极大招。

终极大招

上面讨论了 css 和 js 的调试方法,都有不足,要么无法持久化,要么无法加载时运行。

要解决这两个问题,就得上我们的替换功能了。

image.png

这个功能的作用,就是用本地的文件替换远程的同名文件,这样就能通过编辑本地文件,就使得远程文件实时变化,就如同修改远程文件一样。

那么怎么做呢?

首先,在电脑随便新建个文件夹,任意路径都可,只要你找得到,比如叫 my-snippets,然后点选择放置替换的文件夹即可。

image.png

然后,你会发现,添加完了,什么都没有

image.png

莫慌,这里的的文件从哪里来呢?

有两种方式,一种来自思源中已加载的文件,另一种就是自己添加的文件。

先说第一种,就叫鸠占鹊巢法吧,为什么这么叫?因为这种方法会侵占别人的文件。

所谓的替换,就是指用本地的文件替换远程文件,这里的远程文件自然指思源自带的一些 css 或 js 文件了。

那么,我需要在本地新建文件吗?

不需要,因为我们只要打开左侧的网页选项卡,然后找到你想侵占的文件,然后右键选择替换内容即可。

image.png

image.png

看,有文件了

image.png

然后你只要在 theme.css 和 theme.js 文件中编辑即可,css 编辑时,样式会实时生效,非常方便。

js 如果需要加载执行的,需要刷新页面,如果想临时测试,可以选择执行的代码,使用右键在控制台评估所选文本即可。

那么,这里为什么选择 theme.js 呢?因为这个文件是空的呀,这不是正好方便我们拿来用于调试嘛。

至于 theme.css 里是有内容的,只需要在内容后面添加你的代码即可,注意不要误删除了原有内容,不过如果误删除了也没关系,找到 my-snippets 文件夹,删除后,重新来过即可。

当然,theme.css 里有内容,总是小心翼翼,你用着可能不爽,能不能...?能。

还记得刚才提到的 inspector-stylesheet 文件吗?这个文件也是可以支持替换内容功能的,同样的方法打开这个文件,然后右键选择替换内容即可。

image.png

然后,就可以在这个文件里愉快的编辑样式了,而且保存后能持久化到本地。

不过,这也有个缺点,就是这个文件默认不会自动加载,每次都要点一下样式那里的加号才出来,不过,添加替换内容只需要操作一次就行了,下次使用时,只需要点击下加号即可。

Nice,这看起来已经很完美了,那第二种添加自己的文件是啥?

这种方法由于是自己添加文件,不用思源原有的资源文件,我们就叫自定义文件法吧。

首先,在/data/public/snippets 文件夹中新建个文件夹,比如叫 demo,然后新建两个文件,比如叫 demo.js 和 demo.css。

然后,devtools 里找到刚才的网页选项卡,找到 app 文件

image.png

然后右键,替换内容,添加到替换文件夹即可。

然后打开,这个文件,在里面添加两行代码。

<script defer="defer" src="/public/snippets/demo/demo.js"></script>
<link href="/public/snippets/demo/demo.css" rel="stylesheet">

然后刷新页面,用同样的方法把 demo.js 和 demo.css 添加到替换文件里,然后就可以愉快的编辑了。

不过,这种方式还是麻烦了点,毕竟每次要手动添加两行代码,还是很不方便的,那么可以动态加载 js 和 css 吗?好主意,通过实验得知这样是可行的。

于是,我就写了下面的代码片段,就叫 loadSnippets 吧,然后把它放到思源 设置 》外观 》代码片段中即可。

代码如下:

(() => {
  
    // 配置要加载的项目,比如,load(["demo"]);
    load(["demo"]);

    // 设置load全局可访问,方便快捷开发
    window.loadSnippets = load;

    ////////////// 以下代码不涉及配置项,如果非必要勿改动 //////////////////////
   
    async function getAllFiles(path, includes = [], excludes = []) {
        let files = [];
        if(!includes) includes = [];
        if(!excludes) excludes = [];
        if(!Array.isArray(includes)) includes = [includes];
        if(!Array.isArray(excludes)) excludes = [excludes];
        const walkDir = async (currentPath) => {
            const response = await fetch('/api/file/readDir', {
                method: 'POST',
                body: JSON.stringify({ path: currentPath }),
            });
            const json = await response.json();
            const data = json.data;
            for (const entry of data) {
                const fullPath = `${currentPath}/${entry.name}`;
                if (
                    // 过滤仅包含文件
                    (includes.length && !includes.some(item=>fullPath.split("/").includes(item))) ||
                    // 过滤隐藏文件
                    currentPath.startsWith(".") ||
                    entry.name.startsWith(".") ||
                    // 过滤排除文件
                    excludes.includes(currentPath) || 
                    excludes.includes(entry.name)
                ) {
                    continue;
                }
                if (entry.isDir) {
                    await walkDir(fullPath);
                } else {
                    files.push(fullPath);
                }
            }
        };
        await walkDir(path);
        return files;
    }
  
    function loadStyle(url) {
      const link = document.createElement('link')
      link.type = 'text/css'
      link.rel = 'stylesheet'
      link.href = url
      document.head.appendChild(link);
    }
  
    function loadScript(url) {
        const script = document.createElement('script');
    	script.type = 'text/javascript';
    	script.src = url;
    	document.head.appendChild(script);
    }
  
    async function load(names = []) {
        const files = await getAllFiles("/data/public/snippets", names);
        files.forEach(file => {
            file = file.replace("/data", "");
            if(file.endsWith(".js")){
                loadScript(file);
            }
            if(file.endsWith(".css")){
                loadStyle(file);
            }
        });
    }
})();

这段代码的主要作用就是动态加载/data/public/snippets 下的 js 和 css 文件,还可以指定加载哪个项目。

开发完毕,注释加载即可,当然你也可以不注释,就当做代码片段来使用也是可以的 😄 。

不过,即使注释了,哪天你心血来潮或者想临时调试下某个项目,也可以直接在命令行加载,调用 window.loadSnippets("项目文件夹名") 即可。

那么,怎么让 devtools 中修改的文件和 public 中的文件相互保持同步呢?

这有点不好做,如果从 public 到 devtools 中,只能修改后重新加载文件,你可以写个监控脚本,当 public/snippets 中的文件改变时,实时加载,或者手动刷新也行,或者调用上面的 loadSnippets 命令重新加载。

如果从 devtools 到 public 呢?这个也可以写个监控脚本,当本地文件 my-snippets 文件发生改变时,实时同步到 public/snippets 中,但我通常调试无误后或重大修改后,在文件中右键,然后选择“另存为”保存到 public/snippets 中,感觉也挺方便的。

image.png

目前这些监控脚本有了吗?抱歉,并没有,不过你可以参考这位大佬的代码或利用 node 的 fs.watch 自己实现,关于监控我现在还没用到,感觉也没必要这么智能吧。

但要注意,如果你没有另存为,重启思源后,加载的 js 或 css 就不是最新版了,这是因为重启思源后端口变了,且在替换里修改的文件,只会保存在 my-snippets 目录,新端口不会用 my-snippets 里的旧文件替换,不过也没关系,打开 my-snippets,你修改过的文件都在这里,在 devtools 的替换列表里也能看到历史文件,然后复制过去就是了,记得开发完就保存一次。

如果你有兴趣,可以进一步完善这个方案。

注意:以上涉及的文件,如果找不到只需要刷新下页面即可,注意是刷新,不是重启思源,即在 devtools 控制台执行 location.reload()

另外,如果重启思源,上面添加的替换文件会失效,需要重新添加一遍,这是因为,思源每次重启后端口会变,对 devtools 来说,就相当于你换了一个网站,不同的网站下的内容当然不能共享了。

好在,我们开发时通常不需要频繁的重启思源,通常只需要刷新页面即可,这样的话,通常一个项目只需要添加一次即可,而且下一次添加时,只需要找到相应文件选择替换内容即可,比第一次方便方便多了。

这里顺便提一下,有人不清楚关闭和退出的区别。关闭不一定退出,比如如果你设置了关闭后进入托盘,则不会退出,只是隐藏在后台了,必须在思源主菜单中选择退出应用才最安全。

最佳实践

最后说说最佳实践。

我一般,如果临时调试样式时就用 inspector-stylesheet。

如果临时调试 js 通常用 theme.js,这个空文件,不用都对不起它 😄 。

如果开发具体项目就用自定义文件法 + 代码片段实现刷新加载,然后开发完另存为到 public/snippets 文件夹中即可。如果哪天你忘记另存为了,那么重启思源后,载的 js 或 css 就不是最新版了,这是因为重启思源后端口变了,且在替换里修改的文件,只会保存在 my-snippets 目录,新端口不会用 my-snippets 里的旧文件替换,不过,也没关系,打开 my-snippets,你修改过的文件都在这里,在 devtools 的替换列表里也能看到历史文件,然后复制过去就是了,记得开发完就保存一次。(重要事情多说一遍 😄 )。

而代码段(这里指 devtools 的代码段)我通常用放一些工具类的代码,方便快速执行或当做开发笔记使用。

不过,如果项目复杂,还推荐直接用官方的插件开发方法,而不是用代码片段了。

然后,在 devtools 里调试没问题后,再粘贴到思源代码片段中,这样就不用频繁打开和关闭思源代码片段了,是不是方便多了。

但要注意,放到思源代码片段中和利用 loadSnippets 动态加载两者别共存了,以防重复加载或产生冲突啥的。当然,如果你不想粘贴到思源代码片段中了,直接用 loadSnippets 来实现也是可以的。

最后我想说的是 devtools 就是一个方便的 IDE 啊,放一张图吧。

image.png

补充一点

刷新

刷新页面可以用快捷键 ctrl / cmd + r 必须当窗口焦点在 devtools 时按快捷键。
或者控制台执行 location.reload();

缩放

devtools 界面缩放可用快捷键
放大 ctrl+=
缩小 ctrl+-
还原 ctrl+0

这样在编写代码时看着就没那么累了。

笔记

开发笔记可以写到代码段里,不仅仅可以写代码哦

image.png

注意事项

在 devtools 中编辑文件时,有时候点击文字会被选中,不小心容易删除文字,要注意这一点。
不支持代码跳转,不过,可以用搜索代替。

如果非思源默认主题下,theme.js 可能不存在,不过,一般建议开发在一个新空间中进行,并使用默认主题,毕竟要保证正式空间的稳定性嘛,如果你必须用其他主题,那就用自定义文件法吧。


好了,啰嗦了这么多,希望对你有所帮助吧。

那么,你是怎么调试的呢?

请各位大佬们说说你的看法吧。

  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    22914 引用 • 92117 回帖
  • 代码
    468 引用 • 631 回帖 • 9 关注
  • CSS

    CSS(Cascading Style Sheet)“层叠样式表”是用于控制网页样式并允许将样式信息与网页内容分离的一种标记性语言。

    197 引用 • 551 回帖 • 1 关注
  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    730 引用 • 1328 回帖
3 操作
wilsons 在 2024-08-11 13:06:39 更新了该帖
wilsons 在 2024-08-11 10:33:06 更新了该帖
wilsons 在 2024-08-10 19:27:58 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...
  • xqh042

    反复重复贴代码刷新的憨憨调试者路过;目

    另外,如果重启思源,上面添加的替换文件会失效,需要重新添加一遍,这是因为,思源每次重启后端口会变,对 devtools 来说,就相当于你换了一个网站,不同的网站下的内容当然不能共享了。

    担忧重启时伺服的端口改变引发跨域的话,调试时直接访问默认的 6806 端口就可以了吧:目

    1 回复
  • wilsons 1

    第一个启动的工作空间除了随机端口外也会自动监听 6806 作为固定端口,以方便浏览器剪藏扩展或者其他外部程序调用内核接口

    官方这句话我一直没太理解,这里说的是第一个启动的工作空间,我咋感觉是第一个启动的客户端呢?

    不知怎的?我只有手机端伺服是 6806 端口,电脑上端口一直是随机的,6806 在电脑上无法访问,不清楚为什么?是我哪里理解错了吗?

    2 回复
  • 第一个启动的工作空间 = 第一个启动的客户端 ,因为一个工作空间对应一个客户端

    p.s. 如果有 A B 两个工作空间,先启动 A 再启动 B ,然后重启 A ,此时 A 是第三个启动的工作空间

    1 回复
  • wilsons 1

    原来如此。

    其实如果把一个工作空间对应一个客户端去理解也没错。

    不过也许会有人这么理解,比如我。

    假设有个工作空间 A(它的内容和手机上的 A'一样),那么我在手机上也有一个工作空间 A',这两个工作空间是保持同步的,那么你可以认为 A 和 A'是同一个工作空间,也可以认为是两个工作空间。

    估计这里思源的理解是两个工作空间了。

    但我有一点不太理解,思源为什么一定要随机?固然随机保证了一定不会出错,但保留一个可手动设置固定端口的选项不行吗?如果用户改了这个端口,冲突问题自己保证就行了。或者用户设置的端口无法使用时再随机不行吗?

  • xqh042 1

    应该是开启客户端的第一个工作空间开启伺服时先使用 6806 端口吧,你是用手机端开启的伺服然后 pc 端访问调试吗?

    无法访问的话可以先确认一下电脑上访问(手机端伺服)网页用的是否是环回地址(本机地址,别名包括 127.0.0.1、[::1] 以及 localhost),不是的话可能要以 手机ip:6806 访问,并设置一下(手机端的)访问授权码。

    如果是 PC 端开启的伺服并且无法通过环回地址访问 6806 端口页面,可以检查下是否有其他应用占用了该端口:

    netstat -ano | findstr "6806"
    tasklist | findstr "末尾的PID"
    
    

    Clip20240810222949.png

    1 回复
  • wilsons 1

    感谢提供的命令,但我试了下,6806 端口并未占用。

    而且我用 Python 启动了一个 HTTP 服务,端口用 6806 也能正常启动。

    说明不是端口占用问题。

    另外,我看论坛里有人提供的方法,通过 arp -a 查找手机端 ip 的方法,我这里不能用,不知道为什么,一直找不到手机端的 ip,只能找到电脑自己的 ip,但手机端的 ip 和电脑之间却可以相互访问。

    说明联通是没问题的,但就是找不到,不知道为什么。

    1 回复
  • 谁感兴趣可以做个插件,默认提供一些 js、css 片段,以文件方式维护。插件提供开关。用户也可以提交片段。😈

    1 回复
  • wilsons 1

    好想法 👍 ,最好映射到本地文件中,比如监控某个文件夹,这个文件夹中的 css 修改后,思源里会实时生效,js 加载时会自动执行,这样的话,就没代码片段什么事了 😄

  • xqh042

    我试了试 arp 命令能找到我的移动端 ip,并且访问移动端伺服页面时也能查询到建立链接的 ip。

    image.png

    所以现在的情况是 arp 查询不到手机端 ip, 两端可以互相通过对方的 ip 访问暴露的端口,除了特定的 6806 端口?我想确认一下 pc 端无法访问 6806 接口指的是 访问 pc 端伺服还是移动端伺服?

    如果是 pc 端开启伺服时无法访问 pc 端伺服的 6806 端口,开启伺服页面的方式是点击 打开浏览器 还是直接浏览器访问 localhost:6806 也无法访问?(点击打开浏览器默认似乎就是打开随机端口,但 6806 其实也能访问)

    如果是移动端开启伺服时,电脑无法访问移动端伺服的 6806 端口,但其余端口能访问的话,或许可以考虑检查下防火墙?(网络知识不够用了;目)

    1 回复
  • wilsons 1

    我想确认一下 pc 端无法访问 6806 接口指的是 访问 pc 端伺服还是移动端伺服?

    pc 端无法访问 pc 端伺服的 6806 端口,手动输入端口也无法访问。

    pc 端访问手机端伺服 6806 端口是可以的。

    手机端访问 pc 端随机端口的伺服也是可以的。

    arp 我这里查不到除自己电脑以外的其他局域网设备的 ip,不知道是不是被谁设置了访问权限,这个路由器是公用的。

  • hqweay 1
    3 回复
  • 我觉得不错,考虑到未来发展我还有点补充:

    1. 国际化多语言
    2. 如果有其他人贡献代码片段的话应该要尽可能简单
  • 看后面的替换文件,我觉得我会倾向于直接 vscode 打开主题文件夹,在主题里直接写,css 在 theme.css 写是即时生效的,js 需要刷新下

    1 回复
  • wilsons 1

    哦哦,学习了。

    不过我文档更新了,有了新的办法,可以通过代码片段动态加载 css 和 js 了,不用替换 theme.js 文件了。

    查看终极大招后半部分。

    但不知是否你理想中的方法。

    不过这篇文章不是终结,只是开始,抛砖引玉罢了,大佬们可以在这个基础上完善或参考。

    1 操作
    wilsons 在 2024-08-11 10:57:24 更新了该回帖
  • wilsons 1 1 评论

    刚才注意到,如果非思源默认主题下,theme.js 不存在,不过,一般建议开发在一个新空间中进行,并使用默认主题,毕竟要保证正式空间的稳定性嘛,如果你必须用其他主题,那就用自定义文件法吧。

    链滴修改文档扣积分太狠了,甚至超过发帖本身,小问题这在这里提醒下吧。

    已放到文章的注意事项里
    wilsons
  • kobi 2 1 赞同

    代码片段引用 css 或 js 文件,在 vscode 改就行

    如:

    import('/snippets/思维导图tab.js') @import url('/snippets/块引用.css')

    专门拿个 css 或 js 用来调试也不错

    1 回复
  • wilsons

    👍 学习了。

  • EmberSky 1

    补充几个小点

    1. 光标在调试页面的时候, f5 可以直接刷新
    2. 运行这里, 可以通过 ctrl+enter 直接运行image.png
    3. 在源代码运行正常的代码, 放到代码片段不一定能用, 我猜测的原因: 源代码这里是一个整体, 且独立的代码
      但是放到代码片段里面, 就不太算一个整体了, 好像是跟同步异步有关, 非专业, 不太清楚
    1 回复
  • wilsons

    f5 刷新我在 Mac 上不行,这个快捷键可能和操作系统有关。

    回顾下发现我这里的文档写的有点啰嗦了。

    其实可以精简为

    1. public 新建 js 和 css 文件
    2. 代码片段用 loadSnippets 函数加载 public 的 js 和 css 文件
    3. 用替换功能调试和预览效果
    4. 把修改另存为 public 文件中
    5. 也可以通过外部编辑器修改,刷新预览
    1 回复
  • EmberSky 1 赞同

    小声: 但是写的太精简就评不上 优选 了

  • EmberSky

    这就是大佬么, 插件说搞就搞

  • huaji 实际上,这一套操作搞下来,不如写个插件。

  • zuoez02 1 赞同

    这算啥?插件系统的中的插件系统???

    里面放一堆功能,说实话我感觉跟“番茄工具箱”以及“思源增强插件”差不多,都是一堆功能堆叠在一起(无讽刺或贬低意味),无外乎你的代码片段是更多人提供的而不是一个人自己写的。

    插件系统本身的出现,一个是提供深层次定制能力,超脱代码片段,另一个就是便于分发、管理插件,跟爱好者共创。我是不太建议弄另一套分发工具,因为这样推广起来能力有限不如插件系统,也不易于管理,用插件的人少,能发现这个插件的人更少。

    我更推荐可以推动 D 去弄一个接口,用来直接把思源(liandi)用户编写的代码直接发布为插件,而你可以开发一个插件便于提升开发,调试,发布,更新这一流程的插件,我觉得这样对官方对大家对你都很有好处

    1 回复
    3 操作
    zuoez02 在 2024-08-12 17:05:13 更新了该回帖
    zuoez02 在 2024-08-12 17:02:39 更新了该回帖
    zuoez02 在 2024-08-12 16:59:44 更新了该回帖
  • 所以就又回到“代码片段集市”的需求上来了

    2 回复
  • 主要是跟插件就是类似的东西。

    还是得分发、版本维护、升级之类的各种操作,无外乎这个代码片段不调用思源 API 而已。。。用代码片段我都能让我之前旧时代插件系统跟现在的插件系统并存………

    Eagle 我看他们的插件不是依赖 github 的,是要提交给 eagle 官方的,我觉得可以吸收一下他们的做法。不过如果代码片段是直接分发的,那再弄套开源的 github 的插件方式,也怪怪的,两套都兼容,也不好描述

  • zuoez02 1 赞同 1 评论

    突然想到一个折中的办法,就是基于 github 上的 siyuan-community 社区,用户提交代码,然后直接以 siyuan-community 的名义发布为插件,这样也算一种间接实现开源了 😂

    JeffreyChen
  • vite-plugin-siyuan 插件更方便啊,只想写代码片段也能用,用这个插件加载代码调试完后注释掉插件相关代码,然后将 vite 输出的 js 复制粘贴到代码片段就行

请输入回帖内容 ...