Skip to content

Latest commit

 

History

History
141 lines (108 loc) · 3.28 KB

phoenix-playground.livemd

File metadata and controls

141 lines (108 loc) · 3.28 KB

Phoenix Playground

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"}
])

Port setup

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)

Configuration

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

Helpers

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

Actual Phoenix code!

A fully functional Phoenix application using HTML templates consists of just 6 modules.

flowchart LR
    Endpoint --> Router
    Router --> Controller
    Controller --> Layout
    Layout --> Template
Loading

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.()