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

protobuf-fastdsl

v0.1.9

Published

将 TypeScript 接口在构建时编译为**完全内联**、零依赖的 protobuf 编解码函数。

Readme

protobuf-fastdsl

将 TypeScript 接口在构建时编译为完全内联、零依赖的 protobuf 编解码函数。

.proto 文件。无运行时库。无函数调用开销。只需 TypeScript 接口 → 确定化的二进制编解码代码。

特性

  • 零运行时 — 所有 wire-format 逻辑在编译时内联
  • TypeScript 原生 — 用 pb<N, Type> 标记接口字段即可定义 schema
  • 跨文件类型 — 支持 import type / import 引用其他文件的接口定义
  • 泛型单态化Wrapper<Wrapper<string>> → 自动生成具体编解码函数
  • 重复字段pb_repeated<N, Type> 编译为 Type[]
  • 编译期预计算 Tag — 字段标签在编译时折叠为字面量字节
  • 安全的 Fallback — 未经插件转换时运行会直接抛错,不会静默产生错误结果

安装

npm install protobuf-fastdsl

快速开始

1. 配置构建工具插件:

// vite.config.ts
import protobufPlugin from 'protobuf-fastdsl/vite';

export default defineConfig({
  plugins: [protobufPlugin()],
});

可选地,你可以开启 runtime map 产物(默认关闭):

import protobufPlugin from 'protobuf-fastdsl/vite';

export default defineConfig({
  plugins: [
    protobufPlugin({
      runtimeMap: {
        enabled: true,
        fileName: 'protobuf-fastdsl.runtime-map.json',
      },
    }),
  ],
});

2. 定义 protobuf schema(TypeScript 接口):

// schema/user.ts
import type { pb, pb_repeated, uint_32, bool } from 'protobuf-fastdsl';

export interface UserProfile {
  id:       pb<1, uint_32>;
  username: pb<2, string>;
  active:   pb<3, bool>;
  tags:     pb_repeated<4, string>;
}

3. 编解码:

import { protobuf_encode, protobuf_decode } from 'protobuf-fastdsl';
import type { UserProfile } from './schema/user';

const bytes = protobuf_encode<UserProfile>({
  id: 42,
  username: 'alice',
  active: true,
  tags: ['admin', 'dev'],
});

const user = protobuf_decode<UserProfile>(bytes);
// user.id === 42, user.tags === ['admin', 'dev']

构建时,插件将上述代码转换为:

// 预计算的 tag 字面量,内联 varint 循环,零函数调用
const bytes = protobuf_encode_UserProfile({ id: 42, ... });
const user = protobuf_decode_UserProfile(bytes);

如果忘记配置插件,protobuf_encode / protobuf_decode 会在运行时抛出错误提示。

如果你在构建阶段启用了 runtimeMap,也可以在非 Vite 运行场景下显式启用 map 回退(默认关闭):

import runtimeMap from './protobuf-fastdsl.runtime-map.json';
import { protobuf_enableRuntimeMapFallback } from 'protobuf-fastdsl';

protobuf_enableRuntimeMapFallback(runtimeMap);

该回退模式会根据调用栈命中 call-site map,再按需动态生成对应类型及其依赖消息的编解码函数。

跨文件类型引用

接口定义和编解码调用可以在不同文件中,插件会自动跟踪 import 链:

// inner.ts
import type { pb, uint_32 } from 'protobuf-fastdsl';

export interface Inner {
  value: pb<1, uint_32>;
}

// outer.ts
import { protobuf_encode } from 'protobuf-fastdsl';
import type { Inner } from './inner';
import type { pb } from 'protobuf-fastdsl';

interface Outer {
  inner: pb<1, Inner>;
}

const bytes = protobuf_encode<Outer>({ inner: { value: 42 } });

支持传递性导入(A → B → C),插件会递归解析所有依赖。

别名导入

import { protobuf_encode as encode, protobuf_decode as decode } from 'protobuf-fastdsl';

const bytes = encode<UserProfile>(data);  // → protobuf_encode_UserProfile(data)
const user = decode<UserProfile>(bytes);  // → protobuf_decode_UserProfile(bytes)

也支持 namespace 形式:

import * as pb from 'protobuf-fastdsl';

const bytes = pb.protobuf_encode<UserProfile>(data);
const user = pb.protobuf_decode<UserProfile>(bytes);

泛型单态化

定义泛型 protobuf 模板,使用具体类型实例化:

interface Wrapper<T> {
  value?: pb<1, T>;
}

// 插件自动生成以下具体类型的编解码函数:
//   Wrapper__string  和  Wrapper__Wrapper__string
const data = protobuf_encode<Wrapper<Wrapper<string>>>({
  value: { value: 'hello' },
});

支持的类型

| Protobuf 类型 | TypeScript 类型 | Wire 类型 | |---------------|-----------------|-----------| | uint_32, int_32 | number | Varint | | uint_64, int_64 | bigint | Varint | | sint_32 | number | Varint (ZigZag) | | sint_64 | bigint | Varint (ZigZag) | | bool | boolean | Varint | | string | string | LengthDelimited | | bytes | Uint8Array | LengthDelimited | | float, fixed_32, sfixed_32 | number | 32-bit | | double | number | 64-bit | | fixed_64, sfixed_64 | bigint | 64-bit | | 嵌套消息 | interface | LengthDelimited |

字段标记:

  • pb<fieldNumber, Type> — 单值字段
  • pb_repeated<fieldNumber, Type> — 重复字段(→ Type[]

说明:

  • 所有 64 位整数类型在 TypeScript 中统一映射为 bigint
  • sint_32 / sint_64 使用 ZigZag 编码,适用于频繁出现负数的场景

包入口

| 路径 | 用途 | |------|------| | protobuf-fastdsl | 用户代码 — protobuf_encodeprotobuf_decode、所有类型 | | protobuf-fastdsl/vite | Vite 插件 |

⚡ 性能测试

benchmark 的 .proto 定义位于 bench/proto/bench.proto,生成入口是 npm run bench:gen。脚本会先校验所有实现产出的 wire bytes 完全一致,再统计绝对吞吐率。下表统一以 protobuf-fastdsl = 1x 为基线,其他实现显示相对它慢了多少。

参与对比的实现:

  • protobuf-ts(protoc)@protobuf-ts/plugin + protoc 生成代码
  • protobuf-ts — 手写 MessageType 反射运行时
  • protobufjs(static)pbjs static-module 从同一份 .proto 生成代码
  • protobufjs — 反射 API
  • protobufgoogle-protobuf + protoc-gen-js 生成代码

Node v22.11.0 | Windows x64 | 每项测试 50 万次迭代

编码性能(ops/sec — 越高越好)

| 消息类型 | protobuf-fastdsl | protobuf-ts(protoc) | protobuf-ts | protobufjs(static) | protobufjs | protobuf | |---------|:-----------:|:-------------------:|:-----------:|:------------------:|:----------:|:--------:| | 简单消息(1 个字段) | 35,782,016 (1x) | 8,238,128 (4.34x slower) | 5,828,158 (6.14x slower) | 16,466,923 (2.17x slower) | 16,819,500 (2.13x slower) | 5,794,260 (6.18x slower) | | 多字段消息(3 个字段) | 11,361,700 (1x) | 1,767,940 (6.43x slower) | 1,394,561 (8.15x slower) | 4,481,491 (2.54x slower) | 4,240,911 (2.68x slower) | 1,609,704 (7.06x slower) | | 嵌套消息 | 21,264,923 (1x) | 2,815,065 (7.55x slower) | 2,019,035 (10.53x slower) | 10,287,198 (2.07x slower) | 9,902,049 (2.15x slower) | 2,365,296 (8.99x slower) |

解码性能(ops/sec — 越高越好)

| 消息类型 | protobuf-fastdsl | protobuf-ts(protoc) | protobuf-ts | protobufjs(static) | protobufjs | protobuf | |---------|:-----------:|:-------------------:|:-----------:|:------------------:|:----------:|:--------:| | 简单消息(1 个字段) | 99,577,790 (1x) | 7,586,436 (13.13x slower) | 9,032,575 (11.02x slower) | 27,215,772 (3.66x slower) | 19,002,736 (5.24x slower) | 11,497,372 (8.66x slower) | | 多字段消息(3 个字段) | 10,190,107 (1x) | 3,891,478 (2.62x slower) | 3,219,789 (3.16x slower) | 5,141,816 (1.98x slower) | 4,893,718 (2.08x slower) | 3,606,205 (2.83x slower) | | 嵌套消息 | 51,491,185 (1x) | 8,376,444 (6.15x slower) | 6,033,801 (8.53x slower) | 11,922,077 (4.32x slower) | 13,326,794 (3.86x slower) | 3,148,311 (16.36x slower) |

许可证

MIT