connectrpc / connect-es

The TypeScript implementation of Connect: Protobuf RPC that works.

Home Page:https://connectrpc.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Incorrect Import Path Extensions in Generated TS Files

sugar-cat7 opened this issue · comments

Description:
The generated files, when used in a CommonJS environment, have incorrect import path extensions (.js). This is causing module resolution failures.

Steps to Reproduce:

  1. Prepare the proto and utilize buf to generate the code using the following config:
version: v1
plugins:
  - plugin: es
    out: gen
    opt: target=ts
  - plugin: connect-es
    out: gen
    opt: target=ts
  1. Set up a CommonJS environment.
  2. Use the specified libraries to generate the required files.
  3. Observe the incorrect import path extensions in the generated files.

Expected Behavior:
Generated files should have the correct import path extensions suitable for a CommonJS environment.

Screenshots:

image image image

Environment:

  • Library/Framework Versions:
    • @connectrpc/connect-web: 1.1.2
    • @bufbuild/protobuf: 1.3.3
    • Frontend framework: next@13.5.4
  • Node.js Version: 20.8.0

Additional Context:
Upon reviewing the sample code provided in the connectrpc's GitHub repository, I noticed that the same issue with incorrect import path extensions is also present there.

@sugar-cat7, I have the same issue, and I fixed it by setting the import_extension option.

  - plugin: connect-es
    out: src
    opt: target=ts,import_extension=none

@sugar-cat7, you can use resolve.extensionAlias in webpack, or the plugin option import_extension=none.

We have an example here, and documentation here.

It's unfortunate that webpack does not support .js extensions in TypeScript code out of the box. If you compile the code with the TypeScript compiler and run it with Node.js, you'll find that it actually compiles and runs without issues.

Which parts of the documentation did you use to get started? Hopefully we can improve it.

Thank you for providing the solution! I was able to resolve the issue by following your suggested methods. :)

I stumbled upon this issue while following the documentation provided here: Local Code Generation.

We have added this paragraph to the page:

If your bundler does not handle the .js extension in the import from "./eliza_pb.js" correctly, you can configure it following our examples here, or you can add the plugin option import_extension=none to remove the extension.

Thanks for helping to improve the docs!

I just ran into this issue, and managed to resolve it by changing my buf.gen.yaml to the following:

version: v1
plugins:
  # This will invoke protoc-gen-es
  - plugin: es
    out: clarifai-connect-grpc/gen
    opt:
      - target=ts
      - import_extension=none
  # This will invoke protoc-gen-connect-es
  - plugin: connect-es
    out: clarifai-connect-grpc/gen
    opt:
      - target=ts
      - import_extension=none

It's unfortunate that webpack does not support .js extensions in TypeScript code out of the box. If you compile the code with the TypeScript compiler and run it with Node.js, you'll find that it actually compiles and runs without issues.

Why would it be the bundler's job to change which file extension it matches? As I understand it, most bundler will let you leave off the extension, in which case it will go through a list of various extensions like js, ts, jsx, tsx, mjs, etc, in which case, the generated module greet_pb.ts would have been found eventually, and it would have worked. The problem was that the code that was generated was all .ts files, but the generated code had imports to greet_pb.js so if you specify the extension, most bundlers won't try to second guess what you wanted, and instead try to give you exactly what you requested.

In my opinion, import_extension should be set to none by default, since if I'm not mistaken, all bundlers and even node will support this behavior, and even newer runtimes like Deno which try to create stricter behavior will often include compatibility for node conventions (though I haven't tested any of this). Shy of this, I think the buf.gen.yaml file on that page should include it because then it will actually work regardless of the extension.

In my next.js (which uses webpack), when I use the sample buf.gen.yaml with just target=ts, here's the directory and code that I see:

image

Trying to build this app fails, because it's looking for a non-existent .js file. When I add the import_extension=none option and regenerate the code, I get the following output:

image

This version builds correctly in my next.js app, and I imagine most bundlers out there also include this "fallback" of selecting from a variety of extensions if no extension is specified.

Apologies if I'm misunderstanding the issue, but to me it seems pretty clear that the code generator is incorrectly adding a .js extension when it's outputting ts code, because I don't have any .js files anyway, how could that ever work (other than re-mapping the js extension back to ts as your workaround section suggests).

even node will support this behavior

Unfortunately, that is not the case, @alexandros-megas. From the TypeScript handbook:

In Node.js, module specifiers in import statements and dynamic import() calls are not allowed to omit file extensions or /index.js suffixes

Node.js is following the ECMAScript spec, TypeScript and browsers too, but bundlers have not caught up. Here's an issue filed against next.js. Webpack added the option extensionAlias to mitigate.

When we initially wrote the code generator about two years ago, we expected bundlers to update much more quickly. Unfortunately, they haven't yet. We'll consider to change the default behavior to generate no import extension in the next major version, if the situation has not improved.