deeplay-io / nice-grpc

A TypeScript gRPC library that is nice to you
MIT License
392 stars 32 forks source link

ESM and CJS outputs for packages #610

Open davidfiala opened 3 weeks ago

davidfiala commented 3 weeks ago

I'd love to get a discussion going around build types (ESM, CJS, or hybrid) for the nice-grpc packages. ESM is the future, but not everyone has arrived yet. Part of arriving is getting ESM outputs everywhere. It seems that we can include both CJS and ESM builds in the same package.json when necessary.

I'm curious which packages need to support hybrid outputs, and which don't. For example, nice-grpc-web can probably be pure ESM as it's browser-based while the rest might benefit from having both outputs for the time being.

As for figuring out the module and target, I have some data and survey of related dependencies:

I think for the node case it's pretty clear we can use ES2023. Although grpc-js targets ES2017 (https://github.com/grpc/grpc-node/blob/a4c2106e63064070f3b9e580b2d1c74b0a9503a4/packages/grpc-js/tsconfig.json#L15) and that is "the" big heavy dependency. I'll say that in my own work I do custom build grpc-js on the server side to meet the same target as the rest of my software (above ES2017). I suspect others that care will do the same rather than take whatever is served on npm.

For the browser's nice-grpc-web case it is less clear. ES2020 is great and would bring some notable features. Sadly though the top web dependency is protobufjs, I think. And they compile to ES5 (https://github.com/protobufjs/protobuf.js). So our heaviest dep isn't itself compiled for the modern era: yuck. ES2020 also lacks BigInt support today (looking at you, long.js.. sigh). Though people have been bringing it up, citing similar stats as above(https://github.com/protobufjs/protobuf.js/issues/1151). --- Emotionally at least, it would be nice to show solidarity in pushing the expectation of modern browser support and any potential performance benefits of not shipping ES polyfills.

So, I'd start the discussion with a proposal:

Hyrbridize all packages for ESM/CJS with ES2023 target, except nice-grpc-web. nice-grpc-web is ESM only targetting ES2020.

davidfiala commented 3 weeks ago

Angular 18 showing its 💔 to grpc and proto....

▲ [WARNING] Module 'nice-grpc-web' used by '....' is not ESM

  CommonJS or AMD dependencies can cause optimization bailouts.
  For more information see: https://angular.dev/tools/cli/build#configuring-commonjs-dependencies

▲ [WARNING] Module 'nice-grpc-common' used by '....' is not ESM

  CommonJS or AMD dependencies can cause optimization bailouts.
  For more information see: https://angular.dev/tools/cli/build#configuring-commonjs-dependencies

▲ [WARNING] Module 'protobufjs/minimal' used by '....' is not ESM

  CommonJS or AMD dependencies can cause optimization bailouts.
  For more information see: https://angular.dev/tools/cli/build#configuring-commonjs-dependencies
aikoven commented 3 weeks ago

I'm curious which packages need to support hybrid outputs, and which don't. For example, nice-grpc-web can probably be pure ESM as it's browser-based while the rest might benefit from having both outputs for the time being.

Actually, I have seen nice-grpc-web being used on NodeJS as well. Some service providers make client libraries based on it that are meant to be platform agnostic. So hybrid is needed for all the packages.

I think for the node case it's pretty clear we can use ES2023.

For the browser's nice-grpc-web case it is less clear. ES2020 is great and would bring some notable features.

Note that most of the other nice-grpc-* libraries are usable in both NodeJS and the browser.

Only nice-grpc, nice-grpc-prometheus, nice-grpc-server-* are NodeJS-only. All the others run on both platforms.


Considering targets, it's clear enough for me how to choose the target for NodeJS builds — just look at the NodeJS version support timeline. But for browsers, I've mostly followed the path of compiling to older targets to maximize browser support. However, this may be an outdated approach, because I've heard that people nowadays compile all of the node_modules code when they bundle their frontends. If that's the case, then we can disregard the browser support and just use the NodeJS baseline to select the target.