Skip to content

Instantly share code, notes, and snippets.

@chrismccord
Last active February 24, 2024 13:56
Show Gist options
  • Star 64 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save chrismccord/2ab350f154235ad4a4d0f4de6decba7b to your computer and use it in GitHub Desktop.
Save chrismccord/2ab350f154235ad4a4d0f4de6decba7b to your computer and use it in GitHub Desktop.

Phoenix 1.5.x to 1.6 upgrade instructions

Update your deps

In mix.exs, update your phoenix, phoenix_html, telemetry_metrics, telemetry_poller and phoenix_live_dashboard deps, and add phoenix_live_view:

def deps do
    [
      {:phoenix, "~> 1.6.0"},
      ...
      {:phoenix_html, "~> 3.0"},
      {:phoenix_live_view, "~> 0.16.4"},
      {:phoenix_live_dashboard, "~> 0.5"},
      {:telemetry_metrics, "~> 0.6"},
      {:telemetry_poller, "~> 0.5"},
      ...
    ]
end

Next, run mix deps.get to grab your new deps.

Rename your .html.eex and .html.leex templates to .html.heex (optional)

While leex templates have been deprecated, this step is optional. For the most part, existing templates should continue to work, but the HTML-aware HEEx engine will enforce valid markup and is more strict in the elixir expressions that appear within an open and closing tag. For example, the following code will raise:

<div id="<%= @id %>">

Instead of the standard <%= %> EEx expressions, elixir expressions inside tags can only appear withing {}, such as:

<div id={@id}>

<%= %> expressions remain valid outside of HTML tags in the EEx engine.

To update your existing templates, rename all your .html.eex and .html.leex templats to .html.heex and follow the parser errors to find any tags that require the new {} attribute form.

Also be sure to review the HEEx documentation for more information on features.

Migrate to esbuild for js and css bundling (optional)

Phoenix's watchers configuration is build-tool agnostic, so you may continue to enjoy your existing webpack configurations generated by phoenix 1.5 or earlier. If only have basic js and css needs and you would like to take advantage of our new esbuild usage, for a dependency-free asset builder powered by a portably binary, follow these steps:

First delete your webpack config and related node files:

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

Next, add the esbuild mix dep to your mix.exs deps:

def deps do
  [
    ...
    {:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
  ]
end

Next, configure esbuild in config/config.exs:

# Configure esbuild (the version is required)
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__)}
  ]

Next, replace the node watcher with esbuild in your endpoint watcher config in config/dev.exs:

config :demo, DemoWeb.Endpoint,
  ...,
  watchers: [
    # Start the esbuild watcher by calling Esbuild.install_and_run(:default, args)
    esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}
  ]

Next, add a new assets.deploy mix alias in your mix.exs for easy asset building:

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

Running $ mix assets.deploy will download the esbuild binary on first run and then build your assets:

$ mix assets.deploy
21:40:37.588 [debug] Downloading esbuild from https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.12.18.tgz

  ../priv/static/assets/app.css  9.7kb
  ../priv/static/assets/app.js   1.3kb

⚡ Done in 12ms
Check your digested files at "priv/static"

Next, update your layouts, such as app.html.heex or root.html.heex to use the new assets prefix instead of js/app.js and css/app.css:

    <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>

Finally, update your Plug.Static :only options in your lib/app_web/endpoint.ex to be aware of the new assets directory:

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

Could you please mention to add the following to config/test.exs:

# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime

@Edward-Ta
Copy link

Edward-Ta commented Nov 2, 2021

Could you please mention to add the following to config/test.exs:

# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime

https://github.com/phoenixframework/phoenix/blob/v1.5/CHANGELOG.md#1510-2021-08-06
Would he need to add it if it has been specified in the v1.4 -> v1.5 official changelog

@marcandre
Copy link

marcandre commented Nov 2, 2021

@Edward-Heales good point, I missed that completely when I upgraded from 1.5.9 to 1.6.x. I'd say it is unfortunate that a change in the source is required on a patch-level release and that it wouldn't hurt to repeat this here in the upgrade guide. As of now, this is not listed in any upgrade guide.

@Edward-Ta
Copy link

@marcandre Agreed.

@sweeneydavidj
Copy link

To better deal with files referenced in CSS or JavaScript there was a small change released in Phoenix 1.6.1
Add external flag to esbuild for fonts and images

@marcandre
Copy link

It should be noted that any package added to package.json/.lock needs to be re-added after these files are deleted.

@marcandre
Copy link

Also, target=2016 is quite possible the wrong setting, see phoenixframework/phoenix#4579

@marcandre
Copy link

marcandre commented Nov 25, 2021

Also, same line is missing --external:/fonts/* --external:/images/*, see phoenixframework/phoenix@19ec3c6

@marcandre
Copy link

marcandre commented Nov 26, 2021

IIUC, we should move images and other static assets to priv/static, e.g. mv assets/static/images assets/static/fonts assets/static/video assets/static/docs assets/static/favicon.ico assets/static/robots.txt priv/static, and modify our .gitignore to no longer ignore /priv/static/ but to ignore both /priv/static/assets/ and /priv/static/cache_manifest.json, right?

@kaikuchn
Copy link

IIUC, we should move images and other static assets to priv/static, e.g. mv assets/static/images assets/static/fonts assets/static/video assets/static/docs assets/static/favicon.ico assets/static/robots.txt priv/static, and modify our .gitignore to no longer ignore /priv/static/ but to ignore both /priv/static/assets/ and /priv/static/cache_manifest.json, right?

That's partially correct. You should unignore priv/static and ignore priv/static/assets [1] but you don't need to ignore the cache manifest file since that is the result of phx.digest which should only be run for deployment. After running mix assets.deploy locally you can clean up the phx.digest artifacts using mix phx.digest.clean --all.

[1] https://www.reddit.com/r/elixir/comments/p9t68v/with_the_new_esbuild_transition_what_do_you_use/ha0cskv/?context=3

@marcandre
Copy link

marcandre commented Jan 14, 2022

Thanks @kaikuchn, you are right.
I feel frustrated that we can't improve these instructions yet

@florish
Copy link

florish commented Feb 2, 2022

After doing a couple of Phoenix 1.5 to 1.6 upgrades in the last few weeks, I've found that a diff between the phx.new code from 1.5.0 and 1.6.6 can be very helpful as an extra check to see that you did not miss anything:

https://utils.zest.dev/gendiff/phx_new/62953723EA6DCD4A95D027D4EB99CBAA

Note that some phx.new code has been changed between 1.6.0 and 1.6.6 to fix minor bugs (e.g. es2016 has been replaced with es2017 as the target in the esbuild Elixir config). This all happened after this Gist was published, but is quite relevant in case you are planning a Phoenix 1.6 upgrade right now.

To be sure: most of what is in the diff above is covered in the comments in this Gist, but it can help to see all these changes in one place.

@arfl
Copy link

arfl commented Feb 2, 2022

@florish
Copy link

florish commented Feb 2, 2022

@arfl Hey that's even better! For my understanding: apart from the layout, the diff content is the same as for the link I posted, isn't it?

@arfl
Copy link

arfl commented Feb 3, 2022

@florish I do not know exactly, but the source code is on github (link to github repo in the right upper corner of the app). Seems that they just generate two versions of the app using the --live option and call this code to generate the diff.

@pinksynth
Copy link

Very helpful! Noticed a typo: assetes instead of assets:

rm -rf assetes/node_modules

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment