Phoenix doesn't compile on save

Hi all, I’m having a strange issue when running a Phoenix project. This issue is only impacting me, not my coworkers, and it’s only happening in this specific repo, I can’t reproduce it with a fresh Phoenix install.

With mix phx.server running, if I save a file in my editor, the changes don’t get picked up or compiled and the page I’m viewing doesn’t get reloaded. If manually refresh the page in my browser, my terminal then begins to compile and, once complete, the page finishes loading with my changes. The template files definitely match the live_reload config in dev.exs.

I removed all Elixir-related extensions in my editor (VS Code), so I don’t think something is compiling my files in the background. Any thoughts?

In a strange turn of events, I think I solved my own issue. I noticed that phoenix_live_reload released v1.3.0 back in November, but the README still recommended {:phoenix_live_reload, "~> 1.2"}. I bumped that to v1.3 in my mix.exs file, ran mix deps.get, then ran mix phx.server and live reload was working as expected.

Out of curiosity, I went back to v1.2, ran mix deps.get, and ran mix phx.server, and live reload is still working. I’m not really sure what happened here, but it’s now working. The strange thing is that when I first noticed the issue, I fully removed the project (mix ecto.drop && rm -rf my_app), re-cloned the project, and went through the installation steps to make sure there wasn’t some weird compilation/installation issue. I’m guessing that is what happened, but more than once?

Anyway, happy to have this resolved! :duck:

2 Likes

I’m experiencing similar issue for a quite some time now and will appreciate any help in debugging!

Not even sure why this started to happen in the first place (when I was on Phoenix 1.5.7).
For context: I tried every trick I could find on this forum to no success (eg. removing all deps, _build, node_modules, *-lock files both for Elixir and JS and even upgrading to Webpack-5.x and latest phoenix, live_view and live_reload versions).

Also increased the inotify watchers limit to 524288 - didn’t help.
All the live_reloader settings seem to be standard (never changed).

Note: the recompiling on save and live-reloading works as expected on the same machine when I create a fresh new phx live app. However, removing my main app and cloning from remote repo, does not help and I’m stuck with the broken live-reloading.

The Webpack-5 does log “compiled successfully…” on every save (but only app.js and app.css), yet nothing else happens (i.e. no reloads), and changes are visible only after manual refresh of page.

My editor: latest VS-code
My environment:
MX-Linux 19 - Debian GNU/Linux 10 (buster)
Elixir 1.12.0 (compiled with Erlang/OTP 24)

Please share any ideas on how could i debug this.

Phoenix doesn’t actually do a recompile on save, it does a recompile when a new HTTP request is made and there are uncompiled changes.

Now, your javascript / css assets may have some library you can pull in that will reload changes any time a CSS file changes but that’s distinct from phoenix.

Thanks. How can I find why Phoenix stopped recompiling? ie. why phoenix_live_reload no longer works as it did?

Phoenix live reload has never worked the way you are claiming, it has always required a reload. Maybe you had an extra vs-code extension at one point that worked differently?

1 Like

As a quick followup: To be clear, live reloading elixir code has never worked the way you are claiming. Live reloading of assets should work on save. See the distinction between Phoenix.CodeReloader — Phoenix v1.5.9 and Phoenix.LiveReloader — Phoenix Live-Reload v1.3.1

2 Likes

Well, in a freshly created phoenix app (–live), the code does get recompiled when I change (save) any of .ex .eex .leex .css files, and the browser auto-refreshes.

I don’t have any live reloading extension enabled in the VS-code.
So, how do I find the reason why the reloading stopped working in my other app (developed on the same machine/editor)?

UPDATE: I disabled all the extensions in my VS-Code, but the behavior persists as described above.
Appreciate any pointers to debug this!

Interesting, this is not the behavior I see. Here are the steps I took:

mix phx.new blah
cd blah && mix deps.get && npm install && mix ecto.setup
mix phx.server

Then I loaded localhost:4000 and edited lib/blah_web/controllers/page_controller.ex to be:

defmodule BlahWeb.PageController do
  use BlahWeb, :controller

  def index(conn, _params) do
    IO.puts "yo"
    render(conn, "index.html")
  end
end

When I hit save, I looked at the logs, and no additional requests were made, nor was "yo" printed. Then I went to the localhost:4000 tab in my browser, refreshed, and saw this message: Compiling 1 file (.ex).

Let me see if it is different if I use --live.

2 Likes

Aha! It is indeed different if I do --live (EDIT: sort of). Here are the steps I took:

mix phx.new blah --live
cd blah && mix deps.get && npm install && mix ecto.setup
mix phx.server

Then I loaded localhost:4000 and edited lib/blah_web/live/page_live.ex to have IO.puts "yo" in the def mount function. This DID trigger a live reload, cool! So let’s see what’s different between the project config.

Interestingly, both projects have the same config:

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

So in some sense both projects work the same way: controllers and your regular lib/my_app/* files are not live reloaded, but live views and regular views are live reloaded.

Can you post the config for your project? Which files are you editing and not seeing live reloading for?

5 Likes

Here it is from dev.exs (looks similar):

# Watch static and templates for browser reloading.
config :dbest, DbestWeb.Endpoint,
  live_reload: [
    patterns: [
      ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
      ~r"priv/gettext/.*(po)$",
      ~r"lib/dbest_web/(live|views)/.*(ex)$",
      ~r"lib/dbest_web/templates/.*(eex)$"
    ]
  ]

And just in case, all my deps from mix.exs:

      {:bcrypt_elixir, "~> 2.0"},
      {:phoenix, "~> 1.5.9"},
      {:phoenix_ecto, "~> 4.2.1"},
      {:ecto_sql, "~> 3.6.1"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_live_view, "~> 0.15.7"},
      {:floki, ">= 0.30.1", only: :test},
      {:phoenix_html, "~> 2.14.3"},
      {:phoenix_live_reload, "~> 1.3.1", only: :dev},
      {:phoenix_live_dashboard, "~> 0.4.0"},
      {:phx_gen_auth, "~> 0.7.0", only: [:dev], runtime: false},
      {:telemetry_metrics, "~> 0.6.0"},
      {:telemetry_poller, "~> 0.5.1"},
      {:gettext, "~> 0.18.2"},
      {:jason, "~> 1.2.2"},
      {:plug_cowboy, "~> 2.5.0"},
      {:faker, "~> 0.16.0", only: [:dev, :test]},
      {:bamboo, "~> 2.1.0"},
      {:decimal, "~> 2.0"},
      {:email_guard, "~> 1.2.0"}

Actually, none of the files (when changed) trigger a live reload in the browser anymore.

In your endpoint.ex file what happens if you change this line:

if code_reloading? do

to this:

if code_reloading? |> IO.inspect(label: :code_reloading) do

Sorry for late reply (was away from my PC). So after changing that line here’s the logs:

❯ iex -S mix phx.server
Erlang/OTP 24 [erts-12.0.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]

Compiling 2 files (.ex)
code_reloading: true
[info] Running DbestWeb.Endpoint with cowboy 2.9.0 at 0.0.0.0:4000 (http)
[info] Access DbestWeb.Endpoint at http://localhost:4000
Interactive Elixir (1.12.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 
> watch
> NODE_ENV=development webpack --mode development --watch

Then when I tried to change page_live.ex or root.html.leex I only get the Webpack recompiling logs:

assets by status 222 KiB [cached] 2 assets
Entrypoint app 222 KiB (340 KiB) = ../css/app.css 46.5 KiB app.js 175 KiB 1 auxiliary asset
cached modules 170 KiB (javascript) 46.5 KiB (css/mini-extract) 937 bytes (runtime) [cached] 11 modules
./css/app.css 50 bytes [built]
webpack 5.38.1 compiled successfully in 436 ms
assets by status 175 KiB [cached] 1 asset
asset ../css/app.css 46.6 KiB [emitted] (name: app)
Entrypoint app 222 KiB (340 KiB) = ../css/app.css 46.6 KiB app.js 175 KiB 1 auxiliary asset
cached modules 170 KiB (javascript) 89 bytes (css/mini-extract) 937 bytes (runtime) [cached] 10 modules
modules by layer 50 bytes (javascript) 46.5 KiB (css/mini-extract)
  ./css/app.css 50 bytes [built]
  css ./node_modules/css-loader/dist/cjs.js!./node_modules/postcss-loader/dist/cjs.js!./css/app.css (1) 46.5 KiB [code generated]
webpack 5.38.1 compiled successfully in 318 ms

So, I see the code_reloading: true printed once on startup and never again.

What version of file_system (dependency of phoenix_live_reload) are you using? Maybe try switching to the latest version. One potential fix you might need is:

You might also want to make sure you’re using your distros latest version of inotify: Home · inotify-tools/inotify-tools Wiki · GitHub

1 Like

Thanks for taking a look! my mix.lock file shows the latest version is used:
..."file_system": {:hex, :file_system, "0.2.10"...

And the latest inotify-tools is installed on OS.
This issue is persistent only in the main app (with deps listed above), while everything works in a freshly created test Phoenix app.
Any ideas where to look for hints in the app under development?

I copy-pasted and installed all the deps from my current (problematic) project to a freshly created test Phoenix app.

Result: Nothing changed, i.e. those deps did not break the well-functioning live-reloading in the test app.

Note: some of those deps were simply installed but not used in the test app.

This mystery magic is quite frustrating.

Do you have any specific VSCode workspace settings? Check the .vscode folder at your project root.

I had this and nothing seems criminal .vscode/settings.json:

{
  "spellright.language": [
    "English_US"
  ],
  "spellright.documentTypes": [
    "latex",
    "nunjucks",
    "markdown",
    "plaintext"
  ],
  "spellright.parserByClass": {
    "nunjucks": {
      "parser": "xml"
    }
  },
  "css.validate": false,
  "less.validate": false,
  "scss.validate": false
}

now I nuked that folder entirely and restarted the phx.server but the issue persists.

This is seeming quite odd at this point. Could you either share the repo or create a reproducible example? Does this happen on other computers as well?