npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ethanyu99/model-replace-js

v4.0.0

Published

A framework-agnostic DOM text replacement runtime for model aliases.

Readme

Model Replace JS

一个与框架无关的 DOM 文本替换脚本。业务项目只需引入一个 CDN <script>,无需安装浏览器插件,也无需修改 React/Vue 渲染逻辑。

浏览器数据源统一使用 internal-model-proxy:实时读取总开关,一次获取三个规则组,按 LLM > SKU > 模型 CMS 合并,并保存完整缓存和备份。

快速接入

发布 npm 包后,构建产物 dist/snippet.html 会生成带固定版本和 SRI 的完整标签:

<script
  defer
  src="https://cdn.jsdelivr.net/npm/@ethanyu99/[email protected]/dist/model-replace.min.js"
  integrity="构建生成的 sha384"
  crossorigin="anonymous"
  data-model-replace
></script>

建议把标签放在 <head> 中、业务应用 bundle 之前。脚本会在 DOM 可用后扫描现有 Text Node,并通过 MutationObserver 继续处理 SPA 动态内容和弹窗表单。

脚本启动时先请求 proxy 的总开关;明确开启后读取规则并执行替换。只有网络请求失败时才允许沿用该 proxy 上次确认的开关状态。 三个规则组通过一次聚合请求返回,相同关键词采用 LLM > SKU > 模型 CMS,全部为全局规则。 已有完整缓存时立即分片替换;冷启动默认前台等待 200 毫秒,超时后继续后台加载并自动补扫。 已成功替换的元素保持只处理一次。

默认使用国内 proxy:https://internal-model-proxy.paigod.work。 海外页面设置 data-proxy-base-url="https://internal-model-proxy.pplabs.tech",两个环境使用同一份 JS。 构建产物 dist/snippet-cn.htmldist/snippet-overseas.html 分别提供带固定版本和 SRI 的完整标签。 跨域业务页面必须先在入口配置 CORS;也可通过 data-proxy-base-url 指向同源网关。

映射配置

飞书 skuCode / 代号 可通过 npm run sync:sku 预览并同步到 SKU CMS,支持去重、 PATCH 更新、字段类型兼容、备份和失败恢复。配置与执行方式见 SKU 同步脚本

完整模型映射可通过 npm run sync:model 推导关键词,并同步到 model CMS; --apply 会新增、更新并清理表外规则,保存备份及无法用关键词完整表达的模型差异。 配置与执行方式见 模型关键词同步脚本

手动规则示例维护在以下文件中;不会嵌入运行时或用作网络失败的兜底:

config/model-aliases.json

格式:

{
  "version": "2026-07-28-01",
  "enabled": true,
  "rules": {
    "source-model": "public-model"
  }
}

构建时会:

  1. 构建从 proxy 读取数据的 CDN bundle。
  2. 复制示例 JSON 到 dist/model-aliases.json,供显式手动规则模式参考。
  3. 运行时将成功加载或缓存的规则按 source 长度降序编译,优先匹配完整模型 ID,再匹配系列词。

Proxy 规则数据源

浏览器只访问同一个 proxy 的两个接口:

| 接口 | 用途 | | --- | --- | | /api/items/open_model_replace/1 | 总开关,cache: "no-store";网络失败时可用上次确认的状态 | | /api/model-replace/rules | 一次返回三个有效规则数组,浏览器不再分页 |

{
  "llm_list": [{ "goal_keyword": "original-model", "replace_keyword": "display-model" }],
  "sku_list": [{ "goal_keyword": "ORIGINAL_SKU", "replace_keyword": "DISPLAY_SKU" }],
  "model_replace_keyword": [{ "goal_keyword": "original-keyword", "replace_keyword": "display-keyword" }]
}

三个数组均须存在。每条记录的原词和替换词须为非空字符串,客户端去掉首尾空白并忽略其他字段。 任一数组缺失或记录无效时,整轮更新失败,保留上一份完整快照;合法空数组用于清除对应组的旧规则。 所有远程规则全局生效,不再解析 include_page_pathsexclude_domainscopes

配置入口

<script defer src="CDN_URL" data-model-replace
  data-proxy-base-url="https://rules.example.com/gateway/model-replace"
></script>

该配置请求 https://rules.example.com/gateway/model-replace/api/model-replace/rules, 总开关也使用同一个主机和路径前缀。支持 /model-proxy 这样的相对路径。

await ModelReplace.start({
  proxyBaseUrl: "https://rules.example.com/gateway/model-replace",
  startupTimeoutMs: 200,
  refreshTimeoutMs: 15000,
});

也可在加载脚本前设置全局变量,或者构建时注入:

window.MODEL_REPLACE_PROXY_BASE_URL = "https://rules.example.com";
MODEL_REPLACE_PROXY_BASE_URL="https://rules.example.com" npm run build

优先级:启动参数 / Script 属性 → 全局变量 → 构建变量 → 默认 Railway 地址。 显式空字符串、无效协议或带用户名/密码的 URL 会保持开关关闭,不回退默认主机。 请求不携带 Cookie、Basic Auth 或 Bearer Token,也不跟随重定向。上游鉴权只配置在 proxy 服务端。

从分源配置迁移

移除 cmsBaseUrlskuBaseUrlapiBaseUrlppioBaseUrlbaseUrl 及各来源的 *RulesUrl / rulesUrl, 以及对应的 data-*MODEL_REPLACE_CMS_BASE_URLMODEL_REPLACE_SKU_BASE_URLMODEL_REPLACE_API_BASE_URLMODEL_REPLACE_PPIO_BASE_URLMODEL_REPLACE_BASE_URL 配置。统一改为 proxyBaseUrl / data-proxy-base-url / MODEL_REPLACE_PROXY_BASE_URL。 旧地址配置不再参与请求,CMS 总开关也不会直连原上游。

导出常量改为 DEFAULT_PROXY_BASE_URLDEFAULT_RULES_URLDEFAULT_OPEN_STATUS_URL;旧分源 URL 常量已移除。 api: false / data-api="false" 只排除 llm_listsku: false / data-sku="false" 只排除 sku_listppio / data-ppio 仅作为 api 布尔开关的兼容别名,新开关优先。 这些开关不增加网络请求;完整聚合结果仍只请求一次。

服务端同步工具 sync:modelsync:sku 继续直接管理 CMS;它们不在浏览器 bundle 中。 历史分源代理工具 保留维护,但不是新客户端的聚合服务。 新的聚合服务部署在 internal-model-proxy。 源码更新不会改变已经发布的 npm/CDN 资产;使用新协议前需发布新版本并更新页面的脚本地址,不要覆盖已有版本。

合并、缓存与故障处理

同原词去除首尾空白并忽略大小写,优先级固定为 llm_list > sku_list > model_replace_keyword。 不同关键词合并后按长度优先匹配,保留原词等于替换词的映射,保护完整名称不被短词误替换。 优先级解决同原词冲突;不同原词应避免共用同一别名,以免反向恢复出现歧义。

客户端把三个组作为一个完整快照写入 model-replace:proxy-rules:v1,并保存 :backup。 快照按完整聚合 URL 隔离,最多保留 10 个 URL;旧 v3/v4 分源缓存不迁移,避免不同协议和规则范围混用。 主缓存损坏时读取完整备份,localStorage 不可用时保留页面内存快照。 getStatus().sources 保留 apicms-skucms 三个来源 ID,对应 LLM、SKU 和模型 CMS;它们的请求 URL 相同。

默认浏览器缓存有效期为 5 分钟。新鲜快照不重复下载规则,但每次启动仍实时检查总开关。 过期快照先使用、再后台刷新;请求或响应校验失败时保留整份旧快照。 没有完整缓存时,前台默认等待 200 毫秒;超时仅结束前台等待,页面保持原词,rulesPending: true,后台继续加载。 完整结果返回后一次提交并自动补扫。请求最多等待 5 秒,后台整轮期限默认 15 秒,均包含响应体读取。 后台失败且没有完整快照时保持页面原样:不启动 DOM 扫描、MutationObserver 或表单改写,状态为 active: false。 远程模式不会使用内置或显式传入的手动规则兜底;合法的空数组表示清空规则,不视为网络异常。 失败后不会自动持续重试,可再次 start() 发起新一轮加载。

proxy 在服务端每分钟刷新;浏览器缓存的 5 分钟期限独立生效,服务端轮询不会主动推送更新给已打开的页面。 可用 cacheTtlMs: 0 让每次启动重新获取规则。客户端不请求上游分页,也不在出错时切换到 CMS / API 原站。 每次启动先实时读取总开关,并将成功确认的布尔值按完整 URL 保存到 model-replace:proxy-open-status:v1。 断网、CORS 拦截、请求超时或响应流中断时可沿用缓存状态;只有缓存状态为开启且有完整规则可用时才替换页面。 没有缓存时保持页面原样。明确关闭、HTTP 错误(包括 401/503)或无效开关响应时保持关闭,不会被旧的开启状态覆盖。 开关状态和规则快照均有页面内存缓存,localStorage 不可用时仍可在本页重复启动时使用;跨页面则需要可用的持久缓存。

浏览器网络接入

Proxy 域名的 HTTP 200 不代表跨域页面可读。跨域入口须对业务页面设置精确的 Access-Control-Allow-Origin,并为多个允许的 Origin 正确设置 Vary: Origin;可由既有 Ingress / 网关处理。 国内入口需允许实际国内业务页面,海外入口需允许实际海外业务页面;JS 无法绕过浏览器的 CORS 限制。 若采用同源网关,例如 data-proxy-base-url="/model-proxy",则无需浏览器跨域授权。

本项目不更改公司网段限制、网关鉴权或 proxy 的 CORS 策略。 页面 CSP 的 connect-src 需允许所选 proxy / 网关。总开关的真实值由 CMS 管理,接入改造不会自动打开它。

DOM 按文档顺序增量遍历,优先处理前面的字段,每批目标预算 4 毫秒,通过 scheduler.yield() 让出 主线程,并定期插入普通定时器,避免高优先级续执行饿死业务定时器;不支持该 API 时 全部使用定时器。动态新增节点合并排队,开放 Shadow DOM 和大型下拉框的 option 同样分批处理。 预算在元素之间检查,单个巨大文本节点、浏览器布局和 GC 仍可能超出预算。 start() 在本轮初始扫描完成或进入等待后台数据状态后返回。业务启动不应依赖它: 无需主动等待时使用 void ModelReplace.start(),页面渲染和交互可照常继续。

已成功替换的 DOM 仍保持每个元素只替换一次,规则刷新仅影响未标记或新增元素。 因此旧缓存或后台失败降级产生的已替换结果不会被重做;要求首帧绝对一致时应在 BFF 或服务端渲染阶段完成映射。stop() 或再次 start() 会取消前一轮加载和未完成的扫描分片。

关键词匹配继续忽略大小写并保留输入大小写样式,例如 grok → marsGrok → MarsGROK → MARS

Script 配置

| 属性 | 默认值 | 说明 | | --- | --- | --- | | data-model-replace | - | 标识当前 CDN 脚本 | | data-auto-start | true | 设为 false 后由业务代码手动启动 | | data-proxy-base-url | https://internal-model-proxy.paigod.work | 海外使用 https://internal-model-proxy.pplabs.tech;保留路径前缀 | | data-api | true | 是否使用聚合响应中的 LLM 规则 | | data-sku | true | 是否使用聚合响应中的 SKU 规则 | | data-remote-rules | true | 是否加载远程规则;手动 API 传入 ruleSet 时默认 false | | data-startup-timeout-ms | 200 | 冷启动前台规则等待上限,超时后继续后台加载,须为正数 | | data-refresh-timeout-ms | 15000 | 每轮后台规则加载的硬期限,超时取消未完成请求,须为正数 | | data-cache-ttl-ms | 300000 | 完整规则缓存有效期;设为 0 时每次启动都在后台重新验证 | | data-observe | true | 是否监听后续 DOM 变化 | | data-form-controls | true | 是否直接替换表单控件的真实 value | | data-preserve-form-values | false | 表单显示别名,但原生提交保留原始 value;需同时开启 data-form-controls | | data-debug | false | 输出启动状态和规则加载错误 | | data-ignore-selector | 内置选择器 | 完全覆盖默认忽略选择器 | | data-exclude-selector | 空 | 排除整个子树及其 Shadow DOM、表单控件,例如 wujie-app;保留 3.1.0 行为 |

页面局部不希望被替换时:

<section data-model-replace-ignore>
  这里保留原始模型名称
</section>

Text Node 扫描默认忽略 scriptstyle、表单控件、可编辑元素和带忽略标记的区域;表单控件由独立的 value 替换逻辑处理。

表单 value 替换

Runtime 会直接改写 inputtextareabuttonselect option 的真实 value,select 的 option 显示文本和显式 label 也会一起替换。因此原生 FormData 和基于当前 DOM value 的提交请求会使用替换后的名称。

替换前 value:claude-fable-5
页面展示:    Venus-Cathedral-5
提交 value: Venus-Cathedral-5

如果目标是“编辑时显示别名、提交时使用原始名称”,开启保留模式:

<script
  src="CDN_URL"
  data-model-replace
  data-form-controls="true"
  data-preserve-form-values="true"
></script>

保留模式会用别名显示文本输入框、文本域、按钮和 option label/text,但隐藏字段、复选框、单选框和 option value 保持原始值。Runtime 使用 WeakMap 记录发生替换的控件原值与展示值,并在浏览器生成原生 FormData 时恢复字符串字段。React、Vue 等受控表单应先用 ModelReplace.replaceValue() 把接口数据转换成展示状态,再把该状态交给表单;请求序列化前使用 ModelReplace.restoreValue() 恢复原始名称。两个结构化 API 使用 WeakMap 保留循环引用和共享引用,并跳过 Date、Dayjs 等非普通对象。

const displayValues = ModelReplace.replaceValue(apiPayload);
form.setFieldsValue(displayValues);

const requestPayload = ModelReplace.restoreValue(form.getFieldsValue(true));

只修改受控输入框的 DOM value 会被 React/Vue 后续渲染重新写回。Runtime 不会在 focus 后重复处理已标记元素,因此受控表单必须使用上述展示状态方案。restoreText()/restoreValue() 只会反向转换目标名称唯一的规则;存在重复目标名称时保持原值,避免恢复到错误模型。

初始页面、动态弹窗和新插入控件都会自动处理,也支持 Runtime 与目标 DOM 分属不同同源 Realm 的 Wujie/ShadowRoot 场景。每个实际发生替换的 DOM 元素会写入 data-replace="true",并同时记录在 WeakMap 中;同一个元素在当前页面生命周期内最多替换一次,即使业务代码移除该属性也不会再次处理。初始值未命中规则的控件仍会监听 input/change,直到第一次成功替换。隐藏字段、复选框、单选框和多选 select 都会处理;文件输入框因浏览器安全限制不会修改。需要完全禁用时:

<script src="CDN_URL" data-model-replace data-form-controls="false"></script>

全局 API

IIFE bundle 会暴露 window.ModelReplace

await ModelReplace.start();
ModelReplace.stop();
ModelReplace.refresh();
await ModelReplace.whenIdle();
ModelReplace.replaceText("Opus");
ModelReplace.replaceValue({ model: "claude-opus" });
ModelReplace.restoreText("Marble");
ModelReplace.restoreValue({ model: "venus-marble" });
ModelReplace.getStatus();

getStatus()isOpen 表示是否已通过 proxy 总开关并启用替换,controlReplacementCount 表示当前启动周期中发生过表单控件替换的次数。sources 分别报告 CMS / SKU CMS / API 的 requestedUrlresolvedUrlstate(idle/loading/ready/error/disabled)、 cache(none/fresh/stale)、ruleCountrulesVersioncachedAterrorfallback(失败时为 cache/none)。 手动规则模式或总开关关闭时,sources 为空。rulesPending 表示尚未提交初始规则, scanning 表示存在未完成的 DOM 分片。

也可以手动传入规则,此时默认不加载远程规则,总开关仍通过 proxy 读取。 若显式设置 remoteRules: true 则只使用 proxy 数据或其缓存,忽略手动规则,不把它们作为失败兜底:

await ModelReplace.start({
  ruleSet: {
    version: "custom-1",
    rules: { "source-model": "public-model" },
  },
});

事件:

window.addEventListener("modelreplace:ready", (event) => {
  console.log(event.detail);
});

window.addEventListener("modelreplace:updated", (event) => {
  console.log("动态规则已进入内存", event.detail);
});

window.addEventListener("modelreplace:error", (event) => {
  console.error(event.detail);
});

ModelReplace.refresh() 将扫描加入队列,只处理尚未成功替换过的元素。它仍返回数字, 现在表示调用期间已同步完成的替换数,大页面的其余工作会分片继续;需要完成结果时, 先调用 refresh(),再 await ModelReplace.whenIdle() 并读取 getStatus()whenIdle() 只等待当前 DOM 队列,不等待网络;后台规则提交会发送 modelreplace:updated, 该事件表示规则已提交、补扫已调度,可以在事件中调用 whenIdle() 等补扫完成。

不同项目如何接入

以下示例中的 CDN_URL 应替换为固定版本地址:

https://cdn.jsdelivr.net/npm/@ethanyu99/[email protected]/dist/model-replace.min.js

原生 HTML / 传统服务端模板

直接放在 <head> 中:

<script defer src="CDN_URL" data-model-replace></script>

适用于静态 HTML、PHP、Java/JSP、Go Template、Django Template 等服务端页面。

React + Vite

在项目根目录的 index.html 中,将脚本放在 React 入口之前:

<head>
  <script defer src="CDN_URL" data-model-replace></script>
</head>
<body>
  <div id="root"></div>
  <script type="module" src="/src/main.tsx"></script>
</body>

不需要修改 React 组件。脚本的 Observer 会继续处理路由切换和 setState 产生的新 DOM。

Vue + Vite

同样在 index.html 中、Vue 入口之前引入:

<script defer src="CDN_URL" data-model-replace></script>
<script type="module" src="/src/main.ts"></script>

Vue Router 和响应式更新生成的新节点会被自动处理。

Angular

src/index.html<head> 中添加:

<script defer src="CDN_URL" data-model-replace></script>

不建议写入 angular.jsonscripts 数组,因为那样不方便给标签配置 SRI、crossorigindata-* 参数。

Next.js

SSR 页面必须等 hydration 开始后再修改 DOM,避免服务端 HTML 与客户端首帧不一致。在 App Router 的 app/layout.tsx 中:

import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html lang="zh-CN">
      <body>{children}</body>
      <Script
        src="CDN_URL"
        strategy="afterInteractive"
        data-model-replace=""
      />
    </html>
  );
}

不要使用 beforeInteractive 自动启动,否则脚本可能在 React hydration 前改动服务端文本。

Nuxt

先在 nuxt.config.ts 中加载脚本但关闭自动启动:

export default defineNuxtConfig({
  app: {
    head: {
      script: [
        {
          src: "CDN_URL",
          defer: true,
          "data-model-replace": "",
          "data-auto-start": "false",
        },
      ],
    },
  },
});

再创建 plugins/model-replace.client.ts,等应用挂载后启动:

export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook("app:mounted", async () => {
    await window.ModelReplace?.start();
  });
});

微前端

建议只在主应用 Shell 中加载一次,不要让每个子应用分别创建 Observer:

<!-- host/index.html -->
<script defer src="CDN_URL" data-model-replace></script>

子应用卸载时无需停止主应用 Runtime。需要隔离某个子应用时,在其根节点添加:

<div id="sub-app" data-model-replace-ignore></div>

WordPress / CMS

可以通过主题模板、全局 Header 配置或脚本管理插件加入:

<script defer src="CDN_URL" data-model-replace></script>

普通文本和表单控件默认都会显示别名,提交值也会被替换;需要保留原始提交值时设置 data-preserve-form-values="true"。富文本编辑区仍保留原始内容。

SSR 通用原则

  • CSR/SPA 可以在应用入口前加载并自动启动。
  • React SSR、Vue SSR 等页面应在 hydration 后启动,避免 hydration mismatch。
  • hydration 后启动可能短暂显示原始文本;如果业务不能接受闪烁,应改用 BFF 或服务端模板阶段完成映射。

部署到其他 CDN 平台

除了 npm + jsDelivr/unpkg,也可以直接部署 release/cdn-<version>/ 下的静态文件。

Nginx

将静态文件复制到版本目录,例如:

/var/www/cdn/model-replace/4.0.0/model-replace.min.js

推荐响应头:

location /model-replace/ {
  add_header Access-Control-Allow-Origin "*" always;
  add_header Cache-Control "public, max-age=31536000, immutable" always;
  try_files $uri =404;
}

AWS S3 / Cloudflare R2 / 对象存储

先生成发布目录:

npm run release:build

然后上传整个版本目录:

aws s3 sync release/cdn-4.0.0 s3://YOUR_BUCKET/model-replace/4.0.0 \
  --cache-control "public,max-age=31536000,immutable"

对象存储需要正确设置 .jsContent-Type: text/javascript、JSON 的 application/json,并允许 GET/HEAD 跨域访问。Proxy 的总开关和聚合接口都必须 配置 CORS。

内部制品/CDN 平台

直接上传 release/cdn-<version>/ 即可。业务项目引用带版本的路径,不应覆盖已经发布的版本目录;升级时发布新目录并更新 <script src>

CSP

使用第三方 CDN 时,需要把域名加入 CSP:

Content-Security-Policy: script-src 'self' https://cdn.jsdelivr.net

还需要把默认或自定义规则接口域名加入 CSP 的 connect-src

本地构建与验证

npm install
npm test
npm run dev

打开 http://localhost:4173。演示页包含初始文本、动态插入文本、直接替换提交值的表单和动态弹窗。

构建产物:

dist/
├── model-replace.js
├── model-replace.js.map
├── model-replace.min.js
├── model-replace.min.js.map
├── model-replace-4.0.0.min.js
├── model-aliases.json
├── manifest.json
└── snippet.html

manifest.json 包含文件大小、SHA-384、规则版本和 jsDelivr/unpkg 地址。

生成正式发布包:

npm run release:build

输出:

release/
├── cdn-4.0.0/                         # 可直接上传 Nginx/S3/R2
└── ethanyu99-model-replace-js-4.0.0.tgz # 可执行 npm publish 的包

发布到 CDN

本项目通过 npm 发布,jsDelivr 和 unpkg 会自动分发 npm 包内容。

首次发布前确认 package.json 的包名属于你的 npm 用户或组织,然后登录:

npm login
npm run publish:check
npm run publish:cdn -- --dry-run
npm run publish:cdn

正式发布新版本(例如下一个功能版本):

npm version minor
npm run release:build
npm run publish:check
git push origin main --follow-tags
npm run publish:cdn

当前主远端是 GitLab,因此发布 npm/CDN 默认使用上面的手动命令。仓库中的 .github/workflows/release.yml 仅在同步到 GitHub 且配置 NPM_TOKEN Secret 后, 才会在推送 v* Tag 时自动发布。

发布后固定使用明确版本,避免线上引用 latest

https://cdn.jsdelivr.net/npm/@ethanyu99/[email protected]/dist/model-replace.min.js
https://unpkg.com/@ethanyu99/[email protected]/dist/model-replace.min.js

能力边界

  • 普通内容只修改 DOM Text Node,不修改接口响应、React Props 或框架状态。
  • 默认表单模式会修改当前 DOM value、默认值、placeholder 以及 option 的 value/显示文本。开启 preserveFormValues 后,表单可见内容显示别名,原生 FormData 恢复原始名称;React/Vue 受控表单应以 replaceValue() 生成展示状态,并在请求层调用 restoreValue()。成功替换后,该元素后续由业务框架写入的新值不会再次替换。
  • 文件输入框、富文本、Canvas 和 CSS content 不处理。
  • 支持页面本身及开放的 Shadow DOM;关闭的 Shadow DOM 和跨域 iframe 无法处理。
  • stop() 会停止后续监听,但不会还原已经替换的 Text Node 或表单 value;需要还原时刷新页面。
  • 生产环境应固定版本、配置 SRI,并在 CSP 的 script-src 中允许所用 CDN 域名。