How should I avoid Application config for a Dev-only Application?

I’ve got a configuration question. I’m making a replacement for phoenix_live_reload that does HMR with Webpack. IPC with Webpack requires some config, and a process and some supervision. Because this is a devtool, it should only run in dev mode, not in test or production.

If I package it as an Application (like phoenix_live_reload is) then I can recommend using only: :dev in the dependency list. The other place it touches your elixir code is inside the if code_reloading? block in your Phoenix Endpoint, which should only be active in :dev, or whatever other environment you wish to define. But then how do I provide the config?

The Elixir 1.7 Library Guidelines recommend avoiding application config in most cases, and @micmus’s excellent article on configuration recommends converting the library into a module-callback thing that doesn’t export an Application.

Okay, but then life gets messy for the end users. If it isn’t an Application that gets started for you, then you need to start it yourself in your own supervisor tree, but again only if you’re in an environment where you want HMR. So, do you say

children = [
  supervisor(MyApp.Repo, []),
  if Application.get_env(:my_app, :use_code_reloading) do
    supervisor(HMR.Supervisor, [options...]), # comma here, or outside the block?
  end
  supervisor(MyAppWeb.Endpoint, [])
]

… ew. Maybe this could get improved by some clever Enum calls? Whatever it is, it feels non-standard.

For reference the two pieces of config I’d like to set are

  1. The location of the unix domain socket I’m using for IPC with Webpack.
  2. The server adapter to use to talk over that socket. (If you’re using Cowboy 2, and this plugin is using the Plug.Adapters.Cowboy adapter, then I foresee an incompatible version problem).

Are these valid use cases for Application config? What about if I’ve got two phoenix apps in an umbrella? Wouldn’t they potentially conflict? I feel like I’m missing something basic.

#2 I’d like to fix remove eventually, maybe by using something like :gen_tcp directly instead of Plug/Cowboy, but this was the simple way to get started, and I would still need to set #1 somewhere.

Are there better ways to approach/think about/solve these problems in general?

3 Likes