Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expanded documentation for TypeScript 😈 #666

Closed
atrauzzi opened this issue Jan 28, 2017 · 9 comments
Closed

Expanded documentation for TypeScript 😈 #666

atrauzzi opened this issue Jan 28, 2017 · 9 comments

Comments

@atrauzzi
Copy link

protobuf.js version: 6.6.2

This is more of a documentation issue.. The documentation in README.md doesn't really give me a working understanding of what my workflows need to be with this library.

If I'm authoring code in TypeScript and wish to make use of this library, what do I have to set up and what commands or proto files do I have to leverage to get everything to a point where I can go back to using domain classes?

Again, it's a documentation thing, but if I'm not entirely clear on what I have to do, what generated code I need, where to put it or how to leverage it, perhaps I'm not alone? :)

@atrauzzi atrauzzi changed the title Expanded documentation for TypeScript Expanded documentation for TypeScript 😈 Jan 28, 2017
@dcodeIO
Copy link
Member

dcodeIO commented Jan 28, 2017

Copying the slightly modified TypeScript paragraph here so we can work on it:


Usage with TypeScript

The library ships with its own type definitions and modern editors like Visual Studio Code should automatically detect and use them for code completion when following this pattern:

// node.js
import * as protobuf from "protobufjs";
import * as Long from "long"; // optional

// browser only (alternatively)
import * as protobuf from "./node_modules/protobufjs/index.js";
import * as Long from "./node_modules/long/dist/long.js"; // optional

// example code
protobuf.load("awesome.proto", function(err, root) {
  if (err)
    throw err;

  var AwesomeMessage = root.lookupType("AwesomeMessage");
  var message = AwesomeMessage.create({ awesomeField: "hello" });
  var buffer = AwesomeMessage.encode(message).finish();
  ...
});

To achieve the same with static code generated by pbjs, there is the pbts command line utility to generate type definitions from static code as well.

Let's say you generated your static code to bundle.js and its type definitions to bundle.d.ts, then you can do:

import * as root from "./bundle.js";

// example code
var AwesomeMessage = root.AwesomeMessage;
var message = AwesomeMessage.create({ awesomeField: "hello" });
var buffer = AwesomeMessage.encode(message).finish();
...

@dcodeIO
Copy link
Member

dcodeIO commented Jan 28, 2017

Let me know if this leaves any open questions.

@atrauzzi
Copy link
Author

@dcodeIO - Awesome, yeah -- so let's see if I can get all of this out in one go. Sometimes it's tough to know all problems in advance ;)

  • Is there a way to generate code to a single file per message type? My thought there is that I'm trying to leverage protocol buffers for serialization of my domain models but would still like to be able to have behaviour in the types.
  • As a followup to that, if I deserialize data with protobufjs, will I get instances of my models, or just JS objects that match the .d.ts file(s)?
  • Alternatively, Is there any way to use this library by having protobufjs attach/wrap my types without having to use generated code or extend a type?

Apologies for the "Hi I'm new here"-ness of my questions. Once I know the right way to use this library, things will click.

@dcodeIO
Copy link
Member

dcodeIO commented Jan 28, 2017

Is there a way to generate code to a single file per message type?

Not yet, unfortunately. Some day.

if I deserialize data with protobufjs, will I get instances of my models

Is there any way to use this library by having protobufjs attach/wrap my types without having to use generated code or extend a type

With reflection, you'll get runtime message instances, and you can replace the respective class with your own containing any custom functionality.

dcodeIO added a commit that referenced this issue Jan 28, 2017
@atrauzzi
Copy link
Author

atrauzzi commented Jan 29, 2017

Great, I think this gives me a loose idea of what I can do right away, with some decent wishlist candidates.

Last round of questions (I think):

  • For generated code, any best practices or suggestions on how to manage it cleanly?
    • If I'm working in a TS project, where should I put my generated .js files and the corresponding .d.ts?
    • What's your take on committing the generated code to source control? Normally I don't like to put anything that isn't authored by a person in source control, but I don't know if this qualifies as an exception given that my actual domain classes will be depending on them.

Only remaining thing might be to add points to address some of my "expectations" here in the documentation. It's all quite applied knowledge, but is the kind of stuff people will need to hunt down before they'll feel like they're up and running.

Thanks so much for this library and your help!

@dcodeIO
Copy link
Member

dcodeIO commented Jan 29, 2017

Well, that's completely up to you, but that's what I'd do:

If I'm working in a TS project, where should I put my generated .js files and the corresponding .d.ts?

  • Single bundle containing all the definitions? Put it next to the code relying on it.
  • Multiple bundles? Put everything in a protobuf folder.

What's your take on committing the generated code to source control?

  • Generated static code which is manually edited? Put it in source control, of course.
  • Generated static code which is not manually edited? Use a JSON module with a d.ts generated for the static counterpart instead (see: pbts, scroll down to "TypeScript definitions of static modules are compatible with reflection"), because JSON is pretty much conflict free when it comes to linters etc. and can be easily extended with additional fields or even types manually without re-generating anything. (simple JSON example).

@atrauzzi
Copy link
Author

atrauzzi commented Jan 30, 2017

I'm not sure I follow how "reflection" is being used in this specific scenario. Normally I understand it to be when you query and modify the type system at runtime - which JS/TS lack. What I'm seeing here is a fluent API to build metadata, as an alternative to JSON or protobuf files.

One or more of what you've described so far might be what I'm after here, but I'm having a tough time aligning it to my understanding or picking out the correct approaches.

So let's take a new scenario: Assume I don't want to use generated code, I have a bunch of models I've created in TS. Is there a way to load the metadata (whether through the fluent API, protobuf or JSON) and then use protobufjs as an infrastructure-service in my application to perform serialization and deserialization?

@dcodeIO
Copy link
Member

dcodeIO commented Jan 30, 2017

I've added additional information on reflection-based and code-based use cases to the README.

Basically, everything what's not static code is reflection based.

So let's take a new scenario: Assume I don't want to use generated code, I have a bunch of models I've created in TS. Is there a way to load the metadata (whether through the fluent API, protobuf or JSON) and then use protobufjs as an infrastructure-service in my application to perform serialization and deserialization?

You could load a JSON descriptor / pbjs-generated JSON module, and then register your custom classes with the respective types. Let's say you have a class MyType, referencing the reflected type .com.something.MyType, then you'd do:

protobuf.Class.create(root.lookupType(".com.something.MyType"), MyType);

From then on, deserialized messages of that type are instanceof MyType. When MyType extends protobuf.Message, you should also have proper type information for the mixed in encode, decode etc. methods.

@atrauzzi
Copy link
Author

atrauzzi commented Jan 30, 2017

Alright! Looks like I've got things more or less exactly how I'd like! The settings es6 combined with json-module for pbjs were exactly what I was after. I pass in the proto files, it generates everything for me and I can infrastructure-it all in where necessary.

What an amazing job you've done here.

I've got one minor suggestion to appease my linter which I'll open as another ticket. I don't know if you'd like to ask me any specific questions to help with further improving the documentation. But otherwise, feel free to close!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants