diff --git a/README.md b/README.md index 0eec074c..b71231d1 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,10 @@ [![Apache 2.0 License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE) # ts-protoc-gen + > Protoc Plugin for generating TypeScript Declarations -This repository contains a [protoc](https://github.com/google/protobuf) plugin that generates TypeScript declarations +This repository contains a [protoc](https://github.com/google/protobuf) plugin that generates TypeScript declarations (`.d.ts` files) that match the JavaScript output of `protoc --js_out=import_style=commonjs,binary`. This plugin can also output service definitions as both `.js` and `.d.ts` files in the structure required by [grpc-web](https://github.com/improbable-eng/grpc-web). @@ -15,6 +16,7 @@ This plugin is tested and written using TypeScript 2.7. ## Installation ### npm + As a prerequisite, download or install `protoc` (the protocol buffer compiler) for your platform from the [github releases page](https://github.com/google/protobuf/releases) or via a package manager (ie: [brew](http://brewformulas.org/Protobuf), [apt](https://www.ubuntuupdates.org/pm/protobuf-compiler)). For the latest stable version of the ts-protoc-gen plugin: @@ -30,6 +32,7 @@ npm install ts-protoc-gen@next ``` ### bazel +
Instructions for using ts-protoc-gen within a bazel build environment

Include the following in your `WORKSPACE` - _Most of this setup is for @@ -97,7 +100,7 @@ Also make sure you have the following in your `package.json`: { "dependencies": { "google-protobuf": "^3.6.1", - "grpc-web-client": "0.7.0", + "@improbable-eng/grpc-web": "0.8.0", "browser-headers": "^0.4.1" }, "devDependencies": { @@ -130,20 +133,24 @@ typescript_proto_library( ``` You can use the `test_ts_proto` as a `dep` in other `ts_library` targets. However, you will need to -include `google-protobuf`, `grpc-web-client`, and `browser-headers` at runtime yourself. See +include `google-protobuf`, `@improbable-eng/grpc-web`, and `browser-headers` at runtime yourself. See `//test/bazel:pizza_service_proto_test_suite` for an example.

## Contributing + Contributions are welcome! Please refer to [CONTRIBUTING.md](https://github.com/improbable-eng/ts-protoc-gen/blob/master/CONTRIBUTING.md) for more information. ## Usage + As mentioned above, this plugin for `protoc` serves two purposes: + 1. Generating TypeScript Definitions for CommonJS modules generated by protoc 2. Generating gRPC Service Stubs for use with [grpc-web](https://github.com/improbable-eng/grpc-web). ### Generating TypeScript Definitions for CommonJS modules generated by protoc + By default, protoc will generate ES5 code when the `--js_out` flag is used (see [javascript compiler documentation](https://github.com/google/protobuf/tree/master/js)). You have the choice of two module syntaxes, [CommonJS](https://nodejs.org/docs/latest-v8.x/api/modules.html) or [closure](https://developers.google.com/closure/library/docs/tutorial). This plugin (`ts-protoc-gen`) can be used to generate Typescript definition files (`.d.ts`) to provide type hints for CommonJS modules only. To generate TypeScript definitions you must first configure `protoc` to use this plugin and then specify where you want the TypeScript definitions to be written to using the `--ts_out` flag. @@ -152,7 +159,7 @@ To generate TypeScript definitions you must first configure `protoc` to use this # Path to this plugin PROTOC_GEN_TS_PATH="./node_modules/.bin/protoc-gen-ts" -# Directory to write generated code to (.js and .d.ts files) +# Directory to write generated code to (.js and .d.ts files) OUT_DIR="./generated" protoc \ @@ -172,6 +179,7 @@ msg.setName("John Doe"); ``` ### Generating gRPC Service Stubs for use with grpc-web + [gRPC](https://grpc.io/) is a framework that enables client and server applications to communicate transparently, and makes it easier to build connected systems. [grpc-web](https://github.com/improbable-eng/grpc-web) is a comparability layer on both the server and client-side which allows gRPC to function natively in modern web-browsers. @@ -182,7 +190,7 @@ To generate client-side service stubs from your protobuf files you must configur # Path to this plugin, Note this must be an abolsute path on Windows (see #15) PROTOC_GEN_TS_PATH="./node_modules/.bin/protoc-gen-ts" -# Directory to write generated code to (.js and .d.ts files) +# Directory to write generated code to (.js and .d.ts files) OUT_DIR="./generated" protoc \ @@ -192,26 +200,33 @@ protoc \ users.proto base.proto ``` -The `generated` folder will now contain both `pb_service.js` and `pb_service.d.ts` files which you can reference in your TypeScript project to make RPCs. +The `generated` folder will now contain both `pb_service.js` and `pb_service.d.ts` files which you can reference in your TypeScript project to make RPCs. **Note** Note that these modules require a CommonJS environment. If you intend to consume these stubs in a browser environment you will need to use a module bundler such as [webpack](https://webpack.js.org/). **Note** Both `js` and `d.ts` service files will be generated regardless of whether there are service definitions in the proto files. ```js -import { UserServiceClient, GetUserRequest } from "../generated/users_pb_service" +import { + UserServiceClient, + GetUserRequest +} from "../generated/users_pb_service"; const client = new UserServiceClient("https://my.grpc/server"); const req = new GetUserRequest(); req.setUsername("johndoe"); -client.getUser(req, (err, user) => { /* ... */ }); +client.getUser(req, (err, user) => { + /* ... */ +}); ``` ## Examples + For a sample of the generated protos and service definitions, see [examples](https://github.com/improbable-eng/ts-protoc-gen/tree/master/examples). To generate the examples from protos, please run `./generate.sh` ## Gotchas + By default the google-protobuf library will use the JavaScript number type to store 64bit float and integer values; this can lead to overflow problems as you exceed JavaScript's `Number.MAX_VALUE`. To work around this, you should consider using the `jstype` annotation on any 64bit fields, ie: ```proto diff --git a/examples/generated/proto/examplecom/simple_service_pb_service.d.ts b/examples/generated/proto/examplecom/simple_service_pb_service.d.ts index a5f925fe..b086923d 100644 --- a/examples/generated/proto/examplecom/simple_service_pb_service.d.ts +++ b/examples/generated/proto/examplecom/simple_service_pb_service.d.ts @@ -4,7 +4,7 @@ import * as proto_examplecom_simple_service_pb from "../../proto/examplecom/simple_service_pb"; import * as proto_othercom_external_child_message_pb from "../../proto/othercom/external_child_message_pb"; import * as google_protobuf_empty_pb from "google-protobuf/google/protobuf/empty_pb"; -import {grpc} from "grpc-web-client"; +import {grpc} from "@improbable-eng/grpc-web"; type SimpleServiceDoUnary = { readonly methodName: string; diff --git a/examples/generated/proto/examplecom/simple_service_pb_service.js b/examples/generated/proto/examplecom/simple_service_pb_service.js index 4cfbff7a..96dee997 100644 --- a/examples/generated/proto/examplecom/simple_service_pb_service.js +++ b/examples/generated/proto/examplecom/simple_service_pb_service.js @@ -4,7 +4,7 @@ var proto_examplecom_simple_service_pb = require("../../proto/examplecom/simple_service_pb"); var proto_othercom_external_child_message_pb = require("../../proto/othercom/external_child_message_pb"); var google_protobuf_empty_pb = require("google-protobuf/google/protobuf/empty_pb"); -var grpc = require("grpc-web-client").grpc; +var grpc = require("@improbable-eng/grpc-web").grpc; var SimpleService = (function () { function SimpleService() {} diff --git a/examples/generated/proto/orphan_pb_service.d.ts b/examples/generated/proto/orphan_pb_service.d.ts index 83da29bd..a47dc79e 100644 --- a/examples/generated/proto/orphan_pb_service.d.ts +++ b/examples/generated/proto/orphan_pb_service.d.ts @@ -2,7 +2,7 @@ // file: proto/orphan.proto import * as proto_orphan_pb from "../proto/orphan_pb"; -import {grpc} from "grpc-web-client"; +import {grpc} from "@improbable-eng/grpc-web"; type OrphanServiceDoUnary = { readonly methodName: string; diff --git a/examples/generated/proto/orphan_pb_service.js b/examples/generated/proto/orphan_pb_service.js index d9594ffb..61573103 100644 --- a/examples/generated/proto/orphan_pb_service.js +++ b/examples/generated/proto/orphan_pb_service.js @@ -2,7 +2,7 @@ // file: proto/orphan.proto var proto_orphan_pb = require("../proto/orphan_pb"); -var grpc = require("grpc-web-client").grpc; +var grpc = require("@improbable-eng/grpc-web").grpc; var OrphanService = (function () { function OrphanService() {} diff --git a/package-lock.json b/package-lock.json index 28611a8a..94a8939c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,6 +101,15 @@ } } }, + "@improbable-eng/grpc-web": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.8.0.tgz", + "integrity": "sha512-0K9owV6BGGGVNkGXifsnMAE0Xoy675qqMdr8id4FOILbwxLk9HsJtZKz/zxfRXev1YY9JcAHm4vpZmbr6O+lyw==", + "dev": true, + "requires": { + "browser-headers": "0.4.1" + } + }, "@types/chai": { "version": "3.5.2", "resolved": "https://registry.npmjs.org/@types/chai/-/chai-3.5.2.tgz", @@ -2479,15 +2488,6 @@ "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", "dev": true }, - "grpc-web-client": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/grpc-web-client/-/grpc-web-client-0.7.0.tgz", - "integrity": "sha512-tydslNg6pPHi61aMs0HoaETTtyDR5TQyDZ0AQhbbURpOK2NW8IMrUGs/i1UMkS0H64Vj7PuggSAhDohP41yubQ==", - "dev": true, - "requires": { - "browser-headers": "0.4.1" - } - }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", diff --git a/package.json b/package.json index 4030678e..ce5d24ca 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "devDependencies": { "@bazel/karma": "0.21.0", "@bazel/typescript": "0.21.0", + "@improbable-eng/grpc-web": "^0.8.0", "@types/chai": "^3.5.2", "@types/google-protobuf": "^3.2.7", "@types/jasmine": "^2.8.9", @@ -42,7 +43,6 @@ "browser-headers": "^0.4.1", "chai": "^3.5.0", "google-protobuf": "^3.6.1", - "grpc-web-client": "^0.7.0", "lodash": "^4.17.5", "lodash.isequal": "^4.5.0", "mocha": "^5.2.0", diff --git a/src/service/grpcweb.ts b/src/service/grpcweb.ts index bb7a58fe..54ea0e56 100644 --- a/src/service/grpcweb.ts +++ b/src/service/grpcweb.ts @@ -171,7 +171,7 @@ function generateTypescriptDefinition(fileDescriptor: FileDescriptorProto, expor .forEach(importDescriptor => { printer.printLn(`import * as ${importDescriptor.namespace} from "${importDescriptor.path}";`); }); - printer.printLn(`import {grpc} from "grpc-web-client";`); + printer.printLn(`import {grpc} from "@improbable-eng/grpc-web";`); printer.printEmptyLn(); // Services. @@ -231,7 +231,7 @@ function generateTypescriptDefinition(fileDescriptor: FileDescriptorProto, expor printer.printLn(`}`); printer.printEmptyLn(); - // Add a client stub that talks with the grpc-web-client library + // Add a client stub that talks with the @improbable-eng/grpc-web library serviceDescriptor.services .forEach(service => { printServiceStubTypes(printer, service); @@ -259,7 +259,7 @@ function generateJavaScript(fileDescriptor: FileDescriptorProto, exportMap: Expo .forEach(importDescriptor => { printer.printLn(`var ${importDescriptor.namespace} = require("${importDescriptor.path}");`); }); - printer.printLn(`var grpc = require("grpc-web-client").grpc;`); + printer.printLn(`var grpc = require("@improbable-eng/grpc-web").grpc;`); printer.printEmptyLn(); // Services. @@ -287,7 +287,7 @@ function generateJavaScript(fileDescriptor: FileDescriptorProto, exportMap: Expo printer.printLn(`exports.${service.name} = ${service.name};`); printer.printEmptyLn(); - // Add a client stub that talks with the grpc-web-client library + // Add a client stub that talks with the @improbable-eng/grpc-web library printServiceStub(printer, service); printer.printEmptyLn(); diff --git a/test/bazel/BUILD.bazel b/test/bazel/BUILD.bazel index 9fc94a27..bed05e4e 100644 --- a/test/bazel/BUILD.bazel +++ b/test/bazel/BUILD.bazel @@ -61,7 +61,7 @@ ts_web_test_suite( ], # Files are served under /base// static_files = [ - "@npm//node_modules/grpc-web-client:dist/grpc-web-client.umd.js", + "@npm//node_modules/@improbable-eng/grpc-web:dist/@improbable-eng/grpc-web.umd.js", "@npm//node_modules/browser-headers:dist/browser-headers.umd.js", ], deps = [ diff --git a/test/bazel/require.config.js b/test/bazel/require.config.js index 6b40c01c..a3311778 100644 --- a/test/bazel/require.config.js +++ b/test/bazel/require.config.js @@ -1,6 +1,8 @@ require.config({ paths: { - 'grpc-web-client': 'base/npm/node_modules/grpc-web-client/dist/grpc-web-client.umd', - 'browser-headers': 'base/npm/node_modules/browser-headers/dist/browser-headers.umd', + "@improbable-eng/grpc-web": + "base/npm/node_modules/@improbable-eng/grpc-web/dist/@improbable-eng/grpc-web.umd", + "browser-headers": + "base/npm/node_modules/browser-headers/dist/browser-headers.umd" } }); diff --git a/test/helpers/fakeGrpcTransport.ts b/test/helpers/fakeGrpcTransport.ts index fb541ea2..43d6f3f8 100644 --- a/test/helpers/fakeGrpcTransport.ts +++ b/test/helpers/fakeGrpcTransport.ts @@ -1,5 +1,5 @@ import { Message } from "google-protobuf"; -import { grpc } from "grpc-web-client"; +import { grpc } from "@improbable-eng/grpc-web"; import * as _ from "lodash"; function frameResponse(request: Message): Uint8Array { diff --git a/test/integration/service/grpcweb.ts b/test/integration/service/grpcweb.ts index 2bad3a6f..a1dc854b 100644 --- a/test/integration/service/grpcweb.ts +++ b/test/integration/service/grpcweb.ts @@ -1,7 +1,7 @@ import { resolve } from "path"; import { readFileSync, existsSync } from "fs"; import { assert } from "chai"; -import { grpc } from "grpc-web-client"; +import { grpc } from "@improbable-eng/grpc-web"; import { createContext, runInContext } from "vm"; import { frameRequest, StubTransportBuilder } from "../../helpers/fakeGrpcTransport"; diff --git a/yarn.lock b/yarn.lock index 6aefae7a..19e1a3a7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,6 +27,13 @@ source-map-support "0.5.9" tsutils "2.27.2" +"@improbable-eng/grpc-web@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@improbable-eng/grpc-web/-/grpc-web-0.8.0.tgz#c7a9a23560c6667f75cf0e69d5a672aa026683d4" + integrity sha512-0K9owV6BGGGVNkGXifsnMAE0Xoy675qqMdr8id4FOILbwxLk9HsJtZKz/zxfRXev1YY9JcAHm4vpZmbr6O+lyw== + dependencies: + browser-headers "^0.4.0" + "@types/chai@^3.5.2": version "3.5.2" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e" @@ -1286,12 +1293,6 @@ growl@1.10.5: version "1.10.5" resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" -grpc-web-client@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/grpc-web-client/-/grpc-web-client-0.7.0.tgz#db19d331ad1fec49ed56744031340ee6af8529b9" - dependencies: - browser-headers "^0.4.0" - har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"