Phoenix 1.6.0-rc.0 released!

I’m pleased to announce the first release candidate of Phoenix 1.6.0 has landed on the heels of a fresh LiveView 0.16 release! This release brings a number of major additions, quality of life improvements, bug fixes, and a couple deprecations. You can grab the rc phx.new generator with the following command:

$ mix archive.install hex phx_new 1.6.0-rc.0

New authentication and mailer generators

Thanks to efforts by José Valim and Aaron Renner, Phoenix 1.6 ships with a new phx.gen.auth command for a complete authentication solution bootstrapped into your application. You can read about the design decisions behind the authentication generators in José’s post on the Dashbit blog. Phoenix also now includes swoosh by default for mailer support and a new phx.gen.notifier task for generating a notifier for sending email along with a dev mailbox for local development.

New LiveView HEEx engine

In addition to the generators, Phoenix LiveView 0.16 was just released with a new HTML engine (HEEx, ~H) for HTML-aware template compilation which you’ll see utilized in all phoenix generated HTML files going forward (phx.new, phx.gen.html, phx.gen.live, etc). The new engine not only enforces proper HTML, but provides syntax conveniences for rendering components, such as <.form for={@user} id="user-form">. This new engine is thanks to Marlus Saraiva’s excellent work that he extracted from his wonderful Surface library, which builds features on top of Phoenix LiveView. We look forward to seeing where each project can continue to innovate and share back as we work towards new engine features. With the HTML engine and function components in place, we have the layed the groundwork for a vibrant ecosystem of shared and resuable components. You can follow along the HEEx roadmap to stay up to date on our feature plans. For now, here’s a quick rundown on HEEx from the Phoenix LiveView docs to bring folks up to speed:

Note: HEEx requires Elixir >= 1.12.0 in order to provide accurate
file:line:column information in error messages. Earlier Elixir versions will
work but will show inaccurate error messages.

HEEx is a HTML-aware and component-friendly extension of EEx that provides:

  • Built-in handling of HTML attributes
  • An HTML-like notation for injecting function components
  • Compile-time validation of the structure of the template
  • The ability to minimize the amount of data sent over the wire

Example

~H"""
<div title="My div" class={@class}>
  <p>Hello <%= @name %></p>
  <MyApp.Weather.city name="Kraków"/>
</div>
"""

Syntax

HEEx is built on top of Embedded Elixir (EEx), a templating syntax that uses
<%= ... %> for interpolating results. In this section, we are going to cover the
basic constructs in HEEx templates as well as its syntax extensions.

Interpolation

Both HEEx and EEx templates use <%= ... %> for interpolating code inside the body
of HTML tags:

<p>Hello, <%= @name %></p>

Similarly, conditionals and other block Elixir constructs are supported:

<%= if @show_greeting? do %>
  <p>Hello, <%= @name %></p>
<% end %>

Note we don’t include the equal sign = in the closing tag (because the closing
tag does not output anything).

There is one important difference between HEEx and Elixir’s builtin EEx.
HEEx uses a specific annotation for interpolating HTML tags and attributes.
Let’s check it out.

HEEx extension: Defining attributes

Since HEEx must parse and validate the HTML structure, code interpolation using
<%= ... %> and <% ... %> are restricted to the body (inner content) of the
HTML/component nodes and it cannot be applied within tags.

For instance, the following syntax is invalid:

<div class="<%= @class %>">
  ...
</div>

Instead do:

<div class={@class}>
  ...
</div>

For multiple dynamic attributes, you can use the same notation but without
assigning the expression to any specific attribute.

<div {@dynamic_attrs}>
  ...
</div>

The expression inside { ... } must be either a keyword list or a map containing
the key-value pairs representing the dynamic attributes.

HEEx extension: Defining function components

Function components are stateless components implemented as pure functions
with the help of the Phoenix.Component module. They can be either local
(same module) or remote (external module).

HEEx allows invoking whose function components directly in the template
using an HTML-like notation. For example, a remote function:

<MyApp.Weather.city name="Kraków"/>

A local function can be invoked with a leading dot:

<.city name="Kraków"/>

where the component could be defined as follows:

defmodule MyApp.Weather do
  use Phoenix.Component

  def city(assigns) do
    ~H"""
    The chosen city is: <%= @city %>.
    """
  end

  def country(assigns) do
    ~H"""
    The chosen country is: <%= @country %>.
    """
  end
end

It is typically best to group related functions into a single module, as
opposed to having many modules with a single render/1 function. You can
learn more about components in Phoenix.Component.

New LiveView server lifecycle hooks

Thanks to work by Michael Crumm on the Phoenix team, LiveView 0.16 introduces on_mount and attach_hook hooks which provide a mechanism to tap into key stages of the LiveView lifecycle. This allows developers to bind/update assigns, intercept events, patches, and regular messages when necessary, and to inject common functionality. Hooks may be attached to any of the following lifecycle stages: :mount (via on_mount/1), :handle_params, :handle_event, and :handle_info.

New LiveView live_session for optimized navigation

LiveView 0.16 also introduces the live_session macro in the router to group live routes together. This allows all live navigation through live redirects to happen over the existing websocket connection. This avoids an extra HTTP round trip to the server and provides an extremely fast navigation experience because an HTTP handshake is no longer necessary at all. The live_session also allows a life-cycle on_mount hook to be provided, allowing LiveViews to share common code paths such as authentication without needing to specificy the hooks on every module.

Node and webpack free asset building with esbuild

In addition to the new HTML engine, we’ve also had a major change on the way the phx.new project generators handles assets. We have dropped webpack and node entirely from the equation. You can now build your js and css bundles without having node or npm on your system! The biggest support issues for Phoenix over the years has revolved around node tooling, breaking changes, and often times unnecessary churn. By using esbuild, projects can utilize a portable binary for multiplatform, dependency-free asset building that is fast and Just Works/tm. Five years from now you shouldn’t been afraid to make some changes to a js or css file and find your tooling has broken underneath you. Advanced front-end users can continue to take advantage of the webpack tooling that suits their work-flows, but we hope this dependency-free solution brings more “peace of mind” around assets, per the Phoenix tagline :). Big thanks to Brian Cardarella of DockYard and Max Veytsman on the Phoenix team for spelunking through our js options and experimenting with solutions, along with Wojtek Mach for heading up the portable binary esbuild extraction. Also shout out to José for writing some go and JavaScript PRs for various tools to handle mix shutdown without zombie processes.

This release also extracts Phoenix.View into its own library phoenix_view, so non-web users can make use of Phoenix’s view rendering without bringing in all of Phoenix.

As always, step-by-step upgrade guides can be found here.

You can also view the full changelog for more details.

Find us on elixir slack or the forums if you need help. Happy coding!

–Chris

143 Likes

Congrats on the release!

1 Like

Congratulations and big thanks @josevalim and @chrismccord and numerous others who made very important contributions.
Without a doubt, the goto framework for building web applications in 2021. Hope all of us can make the framework spread one more level down the pyramid.

3 Likes

Congrats to all the contributors on getting 1.6.0 RC.0 released, this is an exciting release bringing a lot of polish, consistency and significant dev quality of life improvements. Looking forward to checking it out.

1 Like

Congratulations, great work as we have become so spoiled with. However, having played around with esbuild over the last few days, for me this is a major step back. I use fairly customised way of dealing with JS assets (I need me some coffeescript) and I did get some
of that to work using a build.js script. However now all my import statements fail with highly impenetrable error messages like:

Could not resolve “phoenix_html” (mark it as external to exclude it from the bundle)

I have no idea how to even investigate let alone remedy this, and no amount of fiddling with target or platform settings in esbuild seems to help. Anyone?
Bottom line is it looks like I will have to stick with Webpack as it did everything I needed and I esbuld appears incapable of emulating this.

1 Like

It probably does not find your deps folder.

Esbuild is a major improvement for people starting fresh with Phoenix and having no clue about webpack and friends.
For everyone else it is totally fine if you still use webpack.

2 Likes

The goal of the switch to esbuild was not to replace webpack for everyone. It‘s not meant to become the default for everyone. It‘s meant to be a more sane default, which doesn‘t break the generators every few month.

If you have needs beyond the capabilities of esbuild I‘d say going with webpack is even the more appropriate path given the sheer number of resources around it.

5 Likes

Thanks, so it is a given esbuild is more of a ‘my first asset-builder’ tool, inherently less capable and customisable than webpack and others? I must say I did not see that coming, it seems a really odd choice to migrate towards then. It will cause a fork of sorts and will perhaps create more support issues rather than fewer (which appears to be the main motivation for this switch).

Hmm… less capable … less customisable - is not how the decision has been taken. I think @josevalim explained that - how the Phoenix team wants to control the overall experience for a first time user of the framework.
If you really look at the Rails framework - Webpacker, Sprockets, Redis, Ruby-Sass - so many moving parts - and- the overall experience can fail from any of the ecosystem components.
Now, in Phoenix, once elixir is installed, there is no way a beginner will fail to launch his dev server. Even the asset management is handled by a single binary esbuild - which is also packaged by the framework itself.
I found the decision to be very rational.
The recent decision by DHH https://twitter.com/dhh/status/1427271518615130115 to move away from webpack in Rails 7 indicates that same problems are faced by all frameworks. The Javascript ecosystem should be an opt-in rather than enforced upon.

If I saw it right - at one place @chrismccord stated that - developer is free to invite pain rather than inherit pain. Beautifully put. :slight_smile:

Finally, the documentation Asset Management — Phoenix v1.6.0-rc.0 contains a step-by-step process to integrate the Javascript ecosytem for the needy.

11 Likes

I am not inviting any pain, I just want to use coffeescript and slim (like I always have) instead of curly braces and eex, which I both hate with the passion of a thousand suns. Talk about inviting pain, it is all relative you see.

But if esbuild forces me to use those defaults (which I still find hard to believe) I will stick with the things that work for me.

Edit: FYI I did follow that doc guide and it left me with the failing import statements.

1 Like

Agreed. We have to work with the tools that keep us productive. I respect your view on that.

2 Likes

And the beauty in phoenix is that you can easily do so. I‘d expect that far fewer people will switch from their existing pipelines to esbuild than for the last asset pipeline switch from brunch to webpack. It‘s just no longer the phoenix teams problem if things break, which it should never really have been in the first place.

16 Likes

Can someone speak to the “advanced features” that we would be missing from webpack? From my understanding, esbuild can replace webpack, so why wouldn’t one not be able to use Coffeescript or Slime? I’ve been really looking forward to this release specifically for esbuild and heex.

Well, I’m sort of answering my own question now that I’m RTFM’ing :sweat_smile:(like some packages need node to run which, ya, duh me). But I wouldn’t mind hearing specific experiences switching to esbuild if anyone is willing to share.

Congrats to all contributors for maintaining this amazing framework

1 Like

Just updated my app to Phoenix 1.6.0-rc.0. Went pretty smoothly, even though I had to bump Elixir to 1.12 (updating Dockerfile, etc.). I started off without Webpack and had my hand-rolled esbuild pipeline, but having it wrapped with an Elixir package is sweet.

One thing that I had to figure out was how to manage static assets. With the new setup:

  • Put static assets straight into /priv/static,
  • Build tools build assets into /priv/static/assets which is .gitignored.

If you want to throw TailwindCSS/UI and/or Alpine into the mix, here’s @josevalim’s approach.

Here’s a diff of a fresh project generated with 1.5 vs 1.6.

5 Likes

I think you are OK as long as you don’t have to rely on a build.js script as described here.

I managed to figure out that you also need a NODE_PATH=../deps environment variable and then esbuild will see the phoenix js modules, but then I get stuck on this error:

deps/phoenix_live_view/assets/js/phoenix_live_view/dom_patch.js:20:21: error: Could not resolve "morphdom" (mark it as external to exclude it from the bundle)

I can see that morphdom is one of the dependencies in phoenix_live_view but how does esbuild ensure it gets installed? Oh how I dislike javascript.

@LostKobrakai already answered our motivations and the benefits very well, but I want to point out that folks are free to continue to use their favorite webpack configuration (or any other build tool). Phoenix was never Webpack-aware, we simply generated the config for you. The phoenix endpoint watchers configuration will gladly start any cli’s for you, so by all means if webpack suits your workflow then continue to use it :slight_smile:

4 Likes

Thanks, this makes total sense. But regardless, when I setup a new 1.6 live app from scratch, follow the build.js instructions, without any further modifications or plugins, I run into the error I mentioned above.

Could not resolve “phoenix_html”

So I am sure there is still something missing there, I shall file a bug report on GitHub if this has not been done already.

Instant edit: @josevalim to the rescue! I love this stuff.

Second edit: finally all working now, but now run into

Dynamic require of “…” is not supported

So all in all I feel esbuild tries to pretend the messy world of javascript is not all that messy. I would be very surprised if this indeed leads to fewer support issues, but hopefully it does since it has no other benefits that I can see.