Feedback needed: where is bsc used in your project?

Hi all,

(Note if you don’t know bsc, it is great, feel free to ignore this post).

Following the latest version, we have introduced the rescript as the single entry point for better user experience.
Currently it covers most daily use cases for rescript users. Note we noticed that bsc is also used somewhere, here we want to collect all your major use cases of bsc and expose it in rescript subcommand.
Would you leave your comment here that when do you call bsc directly in your project?

Hi,

I’m trying to generate js outputs using bsc in Google’s bazel build system. And bsc is a good entry point because it is less stateful than rescript or bsb.

I’m trying to reproduce the build process we’re making with ninja, but it seems bsc is also stateful, and I’ve been hitting roadblocks since :blush: (Bsc.exe seems to assume that the CWD is the project directory with bsbconfig, like the rescript command does.). That, along with my little understanding of the ninja internals we’re having.

If we can provide a compiler toolchain with a stateless interface (input rescript, output javascript), then it’s easier to integrate with other build system. But what’s being asked here is perhaps out of the scope of the project :stuck_out_tongue:

1 Like

(Sorry, had a browser issue with my previous reply) +1, this was also the only thing I had used bsc for. I spent far too many hours trying to get Rescript building on Bazel (in many companies building with Bazel is a hard requirement for integration) before just dropping it.

See our advice here: Interop with JS Build Systems | ReScript Language Manual

Wrapping our build isn’t really viable. Most folks get the incrementality wrong and get churned, not to mention creates problem when these wrapper systems reach userland (or worse, in-house users of the ad-hoc wrapper which we don’t know about, with a growing dislike for the fragile build and the overall experience). We’ve had a few instances before when folks integrated bsc/bsb into e.g. CRA or some JS bundler as a middleware, which then killed our pitch of robustness because we end up only as robust as the bundler - the middleware's flaws. It’s a lose-lose. Countless hours wasted from all sides involved.

1 Like

Yup, I had read that. Bazel is very different than something like a bundler. (I believe Pants and Buck are very similar, if you’re familiar with them) but I understand your point. This was just a hard requirement for someone I was trying to help introduce Rescript into their company’s monorepo.

Yeah kinda familiar with them. In fact I had to explicitly reject proposals to integrate with some of these based on a few criteria. The curse of selling robustness and speed is that we have to ensure that there isn’t a bottleneck somewhere else anyway, like in a wrapper build (or userland library or whatever else).

So was there no way to just run bsb one-shot?

I tried to make that happen because yeah… I knew doing anything too custom would just cause pain. But we got stuck with Bazel having some strict requirements for the output location of build files. Essentially (if I’m remembering this correctly, it was a few months ago), Bazel provides you a location and you have to build into that location. Any files built in your project’s directory are ignored (as a project is only considered input, not output).

1 Like

Does Bazel deal with js? Suppose you always check in generated code, do you need an abstraction layer? Note we recommend to check in generated code

1 Like

Yes, it actually has a fairly good system for dealing with just JS. I know that’s the recommended Rescript pattern, so that was my first suggestion. Unfortunately, hit two issues:

  1. The build/release engineers just wouldn’t allow it. They brought up worries about security, blessed dependency management, compatibility worries, and a few other things. I explained there wouldn’t be any compatibility issues… because JS is JS and the native code is just in node_modules at runtime… but overall it was a tough sell.
  2. The team really didn’t like the idea of reading both rescript and JS for every Pull Request.

(I have to reiterate that this wasn’t my company. I just spent a long weekend helping someone on a small team in a big company try to get started integrating ReScript.)

I believe two things would have gotten them past “Go”:

  1. something like a config option to specify the location of “lib” on the machine (outside of the source code)
  2. the ability to run rescript build from anywhere on the machine, and point to the project directory (I believe this is just a Bazel choice. They only execute commands from the root of the monorepo.)

I have no idea the cost of that, so I’m not suggesting it, it’s just what would have helped in the Bazel situation. Also, our initial implementation before dropping using bsc, was based on GitHub - ostera/rules_reason: 📐Reason/OCaml rules and tools for Bazel, which uses bsc and I know some people still use.

The build/release engineers just wouldn’t allow it. They brought up worries about security

I am completely lost. Is not it way more secure to check in generated code to avoid running native tools on the production server? Imagine babel’s dependencies are hostile, it is really hard to detect given such dependencies are huge. Note we are doing a slightly better job where the compiler is self-contained, but it is generally a better idea to avoid attack surface.

  1. The team really didn’t like the idea of reading both rescript and JS for every Pull Request.

This is not a bad thing, since if you do refactoring, and the generated js are almost the same, much more confidence. But it is configurable, most review tools can detect generated code with some work.

The ability to run rescript build from anywhere on the machine, and point to the project directory

We can do some work to let rescript to figure out the root project, feel free to raise an issue.

We can also add support to flatten the js output directory to make it easily monitored. We can do some work to make rescript work better with bazel, but it is definitely not recommended to integrate bsc with bazel.

To make it clear, integrate bsc with another build system is not supported, you are pretty much on your own and we may change bsc flags which break your work.

I am completely lost. Is not it way more secure to check in generated code to avoid running native tools on the production server?

I’m reaching the limits of my memory on the situation, but I’m 100% certain the production servers don’t build. The CI/Build servers (with security-approved dependencies, tooling) build and then put it in a docker container which does nothing but node server.js… it’s a common pattern. This was company was in the finance area, so I image they have stricter controls than most.

To make it clear, integrate bsc with another build system is not supported, you are pretty much on your own and we may change bsc flags which break your work.

I/They never assumed it was supported. I just tried to help get someone who was excited about rescript, but had very constrained build conditions, onboarded. We tried using bsc to get around the constraints, so I thought it would be worth bringing up here.

I use bsc to generate .cmt files on the fly from stdin. I use them to read signatures and augment code with annotations like here (changes in text editor are buffered, they are not present on disk):
image

3 Likes

I’m sure this is already known, since I found out from forum posts, but in any case. I’ve been using bsc -i lib/bs/src/Cli.cmi to help me generate interface files to tighten module APIs.

Re-typing or fishing to copy paste the signatures can get kind of boring.

3 Likes

This is something we want to support. We came across similar situtations in the vscode plugin( cc @cristianoc )
I am glad that you went that far.
What’s your current architecture?
How do you figure out those command line flags currently?
Is your plugin written in OCaml? How do you consume those cmt files?

Yes, this will be supported. I have a vague memory that the editor support will also ship this feature (cc @chenglou )

1 Like

The editor calls bsc on the .cmi file.
Once this is available as main command, it can be used instead.

2 Likes

AFAIK, the plugin is written in Java. I guess you have to target JVM if you target JetBrains IDEs.

Plugin code is in java.
I read the ninja build file and try to extract correct flags for temporary compilation (using different paths for ex).
It’s empirical knowledge, but it works for now.
I also have to keep different implementations that depends on the version of bs, ninja format have been changed recently.

I am completely lost. Is not it way more secure to check in generated code to avoid running native tools on the production server?

it’s generally avoided in a monorepo world to commit output artifacts (for rescript, it’s javascript) to the repository. I think this simplifies the DevX for a project: it’s easy to formalize the automatic build, and easy to onboard people from other language.

But I see @Hongbo’s point of adding rescript incrementally to a code-base as the justification to just committing JS.

To make it clear, integrate bsc with another build system is not supported, you are pretty much on your own and we may change bsc flags which break your work.

Yeah to add to this point, I’m well aware of this, most Bazel integration of a language would anyways pin down the exactly compiler using SHA hash of the repository having the compiler. So that helps with reproduciable builds, creating a frozen compiler to avoid incompatibility of flags, and achieving some added security, supposedly. If compatibility issue arises, most likely, we have to update the build rules for the new language.


@Hongbo
All points aside, I think the difficulty I’m dealing with interfacing rescript instead of bsc was that rescript is a compiler + a build toolchain. It deals with the project at a bigger scope ( handling dependencies from package.json, handles intra-module dependencies).

I wanted bsc because it exposes an interface that deals with individual module. Just a compiler (bsc) fulfills that needs. If we can expose a stable granular API from rescript, then I don’t have to go down that rabbit hole. (Kinda similar to the C/C++ situation, I think as @Hongbo mentioned somewhere in this forumn)

@johnmegahan GitHub - iocat/rules_rescript: Bazel Rules for Rescript This is the bazel build rules that I’ve been working on by the way.

1 Like

are you available some time for a chat? would be happy to figure out what is needed. Feel free to DM or send an email