For use in Elixir projects
Hi, did you explore this in the end? For some reason I find myself wanting to use gleam explicitly through mix rather than an umbrella project and rebar3. I suspect it just because I'm quite new to the Elixir ecosystem and a bit scared :)
It looks like it is possible to write Mix.Compiler modules. Have you explored that for gleam at all? I can understand it not being a priority.
No work has been done here I'm afraid. This could be a good place for someone to contribute :)
Ok, cool. I'll keep it in mind and let you know if I start or progress on it. Thanks for the quick response.
Ok, I've been poking around a little bit. I don't have a full solution but some of the parts to it.
If you start with a fresh phoenix project, you can add a mix compiler task by creating a file called lib/mix/tasks/compile/gleam.ex. If we give it the following content:
defmodule Mix.Tasks.Compile.Gleam do
use Mix.Task.Compiler
def run(_args) do
System.cmd("gleam", ["build"])
:ok
end
end
Then it does the basic job. We should then run mix compile to compile it and then change the mix.exs file like so:
elixirc_paths: elixirc_paths(Mix.env()),
- compilers: [:phoenix, :gettext] ++ Mix.compilers(),
+ compilers: [:phoenix, :gettext, :gleam] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
Then we can add a src folder with a hello-world gleam file in it in src/hello_world.gleam:
pub fn hello_world() {
"Hello, from gleam!"
}
Then we have to tell mix to make the erlang compiler pass look in the gen folder, back to our mix.exs file with:
elixir: "~> 1.5",
elixirc_paths: elixirc_paths(Mix.env()),
+ erlc_paths: ["gen"],
compilers: [:phoenix, :gettext, :gleam] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
Then we can change our lib/my_app_web/controllers/page_controller.ex like so:
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def index(conn, _params) do
- render(conn, "index.html")
+ render(conn, "index.html", title: :hello_world.hello_world())
end
end
And our lib/my_app_web/templates/page/index.html.eex with:
<section class="phx-hero">
- <h1><%= something about gettext, I forget %></h1>
+ <h1><%= @title %></h1>
<p>A productive web framework that<br/>does not compromise speed or maintainability.</p>
</section>
And run mix compile and mix phx.server and load localhost:4000 to see Hello, from gleam! in the centre of the page.
Notes:
:gleam after Mix.compilers() in the mix.exs file but then more generally we want the output of the gleam compiler to be compiled by the erlang compiler in the Mix.compilers so we want the :gleam before Mix.compilers(). I'm assuming that the compilers are run from left to right through the list. This concern would go away if the :gleam mix compiler integration was coming in through a dependency and compiled with mix deps.compile before :gleam was added to mix.exs compilers line. Bit awkward but not a deal breaker, I guess.lib, src and gen. Though by default mix looks for erlang files in src rather than lib so it expects that to exist and I can see the reason behind generating modules into an entirely separate folder (gen in this case) rather than next to their source modules.Anyway, I'm quite new to all of this so maybe none of this is that interesting, or maybe it is useful. It has been interesting to dig in a bit and see what is going on.
I've spent quite a while with Elm and now that I'm programming Elixir I dearly miss the type system. I also like Rust (though I'm new to it) so gleam is ticking lots of boxes. Personally I would write something with pretty much just the Elm syntax but I don't know how to write a programming language/compiler and I respect that we have different preferences. I'm impressed by the work you've put into gleam and look forward to learning more from the code base.
Wow this is really cool! Perhaps you could make an example GitHub repo to show people? I imagine there would be some interest in a blog post about it too if you're interested.
I'm also not mad keen on having lib, src and gen. Though by default mix looks for erlang files in src rather than lib so it expects that to exist and I can see the reason behind generating modules into an entirely separate folder (gen in this case) rather than next to their source modules.
I agree, gen is somewhat irksome. I think the ideal way to handle generated files would be to keep them in _build somewhere but I'm not sure what the appropriate place would be. If you find out let me know :)
I've spent quite a while with Elm and now that I'm programming Elixir I dearly miss the type system. I also like Rust (though I'm new to it) so gleam is ticking lots of boxes.
Thank you for your kind words! I like those languages a lot :)
Personally I would write something with pretty much just the Elm syntax but I don't know how to write a programming language/compiler and I respect that we have different preferences
I too would prefer the Elm syntax, but the more C style syntax that Gleam has these days is proving much more popular and approachable.
Here is an example repository: https://github.com/michaeljones/gleam-phoenix-mix
There is a weird dance around pre-compiling the mix compiler task before calling mix compile. I think that would go away if there was a published mix-gleam dependency that people could use. Though I'm sure there is plenty of room to improve the actual mix compile task I've written - given that it is one line.
I'll happily put together a blog post too at some point soon.
And I've published a blog post on dev.to: https://dev.to/michaeljones/mixing-gleam-elixir-3fe3
As the README in the demo project is most of a blog post anyway. Thanks for the suggestions. Feedback welcome on both. I can make you a collaborator on the repo if you want to tweak or tune anything.
Cool stuff! Thank you!
I don't know the details but the mix compiler task supports return error information and diagnostics in a manner that the rest of the tool chain can work with. Possibly allowing the elixir language server to do something or at least a step in that direction.
The diagnostics are documented to some degree here: https://hexdocs.pm/mix/Mix.Task.Compiler.Diagnostic.html#content
Is that something that you'd consider exploring for gleam? Could I make a new issue for it?
I imagine that it would involve adding a --format flag to the compiler with certain options. Possibly a generic json format that the mix compiler task could then transform into the diagnostic format. Rather than gleam using that format itself. I'm assuming that isn't possible at the moment as gleam build doesn't seem to have such an option.
That said, I've really not used gleam much at all so maybe I should learn more about the set up and current options before pushing for random stuff that I've stumbled across in the docs.
There are no plans to support any Elixir format at present, though we do wish to support Language Server Protocol. I think we'd want to have better tooling before we start thinking about things like diagnostic integration
@michaeljones https://app.rdstation.email/mail/9b0b82b7-f47a-4cf3-a916-0b64a8817fae
You've been featured in the Elixir Radar newsletter :)
Cool! Makes me happy. Thanks for letting me know. Kind of you.
We could have a section on the gleam docs about running in mix now.
erlc_paths: ["src", "gen"],
compilers: [:gleam | Mix.compilers()],
aliases: ["compile.gleam": "cmd gleam build"],
Open an issue for mix docs and just point me to where they need to go if this is of interest
Once you've used this for a while and we're confident exactly what approach to recommend we could add a "adding gleam to a Elixir mix project" to this section of the book -> https://gleam.run/writing-gleam/index.html
Most helpful comment
And I've published a blog post on dev.to: https://dev.to/michaeljones/mixing-gleam-elixir-3fe3
As the README in the demo project is most of a blog post anyway. Thanks for the suggestions. Feedback welcome on both. I can make you a collaborator on the repo if you want to tweak or tune anything.