订阅在客户端里的身份是「远程数据的一份本地缓存」。每次更新,客户端重新拉一遍远端内容,按它重新生成配置文件。你手写在那个文件里的东西不参与这个过程,自然也留不下来。踩过一次就懂了,剩下的问题只是怎么绕开。

改动应该挂在订阅之上,而不是写进去

Clash Verge Rev 的办法是把「订阅说了什么」和「你改了什么」拆成两层。订阅那份保持只读,你的修改单独存成扩展配置;客户端每次生成最终配置,都是先取订阅原文,再把你这层叠上去。订阅怎么变都行,你那层始终在。别的客户端也有同样的东西,名字可能叫覆写、Mixin 或者预处理,形状是一样的。

合作推荐订阅链接从哪来?本站合作机场注册即送 1GB 香港高速体验流量,可直接一键导入。获取高速节点

两种扩展:一段 YAML,一段 JS

  • Merge:一段 YAML 片段,和生成出来的配置做合并。适合写死的内容——几条规则、一段 dns、改个端口。
  • Script:一段 JavaScript,入口函数拿到完整的 config 对象,你改完 return 回去。适合有条件判断的活;纯静态的内容用它是杀鸡用牛刀。
  • 顺序是固定的:订阅原文 → Merge → Script → 最终生效的配置。Script 看到的是 Merge 之后的结果,两个都挂着的时候,Script 说了算。

Merge 最容易踩的一脚:列表是替换,不是追加

同名的键后者覆盖前者,这符合直觉。列表不符合。你在 Merge 片段里写一个 rules,默认行为是用你这几行把订阅那几百行整个换掉,于是除了你写的以外全没了。表现出来就是绝大多数网站突然全部直连,或者突然全部走代理。要往列表里加内容得用专门的键:prepend-rules 往前插,append-rules 往后接,proxy-groupsproxies 也有对应的 prepend / append 形式。规则讲顺序,自定义规则基本都该用 prepend。

prepend-rules:
  - DOMAIN-SUFFIX,internal.example.com,DIRECT
  - PROCESS-NAME,Telegram.exe,PROXY
append-rules:
  - DST-PORT,25,REJECT
dns:
  enable: true
  nameserver:
    - 223.5.5.5

Script 能做 Merge 做不到的事

脚本入口是一个函数,参数是解析好的配置对象,返回值就是新配置。这意味着你可以按条件处理,而不是把结果写死:筛掉那些名字里写着到期时间和剩余流量的假节点,给所有节点名加统一前缀,或者把符合某个模式的节点批量塞进一个组。这些 Merge 表达不出来,因为你事先根本不知道订阅里会有什么。

function main(config) {
  config.proxies = config.proxies.filter(function (p) {
    return p.name.indexOf('剩余流量') === -1;
  });
  config.rules.unshift('DOMAIN-SUFFIX,example.com,DIRECT');
  return config;
}

别靠猜,去看合成出来的东西

扩展配置写错了,症状很不体贴:要么配置直接加载失败,要么加载成功但某一整段悄悄消失——节点列表少一半,或者规则表里只剩你自己写的那两条。客户端一般提供查看最终生效配置的入口,在配置项的右键菜单或者详情里,有的写作「查看配置」,有的是导出。改完就去看一眼:你加的在不在,原来的还在不在。比从现象往回推快得多。

扩展配置里只放增量:规则、DNS、几个自己加的策略组。别去重写整段 proxies——节点是订阅的职责,你把它接管过来,就等于放弃了自动更新的全部意义,服务商哪天换个服务器地址,你得手动跟一次。至于规则本身怎么写、放在第几行才有效,那是另一篇的事;这篇只管让它别被冲掉。