The Crystal compiler includes a number of different tools that are helpful for Crystal development.
Most of them are part of the compiler because they use compiler internals for code analysis or similar things. And most of them are fairly simple programs that more or less query some particular insights from the AST.
It makes a lot of sense to have them included in the compiler because they require the compiler source anyway, and they don’t add that much weight.
But some things do add weight.
For example, the business end of crystal doc
is basically a domain-specific static site generator that produces HTML output.
crystal play
is an HTTP webserver which starts a compilation process on API request.
These are not really core features of a program that’s intended to compile source code.
Merging all this together in a single program is a pile of complexity.
Every time we build the compiler, we’re building an HTML generator and a web server.
Especially for development builds, that’s pretty wasteful because we usually don’t care about the doc generator or the playground when working on compiler features.
With this patch to disable building some of the tools, we get a nice performance improvement (about 10% on my machine) when we only need a new development build of the compiler itself. It would certainly make a lot of sense to use that when working on the compiler.
There’s currently a discussion on a feature request for HTML sanitization for the doc generator. HTML parsing requires libxml2
, so that would add another dependency to the compiler. And it’s a dependency that has nothing to do with compiling code.
As mentioned there I believe it would be a good idea to extract all parts that are not directly related to the core business of a compiler into their own programs.
I don’t think there’s a compelling reason to have an web server directly running in the compiler process, or an HTML generator (which might soon also do sanitization).
These could very well be their own programs which interact with the compiler program through a well-defined interface.
For crystal play
I imagine this should be pretty straightforward by replacing compiler.compile
with Process.run("crystal build")
. Of course there’s a bit more involved, but the interface already exists and it’s pretty small.
Extracting crystal doc
requires a bit more work to establish a clear structured data format for interchange (Improved Crystal API model mapping · Issue #6947 · crystal-lang/crystal · GitHub). But doable.
I merely think of this as an internal refactor. It should be pretty much invisible to the user. crystal play
and crystal doc
should continue to work as they did before. Just that the compiler delegates to a different program (which then in turn runs the compiler again when it needs it).
We might keep developing these tools in the main repo or gradually extract them into their own repos that can evolve independently (similar to shards
).
Thanks to @ggiraldez for bringing up this topic in a private conversation.