Single file elixir applications (and globally installed libraries)

I am trying to write single file application for demoing Elixir applications.
The aim is to get as close as possible to the frictionless getting started experience with Sinatra.rb

The best I have is the following.

# example.exs
defmodule Server do
  use Ace.HTTP.Service, port: 8080, cleartext: true

  def handle_request(_request, _state) do
    response(:ok)
    |> set_body("Hello, World!")
  end
end

Server.start_link([])
mix deps.get
mix run --no-halt example.exs

However this also requires

# mix.exs
defmodule Single.MixProject do
  use Mix.Project

  def project do
    [
      app: :example,
      version: "0.1.0",
      elixir: "~> 1.7",
      start_permanent: Mix.env() == :prod,
      deps: deps()
    ]
  end

  def application do
    [extra_applications: [:logger]]
  end

  defp deps do
    [{:ace, "0.16.8"}]
  end
end

This is pretty good, and because I can use the mix generator to create mix.exs really not bad.
However it would be even better, for my purposes, if I could get down to one file.
I have found that it is possible to use run outside a mix project mix run --no-mix-exs example.ex but that only works for a project with no dependencies.

I can’t find a way to do global installs, I am missing them? Is there a better suggested way?
As I mentioned 2 files is pretty good and pretty clean, but can I get to one?

1 Like

There are ways for global installs, but you shouldn’t use them, as those globally installed packages were in the load path of all your applications.

After installing eg. ace globally, mix would complain about double defined modules when working in ace directly or when working in a propper project that has ace defined as a dependency. The bad thing is, you wouldn’t even know which of the modules get loaded, and you might end up with a mixed runtime that has modules from global and local installation.

That’s why the global install is only proposed for small mix tasks that do not have any dependencies like phx_gen.

Please see also:

1 Like

Looks like it should be possible with an escript. Then I could have the experience as follows

# add mix bin to path
$ mix escript.install hex ace

ace server.exs

Where the contents of server.exs is just

use Raxx.SimpleServer

def handle_request(_request, _config) do
  response(:ok)
  |> set_body("Hello, world!")
end