stephenh / ts-poet

A code generator DSL for typescript
Apache License 2.0
103 stars 13 forks source link

ts-poet depends on prettier #16

Closed arontsang closed 3 years ago

arontsang commented 3 years ago

I am currently trying to bundle ts-proto as a standalone js file to use outside of npm in a CI context (single file is much faster to download than a npm dependency tree).

Prettier makes up 7.42MB out of 7.66MB of ts-proto, that is pretty bad.

Further more, it breaks the single point of responsibility of ts-poet (I rather not run prettier on a CI build for auto generated files).

Additionally, ts-poet should not need to bring in dependencies on a markdown/html/flow parser.

image

stephenh commented 3 years ago

I'd be open to bundling ts-poet with something that tree-shakes prettier down to only what is used, but I'm unlikely to drop it entirely.

I've been using code generation for awhile now, and in the ~late 90s/early 2000s it had a really bad reputation for "looking ugly" (because it did, formatting would be way off, it would have tons of lint errors, lots of dead code / unused imports / etc.).

So ts-poet comes from a lineage of "poet" code generation libraries, generally starting with Square's java poet, that purposefully produce idiomatic, pleasant to read code.

If you look at Square's java poet, it did this by building a mini-formatter into the code generation library itself, which heavily influenced the API/DSL of the code generation library. You can see this in the 1.x & 2.x versions of ts-poet, that liberally/purposefully copied the poet approach/DSL style.

What changed in ts-poet 3.x+ is the realization, that unlike the code generation of the 90s/00s and even early-10s, is that formatters have gotten so easy to embed as standalone tools/libraries (instead of hidden in the guts of an IDE), that we can completely decouple "generating code" from "formatting code".

So ts-poet 3.x+ leans heavily into this, and does almost zero formatting of the code, before handing off to prettier.

I have not technically looked at the pre-prettier output in awhile (usually I only do that while debugging issues in ts-poet), but my guess is that you'd be surprised at how ugly it is, precisely b/c it's so much simpler (from a complexity standpoint) to just let prettier do it.

Also, stepping back, you mention "this is just for CI" several times, but surely CI is producing artifacts that will be used in a non-CI environment at some point (otherwise why produce it), at which point someone is going to get a stack trace through ts-poet/ts-proto-generated code, and they're going to go "...yuck..." if it's not formatted to at least some standard.

So, anyway, at least two long tangents there, but moving off prettier is out-of-scope for the project at this point.

If you like, you can use the 2.x version of ts-poet (which doesn't use prettier, and instead has a ~100-200 LOC "good enough" formatter that is a port of a port of Square's java poet library), and even the ts-proto versions before migration to ts-poet 3.x, which wasn't that long ago iirc.

So, depending on what features you need from ts-proto, pinning to that version of ts-proto might actually be fine for your use case.

If avoiding prettier long-term is non-negotiable for you, you fork ts-poet + ts-proto from that pre-ts-poet-3.x point in time...

stephenh commented 3 years ago

I'd be open to bundling ts-poet with something that tree-shakes prettier down to only what is used

I realized, mostly talking out loud at this point, that I probably wouldn't do this, b/c ts-poet generally assumes most downstream projects are using prettier anyway, and so already have the full prettier in their node_modules.

So by not bundling prettier, we:

a) avoid the user having two copies of prettier (one in our bundle) + the one they use anyway b) leverage that the ts-poet output will likely use exactly the same version of prettier as the rest of their codebase, and so be as idiomatic close to the rest of their code as possible

(Granted, the "most downstream projects are using prettier anyway" is not a universal assumption, but it's one that I'm personally comfortable making. I started my career with a disdain for formatters, b/c at the time they were objectively worse than hand-formatted code, but starting with Eclipse's Java formatter in the mid-2000s and now with prettier, I dunno, personally I think they are remarkably good for what they do, and worth it from a "98% of the output is what I'd write by hand anyway, and when you can apply that level of consistency to code written by every individual dev in a project, that's pretty great all things considered.")

stephenh commented 3 years ago

(Fwiw I am surprised prettier is 8mb; if they produced per-language modules like @prettier/typescript I'd be very open to switching to that. Granted, that's still 3mb, which fwiw I also agree "seems like too much", but :shrug: , is what it is.)

arontsang commented 3 years ago

FYI. The plan is to bundle ts-proto into a nuget package, where I can auto generate both the client (typescript) and the server (C#, this exist, due to grpc-tools). This way I can get fully typesafe development across TS/C#.

Since the javascript side does not have a single package manager, and since I will be invoking it outside of the client stack yarn/npnm/npm/deno I don't want to make assumptions on how to get access to the existing prettier installation.

I'm currently looking at using a package-patch fix this issue for my release.