Subscribe to access all episodes. View plans →

#138: Upgrading to Phoenix 1.6

Published October 19, 2021

Phoenix 1.6 announcement

Chris McCord’s upgrade guide


Phoenix 1.6 was released including many new great features like new authentication and mail generators, webpack free asset building with esbuild, and the new LiveView HEEx engine. In this episode let’s update an existing Phoenix 1.5 application to 1.6. To do this we’ll be working from Chris McCord’s upgrade guide here.

Alright, let’s get started. The first thing we’ll want to do is open our Mixfile and we’ll need to bump the versions of a few dependencies. We’ll update phoenix to 1.6, phoenix_live_view to 0.16.4, phoenix_html to 3.0, phoenix_live_dashboard to 0.5, telemetry_metrics to 0.6, and telemetry_poller to 0.5. Then let’s include esbuild to use the new way to build assets.

mix.exs

defmodule Teacher.MixProject do
...
defp deps do
  ...
  {:phoenix, "~> 1.6"},
  {:phoenix_live_view, "~> 0.16.4"},
  {:phoenix_html, "~> 3.0"},
  {:phoenix_live_dashboard, "~> 0.5"},
  {:telemetry_metrics, "~> 0.6"},
  {:telemetry_poller, "~> 0.5"},
  {:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
  ...

end
end

With those updates let’s go to the command line and download our new dependencies with mix deps.get.

$ mix deps.get
...
Upgraded:
  phoenix 1.5.13 => 1.6.0
  phoenix_html 2.14.3 => 3.0.4 (major)
  phoenix_live_dashboard 0.4.0 => 0.5.3 (minor)
  phoenix_live_view 0.15.1 => 0.16.4 (minor)
  telemetry_metrics 0.6.0 => 0.6.1
New:
  castore 0.1.12
  esbuild 0.3.2
  phoenix_view 1.0.0

Now with our new version of Phoenix LiveView we get the new HEEx templating language, which enforces proper HTML and provides conveniences for rendering components, which we’ll look at later. To use use the new .heex templates we’ll rename both .html.eex and .html.leex templates in our application to .html.heex. This step is optional and HEEx requires you to be running at least Elixir 1.12. Let’s check out version of Elixir great we’re using 1.12.3.

Now we just need to go through and update our templates to use the new .heex extension. I’ll update the form_component.html template here and to save time I’ll rename the other templates off-camera. Alright, all of the templates have been renamed to .html.heex. So now we can go to the command line and start our server.

$ mix phx.server
...

When we do we get a compilation error in lib/teacher_web/live/album_live/index.html.heex. At this stage we’ll need to follow the errors in our different templates and get them to work as .heex templates. So let’s open that index.html.heex template. And here we’re rendering the album.id in this HTML tag. But with .heex templates we can no longer use this syntax for interpolating Elixir code within HTML tags. Instead we’ll update this to wrap our code in {...}.

Template path: lib/teacher_web/live/album_live/index.html.heex

...
<tr id="album-{album.id}">
...

Then let’s try to start our server again and we get another error, this time in our form_component.html.heex. Let’s open that.

Our form needs to be updated. Phoenix LiveView provides a function component named form which we can invoke with a leading dot. Then let’s re-write the rest of our form.

Template path: lib/teacher_web/live/album_live/form_component.html.heex

...
<.form 
  let={f} 
  for={@changeset} 
  id="album-form"
  phx-target={@myself} 
  phx-change="validate"
  phx-submit: "save">

  <%= label f, :artist %>
  <%= text_input f, :artist %>
  <%= error_tag f, :artist %>

  <%= label f, :title %>
  <%= text_input f, :title %>
  <%= error_tag f, :title %>

  <%= label f, :summary %>
  <%= textarea f, :summary %>
  <%= error_tag f, :summary %>

  <%= label f, :year %>
  <%= number_input f, :year %>
  <%= error_tag f, :year %>

  <%= submit "Save", phx_disable_with: "Saving..." %>
</.form>
...

With our form updated, let’s try to restart our server again. When we do we get an error in the root.html.heex so let’s open that, and we just need to update the asset paths to use the new {...} syntax.

Template path: lib/teacher_web/templates/layout/root.html.heex

...
<link rel="stylesheet" href={Routes.static_path(@conn, "/css/app.css")}/>
<script defer type="text/javascript" src={Routes.static_path(@conn, "/js/app.js")}></script>
...

Now when we go back to the command line and start our server we don’t get any more compilation errors, but we do a warning that our esbuild version is not configured. Let’s do that now. Let’s go ahead and remove our webpack config and node files.

$ rm assets/webpack.config.js assets/package.json assets/package-lock.json assets/.babelrc
$ rm -rf assets/node_modules

Then let’s open our config.exs and I’ll paste in the esbuild config.

config/config.exs

...
config :esbuild,
  version: "0.12.18",
  default: [
  args: ~w(js/app.js --bundle --target=es2016 --outdir=../priv/static/assets),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
  ]
...

Then let’s open dev.exs config and in the config for our Endpoint we’ll update the watchers section to remove node and replace it with esbuild.

config/dev.exs

...
config :teacher, TeacherWeb.Endpoint,
  ...
  watchers: [
    esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
  ]
...

Now let’s go back to our Mixfile and add a new assets.deploy mix task we can use to compile and serve assets in production.

mix.exs

...
defp aliases do
  [
  ...
  "assets.deploy": ["esbuild default --minify", "phx.digest"]
  ]
end
...

Then we need to update our CSS and JavaScript to use the new assets prefix, so we’ll go back to the root.html.heex template and update it to use assets.

Template path: lib/teacher_web/templates/layout/root.html.heex

...
<link phx-track-static rel="stylesheet" href={Routes.static_path(@conn, "/assets/app.css")}/>
<script defer phx-track-static type="text/javascript" src={Routes.static_path(@conn, "/assets/app.js")}></script>
...

Now we have one more step. Let’s open the endpoint.ex module. And update our Plug.Static to use the new assets directory. And we can remove the css and js directories since we won’t need them.

lib/teacher_web/endpoint.ex

defmodule TeacherWeb.Endpoint do
...

plug Plug.Static,
  at: "/",
  from: :teacher,
  gzip: false,
  only: ~w(assets fonts images favicon.ico robots.txt)

...
end

Let’s start the server. And great everything starts up without any errors or warnings.

$ mix phx.server
...

And if we go back to the browser and everything looks great. Our app seems to be working. But if we go to add an album, it looks like we get an error: “LiveView expects stateful components to have a single static HTML tag at the root”. This is a change we’ll have to potentially make to any stateful components we have, but fortunately we just have one in this app.

We’ll open our form_component.html.heex. And we can see there’s not a single HTML tag at the root, so let’s update that.

Template path: lib/teacher_web/live/album_live/form_component.html.heex

<div>
...
</div>

Now if we go back to the browser - great our page is working. Our app is now upgraded to use Phoenix 1.6.

© 2024 HEXMONSTER LLC