非官方技术粉丝站 · 本站与 Clash Verge 官方项目无任何隶属关系 · 仅供网络技术学习与合法科研用途
网络协议架构组 网络协议架构组 · 配置进阶 · 更新于: 2026-10-09

扩展脚本(Script)与配置合并(Merge)进阶指引

利用 JavaScript 与 YAML Merge 动态改写第三方托管订阅。掌握 Clash Verge 内置 JS 运行时、配置动态插装、自定义规则追加与全自动节点筛选代码实战。

配置过程中若遭遇内核报错、端口冲突或无法上网,快速定位修复。
遇到问题?查看故障排查

在网络工程实践中,用户通常需要从第三方服务商导入远程托管订阅。然而,这些由外部生成的订阅配置文件往往存在固有的局限性:服务商往往只提供粗放的通用分流规则,或者预设的 DNS 配置并不适配你的本地局域网环境;更棘手的是,一旦你在本地直接手动修改该配置,每次服务商发布节点更新或重新拉取订阅时,你所做的一切本地修改都将被完全冲刷覆盖。

Clash Verge 客户端 创造性地提供了 YAML Merge(配置合并) 与 JavaScript Script(扩展脚本) 两种分层改写机制。通过将自定义逻辑抽象为独立的代码模块,客户端在拉取并解析原始订阅的瞬时,会在内存中动态对其进行函数式流水线加工。

本文将深入拆解 Clash Verge 的脚本运行时上下文,并提供生产级 JavaScript 脚本范式,助你实现规则全自动追加、节点正则重组与高可用策略编排。


1. 动态改写架构演进:为什么需要与原始订阅解耦?

传统的配置管理模式面临三大不可调和的矛盾:

  1. 修改覆盖危机:手动追加的几百条直连规则,在点击一次“更新订阅”后瞬间归零。
  2. 多订阅维护成本:如果你同时订阅了多家服务商,为每个配置文件重复维护相同的自定义规则与 DNS 配置会导致严重的维护地狱。
  3. 缺乏动态计算能力:静态 YAML 无法根据节点名称中的倍率特征、国家地区或协议类型执行条件过滤与动态重组。
[ 远程服务商原始订阅 (Raw Profile) ]
                │
                ▼ (点击更新或定时自动拉取)
[ Clash Verge 核心预处理器 (Pre-processor) ]
                │
         ┌──────┴────────────────────────┐
         ▼                               ▼
【方式 A: YAML Merge】           【方式 B: JavaScript Script】
以纯声明式键值覆盖               以纯函数式图灵完备代码
进行浅层/深层字典合并            执行遍历、正则过滤与算法重组
         │                               │
         └──────────────┬────────────────┘
                        ▼
       【内存中生成的最终运行时配置 (Runtime Config)】
                        │
                        ▼ (传递给底层的 Mihomo 核心启动)
          [ 具备完整个人客制化与防冲刷特性的代理内核 ]

通过这一架构,用户的个人配置逻辑与服务商的节点数据实现了彻底的关注点分离(Separation of Concerns)。


2. YAML Merge vs JavaScript Script:双重机制横向对比

在开始编写代码前,首先需要根据业务场景选择最适宜的客制化方式:

特性维度YAML Merge (配置合并)JavaScript Script (扩展脚本)
核心机制静态声明式 YAML 字典合并图灵完备的动态 JavaScript 脚本执行
上手门槛极低(只需掌握基础 YAML 语法)需要基础编程能力与 JS 对象操作经验
规则增补适合全局追加一段固定的静态参数适合按条件(如只对特定前缀节点)动态挂载
节点筛选不支持(无法读取并过滤动态节点数组)极其强大(支持完整的 RegExp 正则、数组映射与排序)
容错机制语法错误会被 YAML 解析器阻断支持 try/catch 异常自愈,防止启动崩溃
适用场景统一修改 DNS 或开启 TUN 模式重构策略组拓扑、按倍率剔除节点、动态规则编译

3. JavaScript 扩展脚本执行环境与生命周期模型

在 Clash Verge 中,每个脚本文件本质上是一个遵循特定契约的 CommonJS / ES 模块。当脚本被激活并绑定至某个配置文件时,运行时沙箱会执行约定的入口函数:

// Clash Verge 扩展脚本标准接口定义
/**
 * 配置处理入口函数
 * @param {Object} config - 原始订阅反序列化后的完整 JavaScript 对象
 * @param {Object} profile - 当前订阅的元数据上下文 (包含 name, url, selected 等)
 * @returns {Object} 处理完成后的最终配置对象
 */
function main(config, profile) {
  // 必须返回一个结构完整的 config 对象
  return config;
}

3.1 沙箱环境技术约束:

  1. 纯同步调用:main 函数必须是纯同步函数,目前不支持异步 async/await 或发起外网 HTTP 异步请求,以确保客户端启动与配置热加载的毫秒级时延。
  2. 纯内存变异:函数接收的 config 是一个纯粹的 JSON 友好型对象。你可以直接在内存中对其属性进行增删改查。
  3. 不可变容错原则:如果脚本执行期间抛出未捕获的未受检异常(Uncaught Exception),Clash Verge 会回退并直接采用原始未改写的配置,同时在控制台记录错误,避免导致核心彻底闪退。

4. 生产级 JavaScript 脚本实战案例集锦

以下提供了三个直接可在生产环境中复用的工业级扩展脚本。

4.1 实战一:在第三方订阅顶部安全插入自定义直连与拦截规则

此脚本可确保你的私有网络规则永远处于匹配的最顶端,不受服务商自带规则的影响:

function main(config, profile) {
  // 1. 定义私有高优先级规则列表
  const customPrependRules = [
    // 强制广告拦截
    "DOMAIN-SUFFIX,doubleclick.net,REJECT",
    "DOMAIN-KEYWORD,adservice,REJECT",

    // 内部私有云与开发环境直连
    "DOMAIN-SUFFIX,corp.internal,DIRECT",
    "IP-CIDR,10.50.0.0/16,DIRECT,no-resolve",

    // 常用开发工具镜像直连
    "DOMAIN-SUFFIX,npmmirror.com,DIRECT",
    "DOMAIN-SUFFIX,goproxy.cn,DIRECT"
  ];

  // 2. 防御性检查: 确保原始配置包含 rules 数组
  if (!Array.isArray(config.rules)) {
    config.rules = [];
  }

  // 3. 将自定义规则解构拼接至规则数组最前端 (保证最高匹配优先级)
  config.rules = [...customPrependRules, ...config.rules];

  return config;
}

4.2 实战二:按正则自动过滤节点并动态构建地区策略组

此脚本会自动扫描订阅中的所有节点,剔除名称中带有“高倍率”或“测试”字样的节点,并将香港、日本、新加坡的优质节点按地区自动归类为专属子策略组:

function main(config, profile) {
  // 防御性校验
  if (!Array.isArray(config.proxies) || config.proxies.length === 0) {
    return config;
  }

  // 1. 过滤掉无意义或过高倍率的节点
  const validProxies = config.proxies.filter(p => {
    const name = p.name || "";
    // 过滤包含 "官网", "剩余流量", "重置", "3倍", "5倍" 的节点
    return !/(官网|剩余|流量|重置|[3-9]倍|[1-9]\d倍)/i.test(name);
  });

  // 提取清洗后的节点名称集合
  const allProxyNames = validProxies.map(p => p.name);

  // 2. 按地区正则匹配分类
  const hkNodes = allProxyNames.filter(n => /(香港|HK|Hong Kong)/i.test(n));
  const jpNodes = allProxyNames.filter(n => /(日本|JP|Tokyo|Osaka)/i.test(n));
  const sgNodes = allProxyNames.filter(n => /(新加坡|SG|Singapore)/i.test(n));

  // 3. 构建现代分层策略组
  const regionalGroups = [
    {
      name: "🇭🇰 香港自动选路",
      type: "url-test",
      url: "http://cp.cloudflare.com/generate_204",
      interval: 300,
      tolerance: 50,
      proxies: hkNodes.length > 0 ? hkNodes : ["DIRECT"]
    },
    {
      name: "🇯🇵 日本自动选路",
      type: "url-test",
      url: "http://cp.cloudflare.com/generate_204",
      interval: 300,
      tolerance: 50,
      proxies: jpNodes.length > 0 ? jpNodes : ["DIRECT"]
    },
    {
      name: "🇸🇬 新加坡自动选路",
      type: "url-test",
      url: "http://cp.cloudflare.com/generate_204",
      interval: 300,
      tolerance: 50,
      proxies: sgNodes.length > 0 ? sgNodes : ["DIRECT"]
    }
  ];

  // 4. 重塑主策略组
  const mainProxyGroup = {
    name: "🚀 节点选择",
    type: "select",
    proxies: [
      "🇭🇰 香港自动选路",
      "🇯🇵 日本自动选路",
      "🇸🇬 新加坡自动选路",
      "DIRECT",
      ...allProxyNames
    ]
  };

  // 5. 替换并挂载策略组
  config.proxies = validProxies;
  config["proxy-groups"] = [
    mainProxyGroup,
    ...regionalGroups,
    // 保留原始配置中可能存在的非重复策略组
    ...(config["proxy-groups"] || []).filter(g => g.name !== "🚀 节点选择")
  ];

  return config;
}

4.3 实战三:统一强制覆写全局 DNS 模块与 TUN 模式

无论服务商自带的 DNS 配置多么简陋,此脚本都会将其强制提升为符合企业级防污染标准的双轨体系(与 DNS 防污染指南 和 TUN 模式配置手册 深度协同):

function main(config, profile) {
  // 强制全量覆盖 DNS 架构
  config.dns = {
    enable: true,
    listen: "127.0.0.1:1053",
    ipv6: false,
    "enhanced-mode": "fake-ip",
    "fake-ip-range": "198.18.0.1/16",
    "default-nameserver": ["223.5.5.5", "119.29.29.29"],
    nameserver: [
      "https://dns.alidns.com/dns-query",
      "https://doh.pub/dns-query"
    ],
    fallback: [
      "https://1.1.1.1/dns-query",
      "https://8.8.8.8/dns-query"
    ],
    "fallback-filter": {
      geoip: true,
      "geoip-code": "CN"
    }
  };

  // 强制开启安全 TUN 模式参数
  config.tun = {
    enable: true,
    stack: "mixed",
    device: "MetaTunDevice",
    "auto-route": true,
    "auto-detect-interface": true,
    "dns-hijack": ["any:53", "tcp://any:53"],
    "strict-route": true,
    mtu: 1420
  };

  return config;
}

5. 脚本调试艺术:日志捕获与常见报错排障

编写脚本时,最令人头疼的是语法错误导致配置静默失效。利用现代调试技巧可以快速定位故障点。

[ 编写/修改 JS 脚本 ] ───▶ [ 点击 Clash Verge 重新加载配置 ]
                                   │
                                   ├───▶ (语法错误 / 空指针异常)
                                   │           │
                                   │           ▼
                                   │     【控制台弹出红色警告 / 捕获堆栈】
                                   │           │
                                   │           ▼
                                   │     【执行 try/catch 防御自愈】
                                   │
                                   └───▶ (处理成功) ───▶ 【配置热加载生效】

5.1 常用排障手段:

  1. 打印内部变量:虽然沙箱环境限制了部分终端 I/O,但在脚本中执行 console.log(JSON.stringify(config.proxies[0])) 会将输出打印在 Clash Verge 的应用日志中。详情可参阅 日志查看与连接状态实时监控诊断指南。
  2. 规避对象深拷贝陷阱:在对 config.rules 进行变异时,避免直接修改循环中的引用,推荐使用扩展运算符 [...array] 或解构赋值,防止意外污染原型链。
  3. 异常全面包裹机制:对于生产级脚本,建议用 try ... catch 包裹核心逻辑,并在异常发生时安全降级:
    function main(config, profile) {
      try {
        // 执行核心变异操作...
      } catch (err) {
        console.error("扩展脚本执行发生致命异常: " + err.message);
        // 发生异常时原样返回,确保不断网
        return config;
      }
      return config;
    }
    

6. 基础设施对自动化脚本的底层支持与专线选型

许多高级自动化脚本(如自动测速容灾、根据协议归类策略)的稳定运行,高度依赖服务商底层节点命名的规范性与线路架构的确定性。

6.1 劣质服务商对动态脚本的破坏性影响

  • 随意更改节点命名:一些缺乏工程化运维的小作坊,经常在节点名字中随意插入 emoji、临时推广标语或打乱国家代码前缀,导致基于正则表达式的脚本全部失效。
  • 节点大面积失活:若服务商后端频繁宕机,url-test 脚本会在策略组中频繁触发故障转移,导致 TCP 连接不断重置,带来极差的上网体验。

6.2 规范化企业级专线服务商的代码友好度

具备高工业水准的基础设施提供商,拥有严格的持续交付标准:

评估维度不规范的普通服务商工业级 IEPL 专线服务商
节点命名规范度随意掺杂乱码与营销词汇,导致正则经常失效遵循标准 ISO 国家代码与层级编号,正则极其健壮
底层协议原生性协议参数不规范,脚本解析容易抛出格式错误标准化 Clash Meta/VLESS/Reality 协议,无缝契合
节点可用率 (SLA)经常大面积红显超时,导致自动选路组雪崩99.9% 以上高 SLA 保障,策略组心跳探活几乎零丢包

如果希望你的自动化脚本体系发挥出最大效能,建议接入具备高规范度与专线保障的基础设施:


7. 常见问题深度解答 (FAQ) 与相关技术链路闭环

Q1: 为什么脚本修改完成后,保存并应用时报错 main is not defined? 这说明脚本文件中遗漏了标准入口函数声明,或者函数名大小写错误。请确保你的代码中包含且仅包含一个名为 `function main(config, profile)` 的全局顶级导出函数。
Q2: 多个脚本文件的执行顺序是怎样的?会互相冲突吗? 在 Clash Verge 中,如果为一个订阅关联了多个扩展脚本,系统会按照列表中的上下排列顺序以管道流(Pipeline)方式依次链式执行前一个脚本的输出作为后一个脚本的输入。请注意将最基础的 DNS/TUN 配置脚本排在最前,将复杂的策略组重组脚本排在最后。
Q3: 遇到订阅完全拉取失败、无法加载脚本上下文怎么办? 请参考 [订阅链接导入与配置更新完整操作指南](/tutorials/import-subscription) 检查远程链接合法性,或参考 [订阅更新失败网络排障](/troubleshooting/subscription-update-failed) 定位 TLS 证书或网络阻断问题。

下一步进阶阅读与技术链路闭环:

网络协议架构组头像
网络协议架构组 网络系统架构组 修订日期: 2026-10-09

本文由具备 CCIE / CISSP 资质背景的网络协议架构工程师主笔,已在 Windows 11、macOS 与 Linux 物理机完成实测复核。欢迎查阅 团队档案与审校机制 或参与公开勘误。

下一步建议操作

遇到问题?查看故障排查

配置过程中若遭遇内核报错、端口冲突或无法上网,快速定位修复。

遇到问题?查看故障排查