Lightweight Elixir web framework?

As a note to anyone implementing .eex templating with just plug, don’t use the default eex engine, it’s quite inefficient since it just concatenates binaries – instead, either write your own .eex engine or use phoenix’s one for html to handle the templates as iodata.

It’s also important to understand what exactly is the goal of “lightweight”, if it’s to reduce complexity, then plug won’t offer much against phoenix, especially if you use --no-* flags as people above have mentioned; if it’s to improve performance, then from my benchmarks with tsung for websockets and wrk for http/1.1 from last year, the biggest improvements were not from picking plug or phoenix, but from changing the underlying webserver from cowboy to something, well, more performant (like a modified version of elli).

modified version elli?

The most important modifications in terms of usability and performance that I made were:

  • for http/1.1: support for plug. Since plug is modeled to work well with cowboy, elli needed to be modified a bit to work both with plug and metrics collection callbacks. A simple way to add plug integration into elli without forking elli would be to “handover” the request to a plug adapter in elli_http:handle_request, but then some request timings would be lost.

  • for websockets (websockets support is not included with elli, actually, but rather comes in an extension): that extension was again modeled after cowboy and used :inet.setopts(socket, active: :once) which was inefficient for big messages, so instead I :inet.setopts(socket, active: false) the socket whenever a packet arrived, and read it with :gen_tcp.recv “manually” untill it was over, and switched back into active: :once only then. Not sure if the current cowboy’s websockets implementation has this “optimization”. Seems like it doesn’t and stream’s read_body still uses messaging (in addition to then sending messages once again from the socket process to the stream process? not sure) which is quite less efficient than :gen_tcp.recv.