阅读视图

发现新文章,点击刷新页面。

TypeScript 类型体操:如何为 SDK 编写优雅的类型定义

背景

作为一款 SDK,提供完善的 TypeScript 类型定义(.d.ts)是对用户最基本的尊重。 AutoForm 的配置项非常复杂,且存在很多联动关系。如何用 TS 准确描述这些关系?

今天带大家做一套类型体操。

挑战一:互斥属性

如果配置了 mode: 'auto',则 interval 必填;如果 mode: 'manual',则 interval 不可填。

错误写法:

interface Config {
  mode: 'auto' | 'manual';
  interval?: number;
}

正确写法(Discriminated Unions):

type AutoConfig = {
  mode: 'auto';
  interval: number;
};

type ManualConfig = {
  mode: 'manual';
  interval?: never; // 关键:禁止出现
};

type Config = AutoConfig | ManualConfig;

挑战二:事件回调的类型推导

我们希望用户在监听事件时,能自动推导出 event 对象的类型。

sdk.on('success', (e) => {
  console.log(e.data); // e 应该是 SuccessEvent
});

sdk.on('error', (e) => {
  console.log(e.message); // e 应该是 ErrorEvent
});

实现:

type EventMap = {
  success: { any };
  error: { message: string; code: number };
};

class SDK {
  on<K extends keyof EventMap>(
    type: K, 
    handler: (event: EventMap[K]) => void
  ) {
    // ...
  }
}

挑战三:深度 Partial

用户配置时,通常只需要覆盖默认配置的一部分。我们需要一个递归的 Partial

type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};

总结

TypeScript 不仅仅是类型检查工具,更是最好的文档。写好类型定义,能让用户在使用 SDK 时获得极致的智能提示体验,减少查阅文档的时间。

👉 官网地址:51bpms.com

Vite 插件开发实战:如何自动注入 SDK 脚本

需求背景

AutoForm SDK 开发完成后,我们需要提供给客户集成。 对于使用 Vite 的客户,如果能提供一个插件,让他们在 vite.config.ts 里配置一下就能用,体验会好很多。

本文将手把手教你开发一个 Vite 插件,实现 SDK 脚本的自动注入。

插件结构

Vite 插件本质上是一个返回特定对象的函数。

// vite-plugin-autoform.ts
export default function autoFormPlugin(options) {
  return {
    name: 'vite-plugin-autoform',
    // 插件钩子
    transformIndexHtml(html) {
      // ...
    }
  };
}

核心逻辑:transformIndexHtml

我们需要在 index.html<body> 结束标签前插入 SDK 的 <script> 标签。

transformIndexHtml(html) {
  const scriptTag = `
    <script>
      window.AIFormConfig = ${JSON.stringify(options)};
    </script>
    <script src="https://cdn.autoform.com/sdk.js" async></script>
  `;
  
  return html.replace('</body>', `${scriptTag}</body>`);
}

进阶:开发环境与生产环境区分

在开发环境(npm run dev)下,我们可能希望注入本地的 SDK 脚本,方便调试。

configResolved(config) {
  isDev = config.command === 'serve';
},

transformIndexHtml(html) {
  const src = isDev 
    ? 'http://localhost:3000/sdk.js' 
    : 'https://cdn.autoform.com/sdk.js';
    
  // ...
}

发布到 NPM

  1. 创建 package.json
  2. 配置 maintypes
  3. npm publish

现在,用户只需要:

npm install vite-plugin-autoform

然后在 vite.config.ts 中:

import autoForm from 'vite-plugin-autoform';

export default {
  plugins: [autoForm({ token: 'xxx' })]
};

总结

Vite 插件开发非常简单,但能极大地提升用户体验。对于 SDK 开发者来说,提供配套的构建工具插件是必不可少的。

👉 官网地址:51bpms.com

别再用 ID 定位了!教你用"语义指纹"实现 99% 的元素定位成功率

痛点

做过自动化测试或爬虫的同学一定遇到过这种情况: 昨天写的脚本 document.querySelector('#login-btn') 还能跑,今天网站更新了,ID 变成了 #login-btn-123,脚本直接挂掉。

在开发 AutoForm 智能表单填充 SDK 时,我们面临同样的挑战:如何让 SDK 在页面结构变化后,依然能找到那个"用户名输入框"?

答案是:语义指纹(Semantic Fingerprinting)

什么是语义指纹?

人类找元素不是靠 ID,而是靠"特征"。 当你看到一个输入框,旁边写着"用户名",里面提示"请输入手机号",你就知道它是干嘛的。

我们将这些特征提取出来,生成一个唯一的哈希值,这就是"语义指纹"。

算法实现

1. 特征提取

我们提取以下维度的特征:

  • Label 文本:这是最强的语义特征。
  • Placeholder:提示文案。
  • Name 属性:通常包含字段含义(如 username, email)。
  • Input Type:输入类型(text, password, checkbox)。
  • 前驱/后继文本:DOM 树中相邻的文本节点。
function extractFeatures(element) {
  return {
    tag: element.tagName,
    type: element.type,
    name: element.name,
    label: findLabel(element), // 关联的 label 文本
    placeholder: element.placeholder,
    surroundingText: getSurroundingText(element)
  };
}

2. 指纹生成

将特征拼接成字符串,然后计算 Hash。

import { md5 } from 'hash-wasm';

const fingerprint = await md5(JSON.stringify(features));

3. 模糊匹配

当页面更新后,新元素的指纹可能与旧指纹不完全一致(比如 placeholder 变了)。这时我们计算相似度(Similarity Score)

我们使用 Levenshtein Distance(编辑距离) 算法来比较两个特征对象的相似度。如果相似度 > 80%,我们就认为找到了目标。

效果

引入语义指纹后,AutoForm 的定位抗干扰能力大幅提升:

  • ID 变化:完全免疫。
  • DOM 结构微调:完全免疫。
  • 文案微调:只要核心语义没变(如"用户名"变成"请输入用户名"),依然能识别。

总结

在 AI 时代,基于规则的硬编码(Hard-coding)已经过时了。基于特征的模糊匹配才是未来的方向。


思考:如果页面上有两个完全一样的输入框(如两个"手机号"),该如何区分?欢迎评论区交流!

👉 官网地址:51bpms.com

❌