protobuf.js

repository·master·Indexed 27 days ago

https://github.com/protobufjs/protobuf.js

A high-performance JavaScript implementation of Protocol Buffers for Node.js and browsers. It supports runtime reflection, .proto file loading without protoc, and specialized code generation with TypeScript support. The library includes tools for encoding/decoding messages, converting between message instances and plain objects, and a CLI (protobufjs-cli) for generating static code, reflection bundles, and TypeScript definitions via pbjs and pbts.

Tokens
11.4K
Snippets
24
Records
88
Agent score
89%

What's inside protobufjs

  1. Use protobufjs as a protoc plugin

    master

    If you use protoc, you can use protoc-gen-pbjs as an aggregate generator. Each invocation writes one JavaScript module and (if dts is specified) one matching declaration file.

    By default, it emits index.js with target=static-module and wrap=esm. You can customize this using --pbjs_opt.

    Customization via --pbjs_opt:

    • file=PATH: Choose the aggregate output file.
    • target=json-module: Use JSON module.
    • wrap=commonjs: Use CommonJS output.
    • keep-case: Preserve descriptor field names.
    protoc \
      --plugin=protoc-gen-pbjs=./node_modules/.bin/protoc-gen-pbjs \
      --pbjs_out=gen \
      --pbjs_opt=dts \
      proto/awesome.proto
  2. Load a .proto schema

    master

    You can load a .proto file at runtime using protobuf.load(). This returns a Root object which you can use to look up specific message types.

    Note: By default, protobuf.js converts .proto field names to camelCase. To preserve the exact field names from your .proto file, use the keepCase option when loading.

    const protobuf = require("protobufjs");
    
    const root = await protobuf.load("awesome.proto");
    const AwesomeMessage = root.lookupType("awesomepackage.AwesomeMessage");
  3. Convert messages to and from plain objects

    master

    Use fromObject and toObject to handle the boundary between Protobuf message instances and standard JavaScript objects. This is useful for handling types like Enums, 64-bit integers, and Base64 bytes.

    • fromObject(object): Converts a broad JavaScript object into a formal message instance.
    • toObject(message, options): Converts a message instance into a plain object using specific ConversionOptions.
    const message = AwesomeMessage.fromObject({ awesomeField: 42 });
    const object = AwesomeMessage.toObject(message, {
      longs: String,
      enums: String,
      bytes: String
    });
  4. Encode and decode Protobuf messages

    master

    To convert data to binary and back, use the encode and decode methods on the message type.

    • encode(message): Expects a message instance or a plain object. It returns a Writer which must be finalized with .finish() to get the buffer.
    • decode(buffer): Decodes binary data into a message instance.
    • create(payload): Useful for creating a message instance from a plain object before encoding.
    • verify(object): Validates if a plain object matches the schema. Returns null if valid, or an error string if invalid.
    const payload = { awesomeField: "hello" };
    
    // Optionally create a message instance from already valid data
    const message = AwesomeMessage.create(payload);
    
    const encoded = AwesomeMessage.encode(message).finish();
    const decoded = AwesomeMessage.decode(encoded);
  5. Install protobufjs

    master

    To use protobuf.js in your project, install the main package via npm:

    npm install protobufjs

    If you need the command line utility for generating reflection bundles, static code, or TypeScript declarations, install the protobufjs-cli add-on as a dev dependency:

    npm install --save-dev protobufjs-cli
  6. Generate Reflection Bundles

    master

    Reflection bundles store schemas as JSON metadata, avoiding the need to parse .proto files at runtime. This allows browsers to load schema metadata in a single request.

    • JSON bundle (-t json): Requires protobufjs/light.js. Best for loading schemas via protobuf.Root.fromJSON(bundle).
    • JSON module (-t json-module): Requires protobufjs/light.js. Exports the reflection root and, with -w esm, provides top-level named exports. Note: Message instances should be created using MyMessage.create(...) rather than constructors.
  7. Install the protobufjs-cli package

    master
    As of version 1.0.0, the command line tools have been moved from the main protobufjs repository to a dedicated package named protobufjs-cli. If you were previously using the CLI bundled with protobufjs, you must now install protobufjs-cli separately.
  8. Generate Static JavaScript Modules

    master

    Use protobufjs-cli to generate static, reflection-free JavaScript code. Static modules are optimized for performance and work in CSP-restricted environments because they do not require unsafe-eval. They only require protobufjs/minimal.js at runtime. You can specify the module format using the -w (or --wrap) flag (e.g., esm, commonjs, amd, closure).

    npx pbjs -t static-module -w esm -o awesome.js --dts awesome.proto
  9. Use pre-parsed Google type definitions

    master
    The google/ directory contains stripped and pre-parsed definitions of common Google types. While protobuf.js does not use these files internally, they are provided so that developers can manually include or use them in their own schemas or projects when working with standard Google Protobuf types.
  10. Use TypeScript with protobuf.js

    master

    protobuf.js provides built-in TypeScript support. The runtime API is typed, and you can generate matching .d.ts declarations during code generation using the --dts flag.

    For oneof fields, the generated declarations provide type narrowing. You can also use the $[TypeName].$Shape type for plain-object inputs to ensure they match the expected schema shape.

    // Example of type-safe oneof usage
    const profile = Profile.create({
      contact: "email",
      email: "hello@example.com"
    });
    
    if (profile.contact === "email") {
      profile.email; // string
    }
    
    // Using the $Shape type for plain objects
    const object: Profile.$Shape = {
      contact: "email",
      email: "hello@example.com"
    };