grpc / grpc-web

gRPC for Web Clients
https://grpc.io
Apache License 2.0
8.51k stars 766 forks source link

grpc-web not working in a Vite+Typescript app #1242

Closed loicmagne closed 8 months ago

loicmagne commented 2 years ago

I used protoc -I=. protos/*.proto --js_out=import_style=commonjs,binary:grpcproto_web/ --grpc-web_out=import_style=typescript,mode=grpcweb:grpcproto_web/ to generate my proto file.

Then whenever I try to import proto objects like import { LoginRequest } from '../protos/login_pb'; I get errors Uncaught SyntaxError: import not found: LoginRequest.

I looked at issues #535 or vite#3898 but nothing works.

Does anyone have a working example using Vite+Typescript with grpc-web ?

Krzysztof-Dziardziel commented 2 years ago

I'm having the same issue. Sadly, I couldn't get it to work. I also wasn't able to get Vite+JS to work. Looks like this is some issue with how Vite loads external resources. 😞

Krzysztof-Dziardziel commented 2 years ago

@loicmagne You can use @protobuf-ts and protoc --ts_out ./generated --proto_path "./proto" <protoFilesPaths> command. It works fine with Vite.

lbensaad commented 1 year ago

@Krzysztof-Dziardziel Could you please tell us how you configured protobuf-ts and grpc-web to work with vite?

FredrikMeyer commented 1 year ago

@lbensaad I think the suggestion of @Krzysztof-Dziardziel is to replace grpc-web with protobuf-ts. That's what we did at my job (and it works wonderfully - the objects are much easier to work with, they are just regular JS objects)

wirekang commented 1 year ago

@loicmagne You can use @protobuf-ts and protoc --ts_out ./generated --proto_path "./proto" <protoFilesPaths> command. It works fine with Vite.

This is best answer. We replace grpc-web with protobuf-ts, and every problem have been solved.

lbensaad commented 1 year ago

Thanks @FredrikMeyer, I read it above, but I thought that protobuf-ts is only for messages and must use grpc-web for RPC. Now I also use protobuf-ts for RPC and works perfectly. The key word is replace. Thanks again for mentioning it.

barrelful commented 1 year ago

@sampajano is there any plan to fix grpc-web? I just used the command from the README.md for TypeScript:

protoc -I=$DIR echo.proto \
  --js_out=import_style=commonjs,binary:$OUT_DIR \
  --grpc-web_out=import_style=typescript,mode=grpcweb:$OUT_DIR

But I don't get generated the promissed _grpc_web_pb.ts file. Instead it generates a Pb file with some require('google-protobuf') which will not work on browser environment.

staticdev commented 1 year ago

@lbensaad @FredrikMeyer when replacing gprc-web with protobuf-ts are you using @protobuf-ts/grpcweb-transport? Did you manage do receive a stream with it?

I am having Not Found error for POST http://localhost:5173/0.0.0.0:8080/my_proto.Haberdashery/MakeRowOfHats the example below:

service Haberdashery {
    rpc MakeRowOfHats (Size) returns (stream Hat);
}
sampajano commented 1 year ago

@sampajano is there any plan to fix grpc-web? I just used the command from the README.md for TypeScript:

protoc -I=$DIR echo.proto \
  --js_out=import_style=commonjs,binary:$OUT_DIR \
  --grpc-web_out=import_style=typescript,mode=grpcweb:$OUT_DIR

But I don't get generated the promissed _grpc_web_pb.ts file. Instead it generates a Pb file with some require('google-protobuf') which will not work on browser environment.

@barrelful Thanks for reporting the issue!

FYI the documentation was wrong. There is a generated TS file but with a different name than what's documented. :)

I've fixed it in #1314 above. Let me know there's more blocking issues for you. Thanks!

barrelful commented 1 year ago

@sampajano thanks, actually the rest of the documentation including the example do not work.

import {EchoServiceClient} from './echo_grpc_web_pb';

Should be then

import {EchoServiceClient} from './EchoServiceClientPb';

But also, there is a problem since when I run it in the browser I get the error: SyntaxError: import not found: EchoRequest (exactly same problem mentioned above).

Also the ts-example/client.ts does not match the documented code on README.md so it cannot be a full version of it.

staticdev commented 1 year ago

@barrelful this makes this lib unusable by me, once it is fixed I will try again.

sampajano commented 1 year ago

@barrelful Thanks for pointing out the typo, will fix the documentation. :)

But also, there is a problem since when I run it in the browser I get the error: SyntaxError: import not found: EchoRequest (exactly same problem mentioned above).

Also the ts-example/client.ts does not match the documented code on README.md so it cannot be a full version of it.

I'm guessing that you could be missing a webpack step as we usually intend to have. Please see the below steps for more details on how to run ts-example/client.ts.


@barrelful @staticdev The Typescript example works for me using the new instructions added below:

https://github.com/grpc/grpc-web/tree/master/net/grpc/gateway/examples/echo/ts-example/README.md

Please let me know if the above works for you and if you run into any issues.

Thanks!

barrelful commented 1 year ago

@sampajano thanks for updating the docs. Still the problem is NOT in the import EchoServiceClient anymore but in the following imports

If you run it as Vite application you will get:

Uncaught SyntaxError: import not found: EchoRequest

On the IDE also nothing is found:

 './echo_pb' has no exported member 'EchoRequest'
 './echo_pb' has no exported member 'EchoResponse'
 './echo_pb' has no exported member 'ServerStreamingEchoRequest'
 './echo_pb' has no exported member 'ServerStreamingEchoResponse'

Another confusing thing is that in the new docs you added recommends using mode=grpcwebtext, but on root README.md it has mode=grpcweb. In any case, I tried both and the errors are always the same.

catarse-natural commented 1 year ago

That is true @barrelful, it is not a problem of the documentation I would say. I had the same frustrating experience and decided to go back to good old REST APIs. Maybe if there is a bugfix by @sampajano or other core developers I will be able to try again and give feedback. Unfortunately I could not understand the code well enough to contribute and would require much greater amount of effort on my side.

sampajano commented 1 year ago

@barrelful @catarse-natural thanks for the feedbacks..

@barrelful I'm guessing the issue is Vite specific, is that right? I'm not really familiar with the framework, so i can't really comment on why this is happening..

If you could take a look at your setup v.s. the one i mentioned in the documentation, maybe you can identify what exactly is different (e.g. runtime, different JS bundler (we used WebPack in the example), etc.), and maybe that would give a hint on the nature of this issue..

thanks :)

barrelful commented 1 year ago

@sampajano I spent hours more testing, tried all combinations of --js_out=import_style=commonjs,binary and --js_out=import_style=commonjs, with --grpc-web_out=import_style=typescript,mode=grpcweb and --grpc-web_out=import_style=typescript,mode=grpcwebtext. I always get SyntaxError: import not found: EchoRequest or SyntaxError: The requested module '/src/components/grpc/echo_pb.js' does not provide an export named 'EchoRequest'. I tried on Firefox and Chrome.

I am not really sure if it is Vite specific or not. It is hard to isolate the error since I have already a Vite+Typescript+Vue+npm application, and the example on the repo has Typescript+Webpack+JQuery have does not use Vite or Vue. Would be possible for us to have an extended Echo example in a Typescript Vue component without Webpack?

A quick way to generate a project like that with Vite is:

sudo npm install -g @vue/cli
npm install -D typescript @vue/cli-plugin-typescript
npm create vue@3
# answer questions
npm install
sampajano commented 1 year ago

thanks for trying all the above mentioned options..

I am not really sure if it is Vite specific or not. It is hard to isolate the error since I have already a Vite+Typescript+Vue+npm application, and the example on the repo has Typescript+Webpack+JQuery have does not use Vite or Vue. Would be possible for us to have an extended Echo example in a Typescript Vue component without Webpack?

Sorry i'm not an expert on JS Bundling to know whether we can do without Webpack. But as far as i understand, some bundler needs to be used so that the dependencies can correctly resolve.

Note that echo_pb.js is generated not by grpc-web but by protobuf-javascript so we cannot easily modify the output.

My understanding is that Webpack will ensure that the dependencies are resolved correctly and generate a single JS file for the whole app.

Are you not using any JS Bundler at all? (e.g. wouldn't code size be an issue for you?) I'm guessing you proved that the code does not work without one.

It would be good if you can try some JS bundler and let us know if the compilation succeeds or if the issue remains afterward.

thanks :)

sbussard commented 1 year ago

Are there any updates on this issue?

Shegl commented 1 year ago

I have same issue right now, now I think using vite + react ts was a bad idea for playing around with grpc in browser. However, problem indeed in type_pb.js file, not grpc-web generated. Hope I will find solution and come back to you with work around.

Aymeric-Henry commented 1 year ago

Hello i have been facing the same issue here, I solve it and I created a starter demo example for people also strugling with it. @Shegl maybe you can test it

https://github.com/Aymeric-Henry/GRPC-Vite-TS-Svelte

if you have commentary about it I open to criticism

Shegl commented 1 year ago

@Aymeric-Henry thx, I used https://github.com/vitejs/vite/discussions/8926 < 1st solution and it's worked for me

boldt commented 1 year ago

@Shegl Can you please provide a MWE or a link a project, where that solution works. Thx.

Shegl commented 1 year ago

@boldt hey, in the end it was not working as expected, I use protobuf-ts when I use Vite. https://github.com/Shegl/web-grpc-video-chat you can check how-to

mvonwaldner commented 10 months ago

I think I may have gotten this to work and so am sharing what no longer throws the errors similar to the one mentioned by OP when using gRPC-Web and Vite/TypeScript - for me after running

protoc service.proto \
    --proto_path=. \
    --js_out=import_style=commonjs:. \
    --grpc-web_out=import_style=typescript,mode=grpcwebtext:.

importing the client type from the gRPC-Web generated file can be done using an import statement: import { Client } from './serviceServiceClientPb'; and then the entire service in the generated js / d.ts files is imported using a require statement: const service = require('./service_pb'); at which point the types of the service can be utilized as members of the service: var request = new service.Request(); The types from the service client generated file can be constructed as standalone types, e.g.: var client = new Client('[insert address here]');

Hope this is a helpful working solution for people looking to use gRPC-Web with Vite/Typescript!

sampajano commented 10 months ago

@mvonwaldner Thanks so much for sharing your solution! Very much appreciated!!


To others who had issues earlier:

Does the above solution work for you? If this works for some, i'll document this 😃

Thanks!

adlion commented 9 months ago

No it does not work I get this error

Uncaught ReferenceError: goog is not defined

On the js file there is this import

goog.exportSymbol('proto.command_executor.PostCommandReq', null, global);
goog.exportSymbol('proto.command_executor.PostCommandRes', null, global);

I have used commonjs

on yarn packages I have gprc-web and google-protobuf Part of the code

import { CommandExecutorServiceClient } from './proto/gen//tt/Command_executor_serviceServiceClientPb';

const service = require('./proto/gen/tt/command_executor_service_pb');

function App() {
  const client = new CommandExecutorServiceClient('http://localhost:8100');
  const req = new service.PostCommandReq()
  req.setCommand("ls")
  req.setArgumentsList(["-lah"])
  req.setTimeout(10000)
  const response = client.exec(req,null);

  response.then((res)=>{
    console.log(res);

  }).then((err)=>{
    console.log(err);

  })
sampajano commented 9 months ago

@adlion Thanks for your report!

Could you check if you're following the rough steps laid out in our demo app here: https://github.com/grpc/grpc-web/blob/master/net/grpc/gateway/examples/echo/ts-example/README.md

Note that one of the required steps there is webpack (or maybe some other similar code bundler would work), but if you don't do that, then i believe the goog is not defined error is expected.

adlion commented 9 months ago

I had tried compiling using the typescript or commonjs and was not working. The missing step was the webpack. Same is being described even here https://github.com/vitejs/vite/discussions/8926 My colleagues are not happy to have webpack and vite on same repo so we will look for other ways.

One solution is the first solution here I am still curious how the first method on that link works. If someone could post an example package.json would be great. We will pack our protobuffers in an npm package as we do usually and will check one more time.

boldt commented 8 months ago

Hey,

I created minimal (not) working examples: https://github.com/boldt/grpcweb-cra-to-vite

They show, that the provides solutions by @martinpokorny and @mvonwaldner do not work. I would like to invite @sampajano, @martinpokorny and @mvonwaldner to help us to get that MWEs work.

Probably I am just missing a small piece of the puzzle.

Works with the old CRA

https://github.com/boldt/grpcweb-cra-to-vite/tree/main

It works as expected.

Does not work: Solution by martinpokorny

@see comment from @martinpokorny: https://github.com/grpc/grpc-web/issues/1242#issuecomment-1731152138

https://github.com/boldt/grpcweb-cra-to-vite/tree/martinpokorny

It throws:

Uncaught SyntaxError: The requested module '/src/grpc/echo_pb.js' does not provide an export named 'EchoRequest' (at App.tsx:4:10)

Does not work: Solution by mvonwaldner

@see comment from @mvonwaldner: https://github.com/vitejs/vite/discussions/8926#discussioncomment-7143295

https://github.com/boldt/grpcweb-cra-to-vite/tree/mvonwaldner

It throws:

Uncaught TypeError: service.EchoRequest is not a constructor

a2not commented 8 months ago

I created a working demo for this issue.

Vite apps cannot import CommonJS files (like generated grpc-web files) directly, but it is possible if we make those generated CommonJS files as a local dependency and import from that dep.

Details are in the repo. Too lazy to create the whole envoy proxy and grpc servers but I'm working on a project where grpc-web with vite successfully communicates with grpc servers, so I can assure you this is one way of doing this right.

https://github.com/a2not/vite-grpc-web

boldt commented 8 months ago

I found the missing piece of the puzzle. When I add the following to my vite.config.js in the branch martinpokorny, it works now:

  resolve: {
      preserveSymlinks: true,
    } 
sampajano commented 8 months ago

@boldt Thanks so much for creating a minimal repro case to help the debug. And very happy to hear that you've found the missing puzzle!

Does that mean that, with your approach, we can resolve this issue now? 😃

sampajano commented 8 months ago

@a2not Wow thanks for providing a working demo too! It's great to hear that these working solutions exist now! 😃

a2not commented 8 months ago

I personally think this is not grpc-web's fault.

Whether or not grpc-web should support generation of ES Module files is for sure another topic to consider, because Vite and other tools and js community in general are leaning towards ESM rather than CJS. But we can discuss that in https://github.com/grpc/grpc-web/issues/535.

It is ~not~ possible using grpc-web's CJS with Vite, so I would say this issue can be resolved now 🤔

sampajano commented 8 months ago

I personally think this is not grpc-web's fault.

Whether or not grpc-web should support generation of ES Module files is for sure another topic to consider, because Vite and other tools and js community in general are leaning towards ESM rather than CJS. But we can discuss that in https://github.com/grpc/grpc-web/issues/535.

Yeah thanks for your opinion!

I agree that ES Module is how things should be done in today's world and we'll definitely consider modernizing towards that!

But it is not possible using grpc-web's CJS with Vite, so I would say this issue can be resolved now 🤔

Do you mean this is now possible? 😃

a2not commented 8 months ago

@sampajano oh, sorry for the typo. It's now possible!

It's not about grpc-web, but about how you use Vite properly in my opinion.

sampajano commented 8 months ago

@a2not Aha no problem! Glad to hear! Thanks so much for helping creating the working demo! 😊 (And same with @boldt!)

I'll update our doc in a bit (after i'm back from vacation) and point to the Vite example of yours, and the resolve this bug.

Happy Thanksgiving everyone! :)

sampajano commented 8 months ago

Thanks everyone for helping figuring this out! I'm closing this issue for now 😊

kindlychung commented 5 months ago

For anyone who came here looking for a solution, please read the protobuf-ts manual:

https://github.com/timostamm/protobuf-ts/blob/main/MANUAL.md

it works perfectly (provided that you have enabled grpc-web in the backend).