La version finale de Phoenix 1.7 est disponible ! Phoenix 1.7 contient un certain nombre de nouvelles fonctionnalités très attendues comme les routes vérifiées, le support de Tailwind, les générateurs d'authentification LiveView, les modèles HEEx unifiés, les flux LiveView pour des collections optimisées, et bien plus encore. Il s'agit d'une version rétrocompatible avec quelques dépréciations. La plupart des gens devraient être en mesure de mettre à jour juste en changeant quelques dépendances.
Note : Pour générer un nouveau projet 1.7, vous devrez installer le générateur phx.new de hex :
Code : | Sélectionner tout |
mix archive.install hex phx_new
Les routes vérifiées remplacent les router helpers par une approche basée sur les sigils (~p) et vérifiée à la compilation.
note : Les routes vérifiées utilisent les nouvelles fonctionnalités du compilateur Elixir 1.14. Phoenix supporte toujours les anciennes versions d'Elixir, mais vous devrez les mettre à jour pour profiter des nouvelles fonctionnalités de vérification à la compilation.
En pratique, cela signifie que là où vous utilisiez auparavant des fonctions autogénérées comme :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | # router get "/oauth/callbacks/:id", OAuthCallbackController, :new # usage MyRouter.Helpers.o_auth_callback_path(conn, :new, "github") # => "/oauth/callbacks/github" MyRouter.Helpers.o_auth_callback_url(conn, :new, "github") # => "http://localhost:4000/oauth/callbacks/github" |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | # router get "/oauth/callbacks/:id", OAuthCallbackController, :new # usage ~p"/oauth/callbacks/github" # => "/oauth/callbacks/github" url(~p"/oauth/callbacks/github") # => "http://localhost:4000/oauth/callbacks/github" |
Il y a aussi maintenant une correspondance 1:1 entre les routes que vous écrivez dans le routeur, et la façon dont vous les appelez avec ~p. Vous l'écrivez simplement comme si vous codiez des chaînes en dur partout dans votre application - sauf que vous n'avez pas les problèmes de maintenance qui viennent avec le codage en dur des chaînes. Nous pouvons obtenir le meilleur des deux mondes avec la facilité d'utilisation et de maintenance parce que ~p est une vérification à la compilation des routes dans votre routeur.
Par exemple, imaginons que nous fassions une faute de frappe sur une route :
Code : | Sélectionner tout |
<.link href={~p"/userz/profile"}>Profile</.link>
Code : | Sélectionner tout |
1 2 3 | warning: no route path for AppWeb.Router matches "/postz/#{post}" lib/app_web/live/post_live.ex:100: AppWeb.PostLive.render/1 |
Code : | Sélectionner tout |
~p"/posts/#{post.id}"
Les chaînes de requête sont également prises en charge dans les itinéraires vérifiés, soit sous la forme traditionnelle d'une chaîne de requête :
Code : | Sélectionner tout |
~p"/posts?page=#{page}"
Code : | Sélectionner tout |
1 2 3 | params = %{page: 1, direction: "asc"} ~p"/posts?#{params}" |
Une fois que vous aurez essayé cette nouvelle fonctionnalité, vous ne pourrez plus revenir aux router helpers. Les nouveaux générateurs phx.gen.html|live|json|auth utilisent des routes vérifiées.
Générateurs Tailwind basés sur des composants
Phoenix 1.7 est livré avec TailwindCSS par défaut, sans dépendance avec nodejs sur le système. TailwindCSS est le meilleur moyen que j'ai trouvé pour styliser les interfaces en 20 ans de développement web. Son approche axée sur l'utilité est bien plus facile à maintenir et plus productive que n'importe quel système ou framework CSS que j'ai utilisé. Son approche colocalisée s'aligne parfaitement avec le composant de fonction et le paysage LiveView.
L'équipe de Tailwind a également généreusement conçu la nouvelle page d'accueil du projet, les pages CRUD et les pages du système d'authentification pour les nouveaux projets, vous donnant un point de départ de première classe et poli pour la construction de vos applications.
Un nouveau projet phx.new contiendra un module CoreComponents, abritant un ensemble de composants d'interface utilisateur tels que des tables, des fenêtres modales, des formulaires et des listes de données. La suite de générateurs Phoenix (phx.gen.html|live|json|auth) utilise les composants de base. Cela présente un certain nombre d'avantages intéressants.
Tout d'abord, vous pouvez personnaliser les composants de base de l'interface utilisateur en fonction de vos besoins, de vos conceptions et de vos goûts. Si vous souhaitez utiliser Bulma ou Bootstrap au lieu de Tailwind, pas de problème ! Remplacez simplement les définitions de fonctions dans core_components.ex par vos implémentations spécifiques au framework/UI et les générateurs continuent à fournir un excellent point de départ pour de nouvelles fonctionnalités, que vous soyez un débutant ou un expert chevronné construisant des fonctionnalités de produit sur mesure.
En pratique, les générateurs vous donnent des modèles qui utilisent vos composants de base, qui ressemblent à ceci :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <.header> New Post <:subtitle>Use this form to manage post records in your database.</:subtitle> </.header> <.simple_form for={@form} action={~p"/posts"}> <input field={@form[:title]} type="text" label="Title" /> <input field={@form[:views]} type="number" label="Views" /> <:actions> <.button>Save Post</.button> </:actions> </.simple_form> <.back navigate={~p"/posts"}>Back to posts></.back> |
Composants de fonction unifiés pour les contrôleurs et les LiveViews
Les composants de fonction fournis par HEEx, avec des affectations et des emplacements déclaratifs, constituent un changement radical dans la manière dont nous écrivons du HTML dans les projets Phoenix. Les composants de fonction fournissent des blocs de construction de l'interface utilisateur, permettant aux fonctionnalités d'être encapsulées et mieux étendues par rapport à l'approche précédente des modèles dans Phoenix.View. Vous bénéficiez d'une manière plus naturelle d'écrire des balises dynamiques, d'une interface utilisateur réutilisable qui peut être étendue par l'appelant, et de fonctions de compilation qui font de l'écriture d'applications HTML une expérience de premier ordre.
Les composants de fonction apportent une nouvelle façon d'écrire des applications HTML dans Phoenix, avec de nouveaux ensembles de conventions. En outre, les utilisateurs ont eu du mal à combiner les fonctionnalités Phoenix.View basées sur les contrôleurs avec les fonctionnalités Phoenix.LiveView dans leurs applications. Les utilisateurs se sont retrouvés à écrire render("table", user : user) dans des modèles basés sur des contrôleurs, tandis que leurs LiveViews utilisaient les nouvelles fonctionnalités <.table rows={@users}>. Il n'existait pas de moyen efficace de partager les approches dans une application.
Pour ces raisons, l'équipe de Phoenix a unifié les approches de rendu HTML, que ce soit à partir d'une requête de contrôleur ou d'une LiveView. Ce changement nous a également permis de revoir les conventions et de nous aligner sur l'approche LiveView qui consiste à regrouper les modèles et le code de l'application.
Les nouvelles applications (et les générateurs phx) suppriment Phoenix.View en tant que dépendance en faveur d'une nouvelle dépendance Phoenix.Template, qui utilise des composants de fonction comme base pour tous les rendus dans le framework.
Vos contrôleurs restent les mêmes :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 | defmodule AppWeb.UserController do use MyAppWeb, :controller def index(conn, _params) do users = ... render(conn, :index, users: users) end end |
Tout le rendu HTML est alors basé sur des composants de fonction, qui peuvent être écrits directement dans un module, ou intégrés à partir d'un fichier externe avec la nouvelle macro embed_templates fournie par Phoenix.Component. Votre module PageHTML dans une nouvelle application ressemble à ceci :
Code : | Sélectionner tout |
1 2 3 4 5 | defmodule AppWeb.PageHTML do use AppWeb, :html embed_templates "page_html/*" end |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | lib/app_wb ├── controllers │ ├── page_controller.ex │ ├── page_html.ex │ ├── error_html.ex │ ├── error_json.ex │ └── page_html │ └── home.html.heex ├── live │ ├── home_live.ex ├── components │ ├── core_components.ex │ ├── layouts.ex │ └── layouts │ ├── app.html.heex │ └── root.html.heex ├── endpoint.ex └── router.ex |
En outre, nous avons placé les modules de vue à côté de leurs fichiers de contrôle. Cela présente les mêmes avantages que la colocalisation LiveView : les fichiers fortement couplés vivent ensemble. Les fichiers qui doivent changer ensemble vivent désormais ensemble, qu'il s'agisse d'écrire des fonctionnalités LiveView ou des fonctionnalités de contrôleur.
Ces changements avaient pour but d'améliorer l'écriture des applications HTML, mais ils ont également simplifié le rendu d'autres formats, comme JSON. Par exemple, les modules de vue basés sur JSON suivent les mêmes conventions - Phoenix cherchera d'abord une fonction index/1 lors du rendu du modèle d'index, avant d'essayer render/2. Cela nous a permis de simplifier le rendu JSON en général et de supprimer des concepts tels que Phoenix.View.render_one|render_many.
Par exemple, voici une vue JSON générée par phx.gen.json :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | defmodule AppWeb.PostJSON do alias AppWeb.Blog.Post @doc """ Renders a list of posts. """ def index(%{posts: posts}) do %{data: for(post <- posts, do: data(post))} end @doc """ Renders a single post. """ def show(%{post: post}) do %{data: data(post)} end defp data(%Post{} = post) do %{ id: post.id, title: post.title } end end |
Ces fonctionnalités fournissent un modèle de rendu unifié pour les applications qui vont de l'avant avec une manière nouvelle et améliorée d'écrire des interfaces utilisateur, mais elles s'écartent des pratiques précédentes. La plupart des grandes applications établies sont probablement mieux servies en continuant à dépendre de Phoenix.View.
Streams LiveView
LiveView comprend désormais une interface de flux permettant de gérer de grandes collections dans l'interface utilisateur sans avoir à stocker les collections en mémoire sur le serveur. Avec quelques appels de fonction, vous pouvez insérer de nouveaux éléments dans l'interface utilisateur, les ajouter ou les ajouter dynamiquement, ou les réorganiser sans les recharger sur le serveur.
Le générateur CRUD phx.gen.live live de Phoenix 1.7 utilise des flux pour gérer votre liste d'éléments. Cela permet la saisie de données, les mises à jour et les suppressions sans jamais avoir besoin de récupérer la liste des éléments après le chargement initial. Voyons comment.
Le module PostLive.Index suivant est généré lorsque vous exécutez mix phx.gen.live Blog Post posts title views:integer
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | defmodule DemoWeb.PostLive.Index do use DemoWeb, :live_view alias Demo.Blog alias Demo.Blog.Post @impl true def mount(_params, _session, socket) do {:ok, stream(socket, :posts, Blog.list_posts())} end ... end |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <.table id="posts" rows={@streams.posts} row_click={fn {_id, post} -> JS.navigate(~p"/posts/#{post}") end} > <:col :let={{_id, post}} label="Title"><%= post.title %></:col> <:col :let={{_id, post}} label="Views"><%= post.views %></:col> <:action :let={{_id, post}}> <div class="sr-only"> <.link navigate={~p"/posts/#{post}"}>Show</.link> </div> <.link patch={~p"/posts/#{post}/edit"}>Edit</.link> </:action> <:action :let={{id, post}}> <.link phx-click={JS.push("delete", value: %{id: post.id}) |> hide("##{id}")} data-confirm="Are you sure?" > Delete </.link> </:action> </.table> |
De retour sur le serveur, nous pouvons voir à quel point il est simple d'insérer de nouveaux éléments dans la table. Lorsque notre FormComponent généré met à jour ou enregistre un article via le formulaire, nous envoyons un paquet de messages au LiveView parent PostLive.Index à propos de l'article nouveau ou mis à jour :
PostLive.FormComponent :
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | defmodule DemoWeb.PostLive.FormComponent do ... defp save_post(socket, :new, post_params) do case Blog.create_post(post_params) do {:ok, post} -> notify_parent({:saved, post}) {:noreply, socket |> put_flash(:info, "Post created successfully") |> push_patch(to: socket.assigns.patch)} {:error, %Ecto.Changeset{} = changeset} -> {:noreply, assign_form(socket, changeset)} end end defp notify_parent(msg), do: send(self(), {__MODULE__, msg}) end |
Code : | Sélectionner tout |
1 2 3 4 | @impl true def handle_info({DemoWeb.PostLive.FormComponent, {:saved, post}}, socket) do {:noreply, stream_insert(socket, :posts, post)} end |
Les flux ont été l'un des derniers blocs de construction sur notre chemin vers LiveView 1.0 et je suis super content de ce que nous avons obtenu.
Nouvelle structure de données pour les champs de formulaire
Nous sommes tous familiers avec les primitives de formulaire Phoenix.HTML de <.form for={@changeset}>, où le formulaire prend une structure de données qui implémente le protocole Phoenix.HTML.FormData et renvoie un %Phoenix.HTML.Form{}. L'un des problèmes de notre approche est que la structure de données du formulaire ne pouvait pas suivre les modifications des champs individuels du formulaire. Cela rendait les optimisations impossibles dans LiveView, où nous devions redonner un nouveau rendu et renvoyer le formulaire pour chaque changement individuel. Avec l'introduction de Phoenix.HTML.FormData.to_form et Phoenix.Component.to_form, nous disposons désormais d'une structure de données %Phoenix.HTML.FormField{} pour les changements de champs individuels.
Les nouveaux générateurs phx.gen.live et votre core_components.ex tirent parti de ces nouveaux ajouts.
Prochaines étapes pour Phoenix et LiveView
Les générateurs Phoenix utilisent les dernières fonctionnalités de LiveView, qui continueront à se développer. Avec les collections en streaming par défaut, nous pouvons aller vers des fonctionnalités plus avancées pour nos générateurs CRUD en direct dans phx.gen.live. Par exemple, nous prévoyons d'introduire des interfaces utilisateur synchronisées prêtes à l'emploi pour les ressources. Les fonctionnalités des formulaires générés par Phoenix continueront d'évoluer avec l'ajout de la nouvelle interface to_form.
Pour LiveView, to_form nous a permis de livrer la base de formulaires optimisés. Désormais, une modification individuelle d'un champ du formulaire produira un formulaire optimisé.
Suite à ce travail d'optimisation, la principale caractéristique restante de LiveView 1.0 est une API de formulaire étendue qui prend mieux en charge les entrées de formulaire dynamiques, les formulaires de style assistant et la délégation des entrées de formulaire aux LiveComponents enfants.
Support de serveurs web alternatifs
Grâce au travail de Mat Trudel, nous avons maintenant la base pour un support de serveur web de première classe dans Plug et Phoenix, permettant à d'autres serveurs web comme Bandit d'être échangés dans Phoenix tout en profitant de toutes les fonctionnalités comme WebSockets, Channels, et LiveView. Restez à l'écoute du projet Bandit si vous êtes intéressé par un serveur HTTP en Elixir pur ou essayez-le dans vos propres projets Phoenix !
Prochaines étapes
Comme toujours, des guides de mise à jour étape par étape sont disponibles pour faire passer vos applications 1.6.x à la 1.7.
Retrouvez-nous sur elixir slack ou sur les forums si vous avez des problèmes.
Bon codage !
-Chris
Source : Phoenix Framework
Et vous ?
Que pensez-vous des nouvelles fonctionnalités proposées par cette version Phoenix ?
Voir aussi :
La version 1.9 d'Elixir est publiée avec l'ajout de nouvelles fonctionnalités et une configuration améliorée
La version 3.0 de Tailwind CSS, le framework qui permet de créer rapidement des sites Web modernes, est disponible, il apporte des gains de performance incroyables
La version 3.2 du framework Django est disponible, avec la découverte automatique d'AppConfig, elle apporte de nouveaux décorateurs pour le module d'administration
La version 3.2 du langage de programmation Ruby est disponible, elle apporte de nombreuses fonctionnalités et améliore les performances