Mix.install([
{:phoenix, "~> 1.7"},
{:ecto, "~> 3.10"},
{:kino, "~> 0.9.2"},
{:plug_cowboy, "~> 2.5"},
{:jason, "~> 1.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_view, "~> 0.18.18"}
])
I often have other stuff running on port 4000, so I made it configurable. I propose to set it once and collapse this section.
port_input = Kino.Input.number("Port", default: 4000)
We are setting bare minimum config using the port defined in previous section. You can also collapse this section.
Application.put_env(:phoenix, :json_library, Jason)
Application.put_env(:phoenix_playground, PhoenixPlaygroundWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: Kino.Input.read(port_input)],
server: true,
secret_key_base: String.duplicate("a", 64)
)
I'd like to make restarting the full Phoenix app easy, so I define a helper to do that. Unfortunately, Phoenix sometimes takes 5s to shut down. Let me know if you have a solution to that issue!
I am @snajper47 on Twitter.
I propose to collapse this section as well.
supervisor_name = PhoenixPlayground
restart_phoenix = fn ->
if Process.whereis(supervisor_name) do
Supervisor.stop(supervisor_name)
end
{:ok, _} =
Supervisor.start_link([PhoenixPlaygroundWeb.Endpoint],
strategy: :one_for_one,
name: supervisor_name
)
end
A fully functional Phoenix application using HTML templates consists of just 6 modules.
flowchart LR
Endpoint --> Router
Router --> Controller
Controller --> Layout
Layout --> Template
Feel free to experiment! You can modify each of those module as you like and then click "evaluate". The url to access the rendered page should display at the bottom.
defmodule PhoenixPlaygroundWeb.SampleHTML do
# components are function that render html
# they take a map of assigns e.g. %{name: "Tomek"}
# and return a heex template (sigil ~H)
# you can list assigns with their types using `attr` macro
# and use them in the heex template with <%= @name %> syntax
use Phoenix.Component
attr(:name, :string)
def index(assigns) do
~H"""
<h2>Hello, <%= @name %>!</h2>
"""
end
end
defmodule PhoenixPlaygroundWeb.LayoutView do
# A layout is a special component that receives an assign
# called inner_content
use Phoenix.Component
def app(assigns) do
~H"""
<%= @inner_content %>
"""
end
end
defmodule PhoenixPlaygroundWeb.SampleController do
use Phoenix.Controller, formats: [:html]
def index(conn, _params) do
# `render` function inferes layout and template name from controller name and format
# the last argument are assigns
name = "Tomek"
render(conn, :index, name: name)
end
end
defmodule PhoenixPlaygroundWeb.Router do
use Phoenix.Router
pipeline :browser do
plug(:accepts, ["html"])
end
scope "/", PhoenixPlaygroundWeb do
pipe_through(:browser)
get("/", SampleController, :index)
# Prevent a horrible error because ErrorView is missing
get("/favicon.ico", SampleController, :index)
end
end
defmodule PhoenixPlaygroundWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :phoenix_playground
plug(PhoenixPlaygroundWeb.Router)
end
restart_phoenix.()