@vizejs/plugin-sdk

中文文档
0.650.0发布于 2026/11/03MITTypeScriptES Module零依赖构建来源已验证

确定性编写和独立执行的Vize JavaScript插件

中文使用文档
文档目录9 节
  1. 类型化访问者功能描述符
  2. Lint规则和自动修复
  3. 事实上供应商
  4. 原生模板转换
  5. 格式化程序和输出挂钩
  6. 决定论,缓存和成本
  7. 隔离的回调源
  8. 虚拟TypeScript访客
  9. Devtools跟踪访问者

@vizejs / plugin-sdk

编写同步规则、事实提供程序、本地模板转换和编译 输出钩子。安装 @vizejs/native 0.650.0或更新版本 执行插件。 可选的本机对等体允许该包独立安装以进行创作; 它的帮助程序本身并不编译或检测Vue文件。需要Node 22或更新版本。

类型化访问者功能描述符

@vizejs/plugin-sdk/visitor 定义稳定版本的描述符边界 visitor-style插件。v1功能词汇表包括SFC、模板、 script, style, virtual TypeScript, diagnostics, lint, format和devtools trace 事件。每个声明的功能都需要一个匹配的同步回调,并且 TypeScript将回调负载缩小到该功能。

import {
  VISITOR_API_VERSION,
  defineVisitorPlugin,
  negotiateVisitorPlugin,
} from "@vizejs/plugin-sdk/visitor";

const observer = defineVisitorPlugin({
  apiVersion: VISITOR_API_VERSION,
  name: "virtual-ts-observer",
  version: "1.0.0",
  capabilities: ["virtual-ts", "diagnostics"] as const,
  cacheInputs: [],
  visitors: {
    "virtual-ts"(event) {
      console.log(event.payload.virtualFile, event.payload.mappings.length);
    },
    diagnostics(event) {
      console.log(event.payload.diagnostics.length);
    },
  },
});

negotiateVisitorPlugin(observer, {
  apiVersion: VISITOR_API_VERSION,
  capabilities: ["virtual-ts", "diagnostics"],
});

定义失败关闭未知或重复的功能,缺失或 未声明的回调函数、异步函数、保留的缓存输入名称和API 版本不匹配。 runVisitorFixture 冻结一个已编写的事件并强制执行 包测试的同步返回契约。

这个模块只创建不可变的描述符和作者fixture。事实并非如此 在本机编译器、过滤器或语言服务器中注册回调,以便导入 它不会给这些路径增加功。生产主机必须显式地协商 描述符并拥有取消、截止日期、隔离和事件构造。 虚拟TypeScript和devtools跟踪观察者使用单独的可选主机 entrypoints;导入该模块永远不会全局注册这两个回调。

Lint规则和自动修复

import * as native from "@vizejs/native";
import { definePlugin, applyFixes } from "@vizejs/plugin-sdk";

const rule = definePlugin({
  name: "team-rule",
  version: "1.0.0",
  visit: ["ui.bind"],
  demands: [],
  cacheInputs: [],
  rules: {
    check(ctx) {
      for (const node of ctx.nodes) {
        if (node.name === "disabled" && node.value === "true") {
          ctx.report(node, "Use a literal boolean attribute.", "disabled");
        }
      }
    },
  },
});
const output = native.lintWithPlugins(source, [rule], {
  filename: "Button.vue",
  cache: true,
  validateDeterminism: true,
});
const fixed = applyFixes(source, output.fixes);

报告为访问的L2节点命名。Rust分配它自己编写的UTF-8字节范围; 修复将替换整个范围。 applyFixes 保存其他资源; 重复删除相同的建议并自动拒绝冲突的编辑。 慎重地应用建议,然后重新运行编译器和筛选器。

规则接收不可变的批。 ctx.facts(name) 的组 静态 demands 列表;没有未声明的表越过边界。本地组 包括 templateScopes 以及注册的Croquis生产商 bindings, undefined-refs, component-usages, reactivity, provide-inject 和 race-conditions 和 unused-bindings。后者计算其注册 bindings 依赖。这个 bindings 和 unused-bindings 跨度是创建的 SFC UTF-8字节范围,由共享生成器映射,即使是重新排序分割 脚本。其他主要位置字段保留其Croquis分析框架: 未定义的引用/组件使用是相对于模板的;反应活性, 提供/注入和比赛位置是相对于脚本的(合并的正常/设置) 脚本(当两者都存在时)。报告和修复总是使用主机的SFC范围。公共组件接口页面有 component-signature, prop-types, emit-types, slot-types, reactivity-classes 和 component-references。每个接口值都保留了生产者的模式, 可空的未知数和类型依赖的完整性。签名的 props_complete 单独记录是否枚举了所有属性名。 只有源代码的SDK路由没有已解析的目录证明,因此它报告false 不从磁盘读取导入的文件。导入的类型 分析无法解决仍然明确的未知数。基本的Croquis事实要求 JavaScript或TypeScript脚本;其他脚本方言被明确拒绝。

插件访问需要内联HTML模板。撰写外国模板方言 外部模板块在回调之前被拒绝;SDK没有 假装它们的源是HTML,或者为预处理过程发明源映射。

TypeScript推断出每个原生组的精确映射键和深度只读值 从 ctx.facts("prop-types"),包括授权接口顺序和所有发出 过载。包导出 FactGroups, FactKey, FactValue, FactEntry 以及个体的本地契约。自定义提供程序组可以使用 ctx.facts<MyFact>("design/labels"); 未知组默认为 unknown.

事实上供应商

import { defineFactProvider, definePlugin } from "@vizejs/plugin-sdk";
const labels = defineFactProvider({
  name: "design",
  version: "1",
  provides: ["design/labels"],
  visit: ["ui.element"],
  demands: ["bindings"],
  cacheInputs: [],
  provide(batch) {
    return { "design/labels": batch.nodes.map((node) => [node.id, node.name]) };
  },
});
const consumer = definePlugin({
  name: "labels",
  version: "1",
  demands: ["design/labels"],
  cacheInputs: [],
  rules: {
    check(ctx) {
      const labels = ctx.facts("design/labels");
    },
  },
});
native.lintWithPlugins(source, [consumer], { cache: true, factProviders: [labels] });

提供者将每个输出组声明为 provider-name/group,这是必需的。 事实和节点访问。主机计算依赖闭包并拒绝 在使用事实之前,循环、冲突、未声明的输出和格式错误的表。 每个表包含 [stringOrNumericKey, jsonValue] 具有唯一键的行。 提供程序依赖戳记自动输入消费者缓存键。

原生模板转换

import { defineTransformPlugin } from "@vizejs/plugin-sdk";
const design = defineTransformPlugin({
  name: "design-system",
  version: "1",
  cacheInputs: [],
  transform(batch) {
    return batch.nodes
      .filter((node) =>
        node.attrs.some((attr) => attr.name === "class" && attr.value === "legacy-btn"),
      )
      .map((node) => ({
        kind: "replace-static-attribute",
        node: node.id,
        name: "class",
        value: "ds-button",
      }));
  },
});
const transformed = native.compileWithTransformPlugins(template, [design], {
  filename: "Button.vue",
  sourceMap: true,
  cache: true,
  cacheDir: ".vize-cache",
});

钩子在原生规范前的L2点运行。它可以取代现有的 静态HTML属性从主机的允许设置;动态属性, 结构编辑、模板载体和外部命名空间拒绝。值是 语义文本,而不是实体拼写。未知目标或重复编辑拒绝 整个响应。编译器将类型化编辑应用于它的真实竞技场和 发出代码和绘制的地图;不接受客户AST JSON。结果是 带有前缀标识符的模块。 plugins 包含每个插件的成本。

格式化程序和输出挂钩

import { defineOutputPlugin } from "@vizejs/plugin-sdk";
const license = defineOutputPlugin({
  name: "license",
  version: "1",
  family: "output",
  cacheInputs: [],
  output() {
    return [{ placement: "prepend", comment: "Copyright Example" }];
  },
});
const compiled = native.compileWithOutputPlugins(template, [license], options);
const decorated = native.applyOutputPlugins(transformed.result, [license], { cache: true });

family: "formatter" 返回 {start,end,text} 使用UTF-8字节偏移量进行编辑。 只有保留已解析程序和注释的空白格式 接受。 family: "output" 附加或前置普通块注释; 源映射指令和可执行添加拒绝。主机已存在 映射锚定并保留源内容。每个管线键包含上述内容 输出。功能模式结果携带 preamble 分开 code.

决定论,缓存和成本

声明每个捕获的配置或环境输入 cacheInputs,甚至 当列表为空时。的名字开始 @vize/ host-reserved。源, 文件名,原生构建,SDK运行时字节,插件版本/代码,静态需求, 访问和输入参与键。缓存的lint漏检总是审计两个 相同的批次。提供和转换审计失误。缓存的输出挂钩也总是审计; 默认情况下,非缓存输出挂钩审计。不同的验证输出在缓存之前拒绝。所有钩族 有有限的进程内缓存和选择加入吗 cacheDir 持久性。磁盘点击 在重用之前验证它们的模式、键和受主机限制的输出。

成本包括占用的主机工作时间和JavaScript调用时间,包括审计调用。 缓存命中不执行回调;它的 jsNs 批处理交叉字节为零。 确定性审计观察重复输出。可信回调可以隐藏 环境读取;他们的声明仍然是作者的责任。

隔离的回调源

import {
  createSandboxRunner,
  SANDBOX_IMAGE,
  SandboxRuntimeError,
} from "@vizejs/plugin-sdk/sandbox";
const isolated = createSandboxRunner(
  {
    name: "isolated-rule",
    version: "1",
    cacheInputs: [],
    configuration: { message: "Use our design system" },
    rules: { check: "(ctx, config) => { ctx.report(ctx.nodes[0], config.message); }" },
  },
  { timeoutMs: 5000, maxBytes: 1048576 },
);
native.lintWithPlugins(source, [isolated], { cache: true });

安装Docker,启动它的守护进程并拉出导出的pinned SANDBOX_IMAGE 之前使用。回调源代码和显式JSON配置跨stdin;主人 闭包和导入则不然。每次调用都使用一个非根的只读容器 没有主机挂载、主机环境、外部网络或功能,有 内存/ CPU / PID /文件描述符的限制。主机限制请求/输出字节和 执行时间,然后确认容器移除。运行时检查和清理 每次最多增加5秒 timeoutMs.

SandboxRuntimeError.code 区分 runtime_unavailable, execution_stopped, execution_failed 和 cleanup_failed。不可用的码头工人 或者缺失的图像拒绝执行;它永远不会将来宾作为受信任代码运行。 映像自己的文件系统仍然是可读的。Docker提供隔离; 此API不要求虚拟机隔离。

definePlugin 其他普通的帮助程序执行受信任的应用程序代码 在调用Node进程中同步执行,并且没有执行截止日期。 冻结批次和审计输出并不能隔离这些回调。测量 代理句柄保持峰值兼容性。 @vizejs/extension-sdk 是 单独版本的guest接口。

虚拟TypeScript访客

defineVisitorPlugin 描述符中只有 virtual-ts 能力可以是 为本机类型检查主机协商。普通的 typeCheck 入口点 仍然是plugin-free;呼叫者通过单独的访问者入口点选择加入。

import { typeCheckWithVirtualTsVisitors } from "@vizejs/native";
import {
  VISITOR_API_VERSION,
  createVirtualTsVisitorHost,
  defineVisitorPlugin,
} from "@vizejs/plugin-sdk/visitor";

const observer = defineVisitorPlugin({
  apiVersion: VISITOR_API_VERSION,
  name: "virtual-ts-observer",
  version: "1",
  capabilities: ["virtual-ts"],
  cacheInputs: [],
  visitors: {
    "virtual-ts"({ payload }) {
      console.log(payload.virtualFile, payload.code, payload.mappings);
    },
  },
});

typeCheckWithVirtualTsVisitors(source, [createVirtualTsVisitorHost(observer)], {
  filename: "src/App.vue",
});

回调接收不可变生成的代码和源/生成的UTF-8字节 在构建实际类型检查投影之后的范围。返回一个值, 请求其他功能或伪造不完整的主机标识拒绝 调用。

Devtools跟踪访问者

devtools-trace 描述符显式附加到请求本地 @vizejs/devtools 录音机。记录器序列化每个提交的跟踪事件 通过协商适配器;禁用的记录器不会调用已配置的 主机,而普通的录音机没有 visitorHosts 不要检查插件 描述符。

import { createDevtoolsTraceRecorder } from "@vizejs/devtools";
import {
  VISITOR_API_VERSION,
  createDevtoolsTraceVisitorHost,
  defineVisitorPlugin,
} from "@vizejs/plugin-sdk/visitor";

const observer = defineVisitorPlugin({
  apiVersion: VISITOR_API_VERSION,
  name: "trace-observer",
  version: "1",
  capabilities: ["devtools-trace"],
  cacheInputs: [],
  visitors: {
    "devtools-trace"({ file, payload }) {
      console.log(file, payload.events);
    },
  },
});

const trace = createDevtoolsTraceRecorder({
  sessionId: "request-1",
  visitorHosts: [createDevtoolsTraceVisitorHost(observer)],
});

每个交付的事件都有一个确定的会话/序列ID,这是派生的阶段 从其跟踪类型中,将毫秒时间戳标准化为纳秒,以及 其余记录器字段为不可变的 data。访问者异常或非void Result在记录进入快照之前拒绝该记录。

版本与发布记录

@vizejs/plugin-sdk 共发布 195 个版本,首次发布于 2026/09/27;过去 12 个月发布了 195 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.650.0latest2026/11/03今天
0.649.02026/11/03今天
0.648.02026/11/02今天
0.647.02026/11/02今天
0.646.02026/11/02今天
0.645.02026/11/021 天前

关于 @vizejs/plugin-sdk 的常见问题

@vizejs/plugin-sdk 是什么?

确定性编写和独立执行的Vize JavaScript插件

如何安装 @vizejs/plugin-sdk?

在项目目录运行 npm install @vizejs/plugin-sdk,或使用 pnpm add / yarn add / bun add。

@vizejs/plugin-sdk 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@vizejs/plugin-sdk 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@vizejs/plugin-sdk 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@vizejs/plugin-sdk 可以商用吗?

@vizejs/plugin-sdk 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@vizejs/plugin-sdk 还在维护吗?

最新版本 0.650.0 发布于 2026/11/03(今天);至今共发布 195 个版本,其中过去 12 个月发布了 195 个;首次发布于 2026/09/27。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。