Skip to content

Commit

Permalink
Docs: Improved pbjs/pbts examples, better covers reflection with defi…
Browse files Browse the repository at this point in the history
…nitions for static modules
  • Loading branch information
dcodeIO committed Jan 19, 2017
1 parent 6f0b44a commit 28ddf75
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 18 deletions.
52 changes: 37 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<a href="https://coveralls.io/github/dcodeIO/protobuf.js"><img src="https://coveralls.io/repos/github/dcodeIO/protobuf.js/badge.svg?branch=master" alt=""></a>
<a href="https://npmjs.org/package/protobufjs"><img src="https://img.shields.io/npm/v/protobufjs.svg" alt=""></a>
<a href="https://npmjs.org/package/protobufjs"><img src="https://img.shields.io/npm/dm/protobufjs.svg" alt=""></a>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=dcode%40dcode.io&item_name=Open%20Source%20Software%20Contribution&item_number=dcodeIO%2Fprotobuf.js"><img alt="donate ❤" src="https://img.shields.io/badge/donate-❤-ff2244.svg"></a>
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=dcode%40dcode.io&item_name=Open%20Source%20Software%20Donation&item_number=dcodeIO%2Fprotobuf.js"><img alt="donate ❤" src="https://img.shields.io/badge/donate-❤-ff2244.svg"></a>
</p>

**Protocol Buffers** are a language-neutral, platform-neutral, extensible way of serializing structured data for use in communications protocols, data storage, and more, originally designed at Google ([see](https://developers.google.com/protocol-buffers/)).
Expand Down Expand Up @@ -302,6 +302,14 @@ protobuf.load("bundle.json", function(err, root) {
});
```

As you might have noticed, `pbjs` is also capable of generating static code. For example

```
$> pbjs -t static-module -w commonjs -o compiled.js file1.proto file2.proto
```

will generate static code for definitions within `file1.proto` and `file2.proto` to a CommonJS module `compiled.js`, which then can be used with just the [minimal runtime](https://github.com/dcodeIO/protobuf.js/tree/master/dist/runtime).

**ProTip!** Documenting your .proto files with `/** ... */`-blocks or (trailing) `/// ...` lines translates to generated static code.

### Generating TypeScript definitions from static modules
Expand All @@ -324,6 +332,34 @@ Generates TypeScript definitions from annotated JavaScript files.
usage: pbts [options] file1.js file2.js ... (or) other | pbts [options] -
```

Picking up on the example above, the following not just generates static code to a CommonJS module `compiled.js` but also its respective TypeScript definitions to `compiled.d.ts`:

```
$> pbjs -t static-module -w commonjs -o compiled.js file1.proto file2.proto
$> pbts -o compiled.d.ts compiled.js
```

Additionally, TypeScript definitions of static modules are compatible with reflection, as long as the following conditions are met:

1. Use `SomeMessage.create(...)` instead of `new SomeMessage(...)` because reflection objects do not provide a constructor.
2. Types, services and enums must start with an uppercase letter to become available as properties of the reflected types as well (i.e. to be able to use `MyMessage.MyEnum` instead of `root.lookup("MyMessage.MyEnum")`).
3. When using a TypeScript definition with custom code, `resolveAll()` must be called once on the root instance to populate these additional properties (JSON modules do this automatically).

For example, the following generates a `bundle.json` and a `bundle.d.ts`, but no static code:

```
$> pbjs -t json-module -w commonjs -o bundle.json file1.proto file2.proto
$> pbjs -t static-module file1.proto file2.proto | pbts -o bundle.d.ts -
```

### On reflection vs. static code

While using .proto files requires the [full library](https://github.com/dcodeIO/protobuf.js/tree/master/dist) (about 18.5kb gzipped) or JSON just the [noparse library](https://github.com/dcodeIO/protobuf.js/tree/master/dist/noparse) (about 15.5kb gzipped), pretty much all code but the relatively short descriptors is shared and all features including reflection and the parser are available.

Static code, on the other hand, requires just the [minimal runtime](https://github.com/dcodeIO/protobuf.js/tree/master/dist/runtime) (about 5.5kb gzipped), but generates additional, albeit editable, source code without any reflection features.

There is no significant difference performance-wise as the code generated statically is pretty much the same as generated at runtime and both are largely interchangeable as seen in the previous section.

### Using pbjs and pbts programmatically

Both utilities can be used programmatically by providing command line arguments and a callback to their respective `main` functions:
Expand All @@ -338,20 +374,6 @@ pbjs.main([ "--target", "json-module", "path/to/myproto.proto" ], function(err,
});
```

### Descriptors vs. static modules

While .proto and JSON files require the full library (about 18.5kb gzipped), pretty much all code but the relatively short descriptors is shared and all features including reflection and the parser are available.

Static code, on the other hand, requires just the minimal runtime (about 5.5kb gzipped), but generates additional, albeit editable, source code without any reflection features.

There is no difference performance-wise as the code generated statically is pretty much the same as generated at runtime.

Additionally, JSON modules can be used with TypeScript definitions generated for their static counterparts as long as the following conditions are met:

1. Use `SomeMessage.create(...)` instead of `new SomeMessage(...)` (reflection does not provide such a constructor).
2. Types, services and enums must start with an uppercase letter to become available as properties of the reflected types as well.
3. When using a TypeScript definition with custom code, `resolveAll()` must be called once on the root instance to populate these additional properties (JSON modules do this automatically).

Performance
-----------
The package includes a benchmark that tries to compare performance to native JSON as far as this is possible. On an i7-2600K running node 6.9.1 it yields:
Expand Down
3 changes: 1 addition & 2 deletions cli/targets/static.js
Original file line number Diff line number Diff line change
Expand Up @@ -223,9 +223,8 @@ function buildFunction(type, functionName, gen, scope) {
delete scope[key];
});

// enclose all but the first and last line in an iife returning our properly scoped function
var lines = code.split(/\n/g);
if (hasScope)
if (hasScope) // enclose in an iife
push(name(type.name) + "." + functionName + " = (function(" + Object.keys(scope).join(", ") + ") { return " + lines[0]);
else
push(name(type.name) + "." + functionName + " = " + lines[0]);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "protobufjs",
"version": "6.5.3",
"version": "6.5.4",
"versionScheme": "~",
"description": "Protocol Buffers for JavaScript (& TypeScript).",
"author": "Daniel Wirtz <dcode+protobufjs@dcode.io>",
Expand Down

0 comments on commit 28ddf75

Please sign in to comment.