How to set up Phoenix live code reloading in a not-quite-umbrella?

I am working on a project that is almost, but not quite, an umbrella application. Rather, it contains many mix-projects in subfolders of the apps/ folder, with multiple Mix projects depending on varying groups of these in subfolders of the rels/ folder.

A minimal example setup can be seen in this GitHub repo


The commands to create it were:

$ mkdir apps/
$ mkdir rels/

$ cd apps/
$ mix phx.new phoenix_app --no-ecto
$ cd ../rels
$ mix new main_app

Now edit rels/main_app/mix.exs to include the following in the deps() section:

  defp deps do
      {:phoenix_app, path: "../../apps/phoenix_app", env: Mix.env()}
  end

And edit rels/main_app/config/config.exs to include the Phoenix-related configuration of the dependency:

import_config "../../../apps/phoenix_app/config/config.exs"

This is the bare minimum to get Phoenix running in development (as well as in production) with this not-quite-umbrella setup, using iex -S mix phx.server from the main_app folder.

However, there are two gotcha’s:

  • Live code reloading is not working. Making a change to one of the files in apps/phoenix_app/lib/phoenix_app_web/templates/ for instance does not auto-refresh the page. Even manually refreshing the page will not pick up this change.
  • Webpack works, but only if someone went to apps/phoenix_app/assets and ran the npm install && node node_modules/webpack/bin/webpack.js --mode development there. That will work fine for the person who first set up the applications (because Phoenix asks you if you want to ‘fetch and install dependencies now’). But when another contributor fetches the application from Git later, they won’t have the same luck. They need to manually run those commands. They do get a warning when starting up the app to run cd assets && npm install, but this will not point to the path the Phoenix app itself is installed in, and thus be confusing.

I am trying to resolve these two issues.
What configuration am I missing to make this work without issue?
Feel free to look at and try things out with the minimal example application yourself :slight_smile:.

Thanks!~

1 Like

You would need to change Phoenix’ code reloader to look at path deps instead of umbrella children.

Thank you for your reply!

It is not currently running in an umbrella, i.e. the Phoenix app was not created using the --umbrella setting, and there is no in_umbrella: true in the deps().

In the configuration (apps/phoenix_app/config/dev.exs) the code reloader responds to the following regexps:

config :phoenix_app, PhoenixAppWeb.Endpoint,
  live_reload: [
    patterns: [
      ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
      ~r"priv/gettext/.*(po)$",
      ~r"lib/phoenix_app_web/{live,views}/.*(ex)$",
      ~r"lib/phoenix_app_web/templates/.*(eex)$"
    ]
  ]

These seem to match any paths with the given suffixes, regardless of what appears in front (since the regular expression patterns do not start with a ^). Alas, that does not seem to work.

So what setting needs to be changed here exactly?

You might want to look at the reloadable_apps configuration of the CodeReloader: https://hexdocs.pm/phoenix/Phoenix.CodeReloader.html#reload!/1

(also make sure that you’re making a distinction in your head between the CodeReloader, which compiles and loads new versions of the beam files, and the phoenix_live_reload which triggers page refreshes when files change).

You might also want to take a look at exsync (which I am a maintainer of). You could probably use the reload_callback to trigger a page refresh:

Exsync will reload all path dependencies by default, unlike Phoenix.CodeReloader

4 Likes

That’s my point. Phoenix Code Reloader can do what you are asking for umbrellas, but not for path dependencies. Someone would have to generalize the existing code.

3 Likes

Thanks for bringing this up, and for the link to exsync. This has been an annoyance while developing the Oban ui for a long time now—it is an isolated set of live views and needs to be “hosted” in a proper Phoenix app. I resorted to symlinking to get reloading to work for modules, though “live reload” hasn’t worked at all.

I would imagine that the Phoenix live dashboard has similar development constraints.

1 Like

@sorentwo we start a single file Phoenix application for the dashboard and we configured it with code reloading, so things work fine there: https://github.com/phoenixframework/phoenix_live_dashboard/blob/master/dev.exs

1 Like

Thank you, it was not immediately clear to me that you expected changes to the code itself to be required.

After looking at the implementation, especially here(where the Endpoint’s :reloadable_apps configuration is read) and here (where the default fallback is set, that has a special case for an umbrella application) I figured out that manually setting this configuration to [:phoenix_app] (e.g. the name of your OTP application that runs phoenix) will make the code reloader work:

config :phoenix_app, PhoenixAppWeb.Endpoint,
  # ... other settings here,
  # ... with at the end:
  reloadable_apps: [:phoenix_app]

(See also this commit on the example repository.)

This does not do the live code reloading yet (and I’ll investigate further to figure that out), but at least it will load the new code after a page refresh, which might be good enough for some applications.

2 Likes

Of course you did https://www.youtube.com/watch?v=TslkdT3PfKc

Great idea! I did something very similar for test mode, but I neglected to try it for dev. So much to learn from phoenix_live_dashboard :yellow_heart:

2 Likes