oyvindberg / bleep

A bleeping fast scala build tool!
MIT License
150 stars 21 forks source link

ScalaJS scripts for bleep scripts? #335

Open markehammons opened 1 year ago

markehammons commented 1 year ago

Right now, build rewrites and bleep scripts require using bloop to process. I was curious if the native bloop image could run ScalaJS scripts using graaljs...

oyvindberg commented 1 year ago

I think you gotta give a bit more detail about what you want to accomplish here :)

It's... Almost supported to write scripts in scala.js/native. The bleep model is not cross-compiled, but it's also not strictly necessary. If there is a nice usecase for having non-JVM scripts we could work towards it. In any case they would be run through bloop just like all the other things which can be run

markehammons commented 1 year ago

I don't fully understand bleep's internals yet, but my understanding is that in order for build rewrites to be processed, they have to be run via the JVM, which means a jvm must be booted (I believe you use bloop though).

In theory, if bleep used scalajs, and processed said js through graaljs, then you could have the bleep command (aotc built) able to process these scripts without booting a JVM, cutting down on startup time. If that would result in a net-reduction in script processing time I don't know.

Basically the idea is to cut out the time of booting a JVM by having the bleep aotc binary interpret ScalaJS via graaljs or rhino (if you could AOTC compile those js on java engines).

oyvindberg commented 1 year ago

Ah right, you want to make it faster. All in agreement with that.

"Pay for what you eat"

Let me give a little bit of context first, I designed Bleep so that "you pay for what you eat". Want to keep inside the lines and have a standard build? it'll be super fast. Bleep takes like 90%+ of all sbt builds and makes them faster, or that's the idea.

Then if you need something special which requires you to run arbitrary code as part of running the build, that's when you start to pay a performance cost. And honestly I'm quite OK with this picture, it''s an incentive to keeps builds simple. builds should be simple. and it is my theory that they can always be simple. most of the time when you do complex things I believe it can be moved to the last part of you build pipeline, the packaging/publishing. so that's why packaging and publishing in Bleep is done as code in scripts. You do it rarely, so performance does not matter in this case. (note that publishing will be moved into core as a normal command at some point, just haven't gotten around to it)

Whether this theory holds is another matter. So far it works for my usage, but very interested in feedback on the cases where it is not enough.

Let's say you have a complex build then

So onwards from there, let's say you need a build rewrite. Currently, as you've correctly understood, this requires us to boot a JVM - in accordance with the principle of pay for what you eat.

So this is slow. How can we make it faster? There are a lot of ideas floating around here actually.

I think the easiest in many ways would be to pipe a full YAML file through for instance node, get a YAML file back and boot Bleep with that. Then we could expose a Typescript version of the Bleep model and make that a rather nice experience.

Another is what you mentioned here, to compile scripts to another platform, say scala.js and then pipe it through something like node, or in this case graaljs. I'll be honest and say I didn't know that existed, so I have no insights as to the performance characteristics or complexity of something like that. What I am sceptical of is how slow it is to compile Scala code to javascript code. If we compare (compile scala script, run it on a JVM) with (compile scala script, link it to javascript, run node) I think you have to call that script quite a few times without changing it for this to make sense.

If you want to dig into this and come up with a minimal POC for how it would work, I would be interested in looking at it and discussing it. I can not promise that we will go that direction however, as I'm wary of accruing complexity for the "complex build"-case which I want people to not use.

From here?

The direction I want to research first is what your build does that makes you want to use build rewrites, and can we fit it inside the normal Bleep model?

markehammons commented 1 year ago

Another is what you mentioned here, to compile scripts to another platform, say scala.js and then pipe it through something like node, or in this case graaljs. I'll be honest and say I didn't know that existed, so I have no insights as to the performance characteristics or complexity of something like that. What I am sceptical of is how slow it is to compile Scala code to javascript code. If we compare (compile scala script, run it on a JVM) with (compile scala script, link it to javascript, run node) I think you have to call that script quite a few times without changing it for this to make sense.

Well, my thought is with regards to pre-compiled plugins that use build rewrites. Right now, I am trying to make a jmh "plugin" for bleep, and it has to do a build rewrite to generate a new project depending on the benchmark project where java files are generated based off the classfiles from the benchmark project. This script would be precompiled and distributed as a maven dependency, meaning the compilation phase is not an issue any more.

The direction I want to research first is what your build does that makes you want to use build rewrites, and can we fit it inside the normal Bleep model?

What I'm trying right now is to create a jmh plugin. There's a lot of stuff going on with this, and I've only gotten up to the .java files from the jmh benchmark generator being created, not compiled, but basically the build rewrites find a benchmark project, and create a new project named "benchgen". That new project depends on the original one, has the benchmark generator lib as a maven dependency, and has a sourcegen script that calls the benchmark generator with the classes from the benchmark project.

oyvindberg commented 1 year ago

oh, you're using jmh! I have a sample here for how you can do it as a source generator and a library dependency. I thought I got a really slick experience out of that! :)

oyvindberg commented 1 year ago

If you check it out, pull the newest commit in the repo and run bleep run benchmarks-runner.