Notre objectif est de créer notre premiere page Html avec Phoenix Elixir. Cette première page doit nous permettre de découvrir l’architecture de Phoenix et de voir comment s’organise un projet Phoenix.
Cette premiere page HTML avec Phoenix nous permettra de prendre en main Phoenix avant de réaliser des applications complètes. Nous allons utiliser le livre Programming Phoenix>1.4 pour réaliser cette première page.
Installer l’environnement de développement
Nous allons vérifier que notre environnement de développemetn est prêt.
Version d’Elixir compatible avec la version d’Erlang :
C:\Users\broussel>elixir -v Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns] Elixir 1.15.5 (compiled with Erlang/OTP 26) C:\Users\broussel>
vérification de la version du package manager Elixir appelé Hex :
C:\Users\broussel>mix local.hex Found existing entry: c:/Users/broussel/.mix/archives/hex-2.0.6 Are you sure you want to replace it with "https://builds.hex.pm/installs/1.14.0/hex-2.0.6.ez"? [Yn] n C:\Users\broussel>
Nous avons déjà la dernière version de Hex installée.
Vérification de la version de Postgres :
C:\Users\broussel>psql --version psql (PostgreSQL) 15.4 C:\Users\broussel> C:\Users\broussel>psql -U postgres Mot de passe pour l'utilisateur postgres : psql (15.4) Attention : l'encodage console (850) diffère de l'encodage Windows (1252). Les caractères 8 bits peuvent ne pas fonctionner correctement. Voir la section « Notes aux utilisateurs de Windows » de la page référence de psql pour les détails. Saisissez « help » pour l'aide. postgres=# \du Liste des r¶les Nom du r¶le | Attributs | Membre de -------------+---------------------------------------------------------------------------------+----------- postgres | Superutilisateur, CrÚer un r¶le, CrÚer une base, RÚplication, Contournement RLS | {} postgres=# \q C:\Users\broussel>
Nous avons bien la base de données Postgres installée avec un utilisateur postgres/postgres.
Vérification de la version de node.js :
C:\Users\broussel>node --version 'node' n'est pas reconnu en tant que commande interne ou externe, un programme exécutable ou un fichier de commandes. C:\Users\broussel>
Pour installer node, nous rédigeons un article montrant comment installer NodeJS et NPM sur Windows.
Afin que l’installation de Node soit prise en compte, nous devons relancer le shell.
C:\Users\broussel>node -v v18.17.1 C:\Users\broussel>npm -v 9.6.7 C:\Users\broussel>
Vérification de l’installation de Phoenix
C:\Users\broussel>mix phx.new -v Phoenix installer v1.7.7 C:\Users\broussel>
L’environnement de développement est maintenant prêt sur Windows. Nous utiliserons VS Code pour le développement. Dans un article précédent, nous avons montré comment installer VS Code pour développer avec Elixir.
Créer un projet de base avec Phoenix
Nous créons un projet hello avec le script mix phx.new. Le projet sera créé dans notre répertoire :
- C:\CarbonX1\Phoenix\Projets\
C:\Users\broussel>cd C:\CarbonX1\Phoenix\Projets C:\CarbonX1\Phoenix\Projets>mix phx.new hello * creating hello/config/config.exs * creating hello/config/dev.exs * creating hello/config/prod.exs * creating hello/config/runtime.exs * creating hello/config/test.exs * creating hello/lib/hello/application.ex * creating hello/lib/hello.ex * creating hello/lib/hello_web/controllers/error_json.ex * creating hello/lib/hello_web/endpoint.ex * creating hello/lib/hello_web/router.ex * creating hello/lib/hello_web/telemetry.ex * creating hello/lib/hello_web.ex * creating hello/mix.exs * creating hello/README.md * creating hello/.formatter.exs * creating hello/.gitignore * creating hello/test/support/conn_case.ex * creating hello/test/test_helper.exs * creating hello/test/hello_web/controllers/error_json_test.exs * creating hello/lib/hello/repo.ex * creating hello/priv/repo/migrations/.formatter.exs * creating hello/priv/repo/seeds.exs * creating hello/test/support/data_case.ex * creating hello/lib/hello_web/controllers/error_html.ex * creating hello/test/hello_web/controllers/error_html_test.exs * creating hello/lib/hello_web/components/core_components.ex * creating hello/lib/hello_web/controllers/page_controller.ex * creating hello/lib/hello_web/controllers/page_html.ex * creating hello/lib/hello_web/controllers/page_html/home.html.heex * creating hello/test/hello_web/controllers/page_controller_test.exs * creating hello/lib/hello_web/components/layouts/root.html.heex * creating hello/lib/hello_web/components/layouts/app.html.heex * creating hello/lib/hello_web/components/layouts.ex * creating hello/priv/static/images/logo.svg * creating hello/lib/hello/mailer.ex * creating hello/lib/hello_web/gettext.ex * creating hello/priv/gettext/en/LC_MESSAGES/errors.po * creating hello/priv/gettext/errors.pot * creating hello/priv/static/robots.txt * creating hello/priv/static/favicon.ico * creating hello/assets/js/app.js * creating hello/assets/vendor/topbar.js * creating hello/assets/css/app.css * creating hello/assets/tailwind.config.js * creating hello/assets/vendor/heroicons/LICENSE.md * creating hello/assets/vendor/heroicons/UPGRADE.md * extracting hello/assets/vendor/heroicons/optimized Fetch and install dependencies? [Yn] Y * running mix deps.get * running mix assets.setup * running mix deps.compile We are almost there! The following steps are missing: $ cd hello Then configure your database in config/dev.exs and run: $ mix ecto.create Start your Phoenix app with: $ mix phx.server You can also run your app inside IEx (Interactive Elixir) as: $ iex -S mix phx.server C:\CarbonX1\Phoenix\Projets>
Le script a créé un projet hello dans notre dossier projets :
Nous suivons les instructions consistant à créer la base de données et à lancer lle serveur permettant de voir notre application dans le navigateur :
C:\CarbonX1\Phoenix\Projets>cd hello C:\CarbonX1\Phoenix\Projets\hello>mix ecto.create Compiling 15 files (.ex) Generated hello app The database for Hello.Repo has been created C:\CarbonX1\Phoenix\Projets\hello>mix phx.server [warning] Phoenix is unable to create symlinks. Phoenix' code reloader will run considerably faster if symlinks are allowed. On Windows, the lack of symlinks may even cause empty assets to be served. Luckily, you can address this issue by starting your Windows terminal at least once with "Run as Administrator" and then running your Phoenix application. [info] Running HelloWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http) [info] Access HelloWeb.Endpoint at http://localhost:4000 [watch] build finished, watching for changes... Rebuilding... Done in 374ms. [info] GET / [debug] Processing with HelloWeb.PageController.home/2 Parameters: %{} Pipelines: [:browser] [info] Sent 200 in 75ms
Puis nous ouvrons le navigateur en :
- http://localhost:4000/
La page dans le navigateur :
Ajouter une page dans notre projet hello
Dans le projet hello que nous venons de générer, nous souhaitons ajouter une page afin de le personnaliser. Nous allons regarder comment ajouter une nouvelle page affichant pour l’instant un message « Hello World ! ».
Nous ouvrons VS Code avec le projet :
C:\Users\broussel>cd C:\CarbonX1\Phoenix\Projets\hello C:\CarbonX1\Phoenix\Projets\hello>code . C:\CarbonX1\Phoenix\Projets\hello>
VS Code s’ouvre avec le projet :
Pour créer une page nous devons :
- créer une page template affichant « hello world ! », à placer dans le dossier : lib/hello_web/templates/
- créer une view qui utilisera notre template, la view sera placée dans le dossier : lib/hello_web/views/
- ajouter un contrôleur dans le dossier : lib/hello_web/controllers
- déclarer notre contrôleur dans le routeur : lib/hello_web/router.ex
Nous allons créer dela en suivant le parcours de la requête provenant du navigateur.
Ajout du chemin dans Router.ex
Le routeur reçoit les requêtes en provenance du navigateur :
- HELLO>lib>hello_web>router.ex
router.ex :
scope "/", HelloWeb do pipe_through :browser get "/", PageController, :home end
Ici, scope attrape les requêtes dont l’url est ‘/’ et dirige la requête vers le controleur ‘PageController‘ en activant la fonction appelée ‘home‘ :
PageController.ex :
defmodule HelloWeb.PageController do use HelloWeb, :controller def home(conn, _params) do # The home page is often custom made, # so skip the default app layout. render(conn, :home, layout: false) end end
Ajoutons notre route vers notre controleur ‘HelloController‘ et sa fonction ‘world‘
Nous plaçons notre nouvelle route ‘/hello’ juste au dessus de la route générale ‘/’.
router.ex :
scope "/", HelloWeb do pipe_through :browser get "/hello", HelloController, :world get "/", PageController, :home end
L’ordre des routes a de l’importance car Elixir prend les routes dans l’ordre en s’arrêtant sur la première route qui match, donc ‘/hello’ doit être avant la route qui attrape tout : ‘/’.
Si nous activons le projet et demandons l’url ‘/hello’, nous avons un message qui s’affiche dans le navigateur et dans la console :
Dans la partie droite, nous avons la liste des étapes parcourues par la requête. Les lignes commençant avec un point orange sont des modules et fonctions de l’application que nous développons. En cliquant sur ces lignes nous accédons au code de l’application.
La console affiche le message d’erreur :
C:\CarbonX1\Phoenix\Projets\hello>mix phx.server Compiling 1 file (.ex) warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined) lib/hello_web/router.ex:20: HelloWeb.Router.__checks__/0 [warning] Phoenix is unable to create symlinks. Phoenix' code reloader will run considerably faster if symlinks are allowed. On Windows, the lack of symlinks may even cause empty assets to be served. Luckily, you can address this issue by starting your Windows terminal at least once with "Run as Administrator" and then running your Phoenix application. [info] Running HelloWeb.Endpoint with cowboy 2.10.0 at 127.0.0.1:4000 (http) [info] Access HelloWeb.Endpoint at http://localhost:4000 [watch] build finished, watching for changes... Rebuilding... Done in 378ms. warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined) lib/hello_web/router.ex:20 [info] GET / [debug] Processing with HelloWeb.PageController.home/2 Parameters: %{} Pipelines: [:browser] [info] Sent 200 in 280ms warning: HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available or is yet to be defined) lib/hello_web/router.ex:20 [info] GET /hello [debug] Processing with HelloWeb.HelloController.world/2 Parameters: %{} Pipelines: [:browser] [info] Sent 500 in 206ms [error] #PID<0.532.0> running Phoenix.Endpoint.SyncCodeReloadPlug (connection #PID<0.506.0>, stream id 2) terminated Server: localhost:4000 (http) Request: GET /hello ** (exit) an exception was raised: ** (UndefinedFunctionError) function HelloWeb.HelloController.init/1 is undefined (module HelloWeb.HelloController is not available) HelloWeb.HelloController.init(:world) (phoenix 1.7.7) lib/phoenix/router.ex:430: Phoenix.Router.__call__/5 (hello 0.1.0) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.plug_builder_call/2 (hello 0.1.0) deps/plug/lib/plug/debugger.ex:136: HelloWeb.Endpoint."call (overridable 3)"/2 (hello 0.1.0) lib/hello_web/endpoint.ex:1: HelloWeb.Endpoint.call/2 (phoenix 1.7.7) lib/phoenix/endpoint/sync_code_reload_plug.ex:22: Phoenix.Endpoint.SyncCodeReloadPlug.do_call/4 (plug_cowboy 2.6.1) lib/plug/cowboy/handler.ex:11: Plug.Cowboy.Handler.init/2 (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_handler.erl:37: :cowboy_handler.execute/2 (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_stream_h.erl:306: :cowboy_stream_h.execute/3 (cowboy 2.10.0) c:/CarbonX1/Phoenix/Projets/hello/deps/cowboy/src/cowboy_stream_h.erl:295: :cowboy_stream_h.request_process/3 (stdlib 5.0.2) proc_lib.erl:241: :proc_lib.init_p_do_apply/3
Le message nous indique bien que HelloController n’est pas défini ligne (35).
Ajout d’un Controlleur pour le projet : _controller.ex
Nous ajoutons le controleur HelloController dans le dossier qui regroupe l’ensemble des controleurs :
lib/hello_web/controllers/hello_controller.ex :
defmodule HelloWeb.HelloController do use HelloWeb, :controller def world(conn, _params) do # render(conn, :home, layout: false) render(conn, :world) # nous gardons le layout end end
Comme nous avons laissé le navigateur ouvert, chaque enregistrement de modification dans VS Code relance automatiquement le chargement de la page. Nous voyons une nouvelle erreur s’afficher :
Ajout du Template dans le dossier controllers
Nous ne pouvons pas suivre à la lettre l’ouvrage Programming Phoenix >1.4 car la version 1.7 a changé la façon de faire :
Les pages templates sont rangées dorénavant dans le dossiert controllers.
lib/hello_web/controllers/hello_html.ex :
defmodule HelloWeb.HelloHTML do use HelloWeb, :html embed_templates "hello_html/*" end
Puis nous créons le fichier
lib/hello_web/controllers/hello_html/world.html.heex :
<h1>Hello world!</h1>
Si nous supprimons le layout dans hello_controller.ex :
defmodule HelloWeb.HelloController do use HelloWeb, :controller def world(conn, _params) do # The home page is often custom made, # so skip the default app layout. # render(conn, :home, layout: false) # render(conn, :world) render(conn, :world, layout: false) end end
La mise en page change et n’affiche plus le layout :
Le layout est défini dans le dossier components/layouts.
lib/hello_web/components/layouts/app.html.heex :
<header class="px-4 sm:px-6 lg:px-8"> <div class="flex items-center justify-between border-b border-zinc-100 py-3 text-sm"> <div class="flex items-center gap-4"> <a href="/"> <img src={~p"/images/logo.svg"} width="36" /> </a> <p class="bg-brand/5 text-brand rounded-full px-2 font-medium leading-6"> v<%= Application.spec(:phoenix, :vsn) %> </p> </div> <div class="flex items-center gap-4 font-semibold leading-6 text-zinc-900"> <a href="https://twitter.com/elixirphoenix" class="hover:text-zinc-700"> @elixirphoenix </a> <a href="https://github.com/phoenixframework/phoenix" class="hover:text-zinc-700"> GitHub </a> <a href="https://hexdocs.pm/phoenix/overview.html" class="rounded-lg bg-zinc-100 px-2 py-1 hover:bg-zinc-200/80" > Get Started <span aria-hidden="true">→</span> </a> </div> </div> </header> <main class="px-4 py-20 sm:px-6 lg:px-8"> <div class="mx-auto max-w-2xl"> <.flash_group flash={@flash} /> <%= @inner_content %> </div> </main>
La structure du projet
Dans la version 1.7 de Phoenix l’emplacement des fichiers est modifiée par rapport à la version décrite dans l’ouvrage Programming Phoenix >1.4.
La structure du projet :
la page hello_controller.ex :
La page hello_html.ex :
Dans le dossier controllers, nous avons le dossier hello_html où nous plaçons le template world.html.heex
Les repertoires templates et views (1) sont deplacés dans controllers (2).
Conclusion,
nous avons créé une première page pour une application dans Phoenix Elixir. La réalisation passe par :
- la déclaration de la page dans le router.ex dirigeant vers HelloController.ex,
- la création du controller HelloController pour notre page,
- le contenu de notre page dans world.html.heex.
- Le controller HelloController trouve le dossier dans lequel est rangé la page world.html.heex dans HelloHtml.