$30 off During Our Annual Pro Sale. View Details »

Phoenix LiveView チュートリアル

Phoenix LiveView チュートリアル

Phoenix LiveView チュートリアル
https://github.com/ne-sachirou/phoenix_live_view_sample

さっちゃん

June 14, 2019
Tweet

More Decks by さっちゃん

Other Decks in Programming

Transcript

  1. Phoenix LiveView チュート
    Phoenix LiveView チュート
    リアル
    リアル

    View Slide

  2. 2019-06 の theme は、
    2019-06 の theme は、
    Phoenix LiveView
    Phoenix LiveView

    View Slide

  3. Phoenix |> とは
    Phoenix |> とは
    Elixir の Web Application Framework (Ruby on Rails っぽいもの) で
    Elixir の Web Application Framework (Ruby on Rails っぽいもの) で
    す。Rails と同じく、RDB と連携した Web Application を素早く簡單に
    す。Rails と同じく、RDB と連携した Web Application を素早く簡單に
    作れます。
    作れます。
    https://phoenixframework.org/
    https://phoenixframework.org/

    View Slide

  4. 加えて、
    加えて、
    Phoenix.Channel
    Phoenix.Channelと云ふ仕組みで、WebSocket を通した multi
    と云ふ仕組みで、WebSocket を通した multi
    user & real-time application (典型的には chat) を素早く簡單に作れま
    user & real-time application (典型的には chat) を素早く簡單に作れま
    す。
    す。

    View Slide

  5. Phoenix LiveView |> とは
    Phoenix LiveView |> とは
    「わっちは Web browser の表⽰を real-time に更新したいだけなんぢ
    「わっちは Web browser の表⽰を real-time に更新したいだけなんぢ
    ゃ! それだけの爲に JavaScript なんぞを書きとうない! (異論は認める)」
    ゃ! それだけの爲に JavaScript なんぞを書きとうない! (異論は認める)」

    View Slide

  6. sever-side の Elixir で HTML を吐く code を書くだけで、real-time に
    sever-side の Elixir で HTML を吐く code を書くだけで、real-time に
    Web browser の表⽰を更新できる!?
    Web browser の表⽰を更新できる!?
    https://github.com/phoenixframework/phoenix_live_view
    https://github.com/phoenixframework/phoenix_live_view

    View Slide

  7. Do It.
    Do It.

    View Slide

  8. Erlang と Elixir が⼊ってゐる事を確か
    Erlang と Elixir が⼊ってゐる事を確か
    める
    める
    elixir -v
    elixir -v
    ⼊ってゐなければ (asdf, anyenv 等は御好みに)、
    ⼊ってゐなければ (asdf, anyenv 等は御好みに)、
    brew install erlang elixir
    brew install erlang elixir
    Ubuntu (WSL 含む) は
    Ubuntu (WSL 含む) は https://www.erlang-
    https://www.erlang-
    solutions.com/resources/download.html
    solutions.com/resources/download.html から。
    から。

    View Slide

  9. Node.js を⼊れる
    Node.js を⼊れる
    brew install node
    brew install node
    node -v
    node -v
    Ubuntu (WSL を含む) は
    Ubuntu (WSL を含む) は
    https://github.com/nodesource/distributions/blob/master/README.
    https://github.com/nodesource/distributions/blob/master/README.
    md
    md から。
    から。

    View Slide

  10. MySQL (MariaDB) を⼊れる
    MySQL (MariaDB) を⼊れる
    brew install mysql
    brew install mysql
    brew services start mysql
    brew services start mysql

    View Slide

  11. Phoenix を⼊れる
    Phoenix を⼊れる
    https://hexdocs.pm/phoenix/installation.html
    https://hexdocs.pm/phoenix/installation.html
    mix archive.install hex phx_new
    mix archive.install hex phx_new

    View Slide

  12. Web application を作る
    Web application を作る
    https://hexdocs.pm/phoenix/up_and_running.html
    https://hexdocs.pm/phoenix/up_and_running.html
    mix
    mix help
    help phx.new
    phx.new
    mix phx.new hello --umbrella --database mysql
    mix phx.new hello --umbrella --database mysql
    cd
    cd hello_umbrella
    hello_umbrella
    (
    (cd
    cd apps/hello_web/assets && npm install)
    apps/hello_web/assets && npm install)
    mix ecto.create
    mix ecto.create
    iex -S mix phx.server
    iex -S mix phx.server
    http://localhost:4000/
    http://localhost:4000/

    View Slide

  13. Phoenix LiveView を⼊れる
    Phoenix LiveView を⼊れる
    ^C
    ^C で phx.server を落とす。 (
    で phx.server を落とす。 ( mix.exs
    mix.exs や
    や config/
    config/ を書き換へた時に
    を書き換へた時に
    は LiveReload が效かないので、再起動する。)
    は LiveReload が效かないので、再起動する。)
    diff --git a/apps/hello_web/mix.exs b/apps/hello_web/mix.exs
    diff --git a/apps/hello_web/mix.exs b/apps/hello_web/mix.exs
    index b5158fc..33aa0de 100644
    index b5158fc..33aa0de 100644
    --- a/apps/hello_web/mix.exs
    --- a/apps/hello_web/mix.exs
    +++ b/apps/hello_web/mix.exs
    +++ b/apps/hello_web/mix.exs
    @@ -42,6 +42,7 @@ defmodule HelloWeb.MixProject do
    @@ -42,6 +42,7 @@ defmodule HelloWeb.MixProject do
    {:phoenix_ecto, "~> 4.0"},
    {:phoenix_ecto, "~> 4.0"},
    {:phoenix_html, "~> 2.11"},
    {:phoenix_html, "~> 2.11"},
    {:phoenix_live_reload, "~> 1.2", only: :dev},
    {:phoenix_live_reload, "~> 1.2", only: :dev},
    + {:phoenix_live_view, github: "phoenixframework/phoenix_live_view"},
    + {:phoenix_live_view, github: "phoenixframework/phoenix_live_view"},
    {:gettext, "~> 0.11"},
    {:gettext, "~> 0.11"},
    {:hello, in_umbrella: true},
    {:hello, in_umbrella: true},
    {:jason, "~> 1.0"},
    {:jason, "~> 1.0"},
    mix deps.get
    mix deps.get

    View Slide

  14. mix phx.gen.secret 32
    mix phx.gen.secret 32
    # SECRET_SALT
    # SECRET_SALT
    diff --git a/config/config.exs b/config/config.exs
    diff --git a/config/config.exs b/config/config.exs
    index d5b58e4..c40d159 100644
    index d5b58e4..c40d159 100644
    --- a/config/config.exs
    --- a/config/config.exs
    +++ b/config/config.exs
    +++ b/config/config.exs
    @@ -22,7 +22,8 @@ config :hello_web, HelloWeb.Endpoint,
    @@ -22,7 +22,8 @@ config :hello_web, HelloWeb.Endpoint,
    url: [host: "localhost"],
    url: [host: "localhost"],
    secret_key_base: "JQ/tn4vM/UDSW/BkHsotJKRpvugZMOGuL51u/j8LzYjIh+elejWrL7jgEt8vZIdt",
    secret_key_base: "JQ/tn4vM/UDSW/BkHsotJKRpvugZMOGuL51u/j8LzYjIh+elejWrL7jgEt8vZIdt",
    render_errors: [view: HelloWeb.ErrorView, accepts: ~w(html json)],
    render_errors: [view: HelloWeb.ErrorView, accepts: ~w(html json)],
    - pubsub: [name: HelloWeb.PubSub, adapter: Phoenix.PubSub.PG2]
    - pubsub: [name: HelloWeb.PubSub, adapter: Phoenix.PubSub.PG2]
    + pubsub: [name: HelloWeb.PubSub, adapter: Phoenix.PubSub.PG2],
    + pubsub: [name: HelloWeb.PubSub, adapter: Phoenix.PubSub.PG2],
    + live_view: [signing_salt: "SECRET_SALT"]
    + live_view: [signing_salt: "SECRET_SALT"]
    # Configures Elixir's Logger
    # Configures Elixir's Logger
    config :logger, :console,
    config :logger, :console,

    View Slide

  15. diff --git a/apps/hello_web/lib/hello_web/router.ex b/apps/hello_web/lib/hello_web/router.ex
    diff --git a/apps/hello_web/lib/hello_web/router.ex b/apps/hello_web/lib/hello_web/router.ex
    index e691cdb..3983991 100644
    index e691cdb..3983991 100644
    --- a/apps/hello_web/lib/hello_web/router.ex
    --- a/apps/hello_web/lib/hello_web/router.ex
    +++ b/apps/hello_web/lib/hello_web/router.ex
    +++ b/apps/hello_web/lib/hello_web/router.ex
    @@ -7,6 +7,8 @@ defmodule HelloWeb.Router do
    @@ -7,6 +7,8 @@ defmodule HelloWeb.Router do
    plug :fetch_flash
    plug :fetch_flash
    plug :protect_from_forgery
    plug :protect_from_forgery
    plug :put_secure_browser_headers
    plug :put_secure_browser_headers
    + plug :fetch_flash
    + plug :fetch_flash
    + plug Phoenix.LiveView.Flash
    + plug Phoenix.LiveView.Flash
    end
    end
    pipeline :api do
    pipeline :api do

    View Slide

  16. diff --git a/apps/hello_web/lib/hello_web.ex b/apps/hello_web/lib/hello_web.ex
    diff --git a/apps/hello_web/lib/hello_web.ex b/apps/hello_web/lib/hello_web.ex
    index 9cf6215..9055872 100644
    index 9cf6215..9055872 100644
    --- a/apps/hello_web/lib/hello_web.ex
    --- a/apps/hello_web/lib/hello_web.ex
    +++ b/apps/hello_web/lib/hello_web.ex
    +++ b/apps/hello_web/lib/hello_web.ex
    @@ -22,6 +22,7 @@ defmodule HelloWeb do
    @@ -22,6 +22,7 @@ defmodule HelloWeb do
    use Phoenix.Controller, namespace: HelloWeb
    use Phoenix.Controller, namespace: HelloWeb
    import Plug.Conn
    import Plug.Conn
    import HelloWeb.Gettext
    import HelloWeb.Gettext
    + import Phoenix.LiveView.Controller, only: [live_render: 3]
    + import Phoenix.LiveView.Controller, only: [live_render: 3]
    alias HelloWeb.Router.Helpers, as: Routes
    alias HelloWeb.Router.Helpers, as: Routes
    end
    end
    end
    end
    @@ -40,6 +41,7 @@ defmodule HelloWeb do
    @@ -40,6 +41,7 @@ defmodule HelloWeb do
    import HelloWeb.ErrorHelpers
    import HelloWeb.ErrorHelpers
    import HelloWeb.Gettext
    import HelloWeb.Gettext
    + import Phoenix.LiveView, only: [live_render: 2, live_render: 3]
    + import Phoenix.LiveView, only: [live_render: 2, live_render: 3]
    alias HelloWeb.Router.Helpers, as: Routes
    alias HelloWeb.Router.Helpers, as: Routes
    end
    end
    end
    end
    @@ -49,6 +51,7 @@ defmodule HelloWeb do
    @@ -49,6 +51,7 @@ defmodule HelloWeb do
    use Phoenix.Router
    use Phoenix.Router
    import Plug.Conn
    import Plug.Conn
    import Phoenix.Controller
    import Phoenix.Controller
    + import Phoenix.LiveView.Router
    + import Phoenix.LiveView.Router
    end
    end
    end
    end

    View Slide

  17. diff --git a/apps/hello_web/lib/hello_web/endpoint.ex b/apps/hello_web/lib/hello_web/endpoint.ex
    diff --git a/apps/hello_web/lib/hello_web/endpoint.ex b/apps/hello_web/lib/hello_web/endpoint.ex
    index 3e89975..c03dbb9 100644
    index 3e89975..c03dbb9 100644
    --- a/apps/hello_web/lib/hello_web/endpoint.ex
    --- a/apps/hello_web/lib/hello_web/endpoint.ex
    +++ b/apps/hello_web/lib/hello_web/endpoint.ex
    +++ b/apps/hello_web/lib/hello_web/endpoint.ex
    @@ -5,6 +5,8 @@ defmodule HelloWeb.Endpoint do
    @@ -5,6 +5,8 @@ defmodule HelloWeb.Endpoint do
    websocket: true,
    websocket: true,
    longpoll: false
    longpoll: false
    + socket "/live", Phoenix.LiveView.Socket
    + socket "/live", Phoenix.LiveView.Socket
    +
    +
    # Serve at "/" the static files from "priv/static" directory.
    # Serve at "/" the static files from "priv/static" directory.
    #
    #
    # You should set gzip to true if you are running phx.digest
    # You should set gzip to true if you are running phx.digest

    View Slide

  18. diff --git a/apps/hello_web/assets/package.json b/apps/hello_web/assets/package.json
    diff --git a/apps/hello_web/assets/package.json b/apps/hello_web/assets/package.json
    index eaf01c6..5c5a8d0 100644
    index eaf01c6..5c5a8d0 100644
    --- a/apps/hello_web/assets/package.json
    --- a/apps/hello_web/assets/package.json
    +++ b/apps/hello_web/assets/package.json
    +++ b/apps/hello_web/assets/package.json
    @@ -7,7 +7,8 @@
    @@ -7,7 +7,8 @@
    },
    },
    "dependencies": {
    "dependencies": {
    "phoenix": "file:../../../deps/phoenix",
    "phoenix": "file:../../../deps/phoenix",
    - "phoenix_html": "file:../../../deps/phoenix_html"
    - "phoenix_html": "file:../../../deps/phoenix_html"
    + "phoenix_html": "file:../../../deps/phoenix_html",
    + "phoenix_html": "file:../../../deps/phoenix_html",
    + "phoenix_live_view": "file:../../../deps/phoenix_live_view"
    + "phoenix_live_view": "file:../../../deps/phoenix_live_view"
    },
    },
    "devDependencies": {
    "devDependencies": {
    "@babel/core": "^7.0.0",
    "@babel/core": "^7.0.0",
    (
    (cd
    cd apps/hello_web/assets && npm install)
    apps/hello_web/assets && npm install)

    View Slide

  19. diff --git a/apps/hello_web/assets/css/app.css b/apps/hello_web/assets/css/app.css
    diff --git a/apps/hello_web/assets/css/app.css b/apps/hello_web/assets/css/app.css
    index fec0b3f..416abc2 100644
    index fec0b3f..416abc2 100644
    --- a/apps/hello_web/assets/css/app.css
    --- a/apps/hello_web/assets/css/app.css
    +++ b/apps/hello_web/assets/css/app.css
    +++ b/apps/hello_web/assets/css/app.css
    @@ -1,3 +1,4 @@
    @@ -1,3 +1,4 @@
    /* This file is for your main application css. */
    /* This file is for your main application css. */
    @import "./phoenix.css";
    @import "./phoenix.css";
    +@import "../../../../deps/phoenix_live_view/assets/css/live_view.css";
    +@import "../../../../deps/phoenix_live_view/assets/css/live_view.css";
    \ No newline at end of file
    \ No newline at end of file
    diff --git a/apps/hello_web/assets/js/app.js b/apps/hello_web/assets/js/app.js
    diff --git a/apps/hello_web/assets/js/app.js b/apps/hello_web/assets/js/app.js
    index 8a5d386..719c0ab 100644
    index 8a5d386..719c0ab 100644
    --- a/apps/hello_web/assets/js/app.js
    --- a/apps/hello_web/assets/js/app.js
    +++ b/apps/hello_web/assets/js/app.js
    +++ b/apps/hello_web/assets/js/app.js
    @@ -15,3 +15,8 @@ import "phoenix_html"
    @@ -15,3 +15,8 @@ import "phoenix_html"
    //
    //
    // Local files can be imported directly using relative paths, for example:
    // Local files can be imported directly using relative paths, for example:
    // import socket from "./socket"
    // import socket from "./socket"
    +
    +
    +import LiveSocket from "phoenix_live_view"
    +import LiveSocket from "phoenix_live_view"
    +
    +
    +let liveSocket = new LiveSocket("/live")
    +let liveSocket = new LiveSocket("/live")
    +liveSocket.connect()
    +liveSocket.connect()

    View Slide

  20. diff --git a/config/dev.exs b/config/dev.exs
    diff --git a/config/dev.exs b/config/dev.exs
    index d286f50..121eb30 100644
    index d286f50..121eb30 100644
    --- a/config/dev.exs
    --- a/config/dev.exs
    +++ b/config/dev.exs
    +++ b/config/dev.exs
    @@ -61,7 +61,8 @@ config :hello_web, HelloWeb.Endpoint,
    @@ -61,7 +61,8 @@ config :hello_web, HelloWeb.Endpoint,
    ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
    ~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
    ~r"priv/gettext/.*(po)$",
    ~r"priv/gettext/.*(po)$",
    ~r"lib/hello_web/{live,views}/.*(ex)$",
    ~r"lib/hello_web/{live,views}/.*(ex)$",
    - ~r"lib/hello_web/templates/.*(eex)$"
    - ~r"lib/hello_web/templates/.*(eex)$"
    + ~r"lib/hello_web/templates/.*(eex)$",
    + ~r"lib/hello_web/templates/.*(eex)$",
    + ~r{lib/hello_web/live/.*(ex)$}
    + ~r{lib/hello_web/live/.*(ex)$}
    ]
    ]
    ]
    ]

    View Slide

  21. Phoenix でページを作ってみる
    Phoenix でページを作ってみる
    cd
    cd apps/hello_web
    apps/hello_web
    mix phx.gen.html Accounts Users users name:string
    mix phx.gen.html Accounts Users users name:string
    mix ecto.migrate
    mix ecto.migrate
    diff --git a/apps/hello_web/lib/hello_web/router.ex b/apps/hello_web/lib/hello_web/router.ex
    diff --git a/apps/hello_web/lib/hello_web/router.ex b/apps/hello_web/lib/hello_web/router.ex
    index 3983991..2f96646 100644
    index 3983991..2f96646 100644
    --- a/apps/hello_web/lib/hello_web/router.ex
    --- a/apps/hello_web/lib/hello_web/router.ex
    +++ b/apps/hello_web/lib/hello_web/router.ex
    +++ b/apps/hello_web/lib/hello_web/router.ex
    @@ -19,6 +19,7 @@ defmodule HelloWeb.Router do
    @@ -19,6 +19,7 @@ defmodule HelloWeb.Router do
    pipe_through :browser
    pipe_through :browser
    get "/", PageController, :index
    get "/", PageController, :index
    + resources "/users", UsersController
    + resources "/users", UsersController
    end
    end
    # Other scopes may use custom stacks
    # Other scopes may use custom stacks
    http://localhost:4000/users
    http://localhost:4000/users

    View Slide

  22. LiveView を埋め込む!
    LiveView を埋め込む!
    diff --git a/apps/hello_web/lib/hello_live.ex b/apps/hello_web/lib/hello_live.ex
    diff --git a/apps/hello_web/lib/hello_live.ex b/apps/hello_web/lib/hello_live.ex
    new file mode 100644
    new file mode 100644
    index 0000000..d362431
    index 0000000..d362431
    --- /dev/null
    --- /dev/null
    +++ b/apps/hello_web/lib/hello_live.ex
    +++ b/apps/hello_web/lib/hello_live.ex
    @@ -0,0 +1,19 @@
    @@ -0,0 +1,19 @@
    +defmodule HelloWeb.HelloLive do
    +defmodule HelloWeb.HelloLive do
    + use Phoenix.LiveView
    + use Phoenix.LiveView
    +
    +
    + def render(assigns) do
    + def render(assigns) do
    + ~L"""
    + ~L"""
    + Count: <%= @count %>
    + Count: <%= @count %>
    + """
    + """
    + end
    + end
    +
    +
    + def mount(%{}, socket) do
    + def mount(%{}, socket) do
    + if connected?(socket), do: :timer.send_interval(1000, self(), :update)
    + if connected?(socket), do: :timer.send_interval(1000, self(), :update)
    + {:ok, assign(socket, :count, 0)}
    + {:ok, assign(socket, :count, 0)}
    + end
    + end
    +
    +
    + def handle_info(:update, socket) do
    + def handle_info(:update, socket) do
    + count = socket.assigns.count
    + count = socket.assigns.count
    + {:noreply, assign(socket, :count, count + 1)}
    + {:noreply, assign(socket, :count, count + 1)}
    + end
    + end
    +end
    +end

    View Slide

  23. diff --git a/apps/hello_web/lib/hello_web/templates/users/index.html.eex b/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    diff --git a/apps/hello_web/lib/hello_web/templates/users/index.html.eex b/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    index 45d0dd8..ebbce2b 100644
    index 45d0dd8..ebbce2b 100644
    --- a/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    --- a/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    +++ b/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    +++ b/apps/hello_web/lib/hello_web/templates/users/index.html.eex
    @@ -1,5 +1,7 @@
    @@ -1,5 +1,7 @@
    Listing Users
    Listing Users
    +<%= Phoenix.LiveView.live_render(@conn, HelloWeb.HelloLive, session: %{}) %>
    +<%= Phoenix.LiveView.live_render(@conn, HelloWeb.HelloLive, session: %{}) %>
    +
    +






    View Slide

  24. 上り!
    上り!
    diff --git a/apps/hello_web/lib/hello_live.ex b/apps/hello_web/lib/hello_live.ex
    diff --git a/apps/hello_web/lib/hello_live.ex b/apps/hello_web/lib/hello_live.ex
    index d362431..8cf71aa 100644
    index d362431..8cf71aa 100644
    --- a/apps/hello_web/lib/hello_live.ex
    --- a/apps/hello_web/lib/hello_live.ex
    +++ b/apps/hello_web/lib/hello_live.ex
    +++ b/apps/hello_web/lib/hello_live.ex
    @@ -4,16 +4,27 @@ defmodule HelloWeb.HelloLive do
    @@ -4,16 +4,27 @@ defmodule HelloWeb.HelloLive do
    def render(assigns) do
    def render(assigns) do
    ~L"""
    ~L"""
    Count: <%= @count %>
    Count: <%= @count %>
    + リバ!
    + リバ!
    """
    """
    end
    end
    def mount(%{}, socket) do
    def mount(%{}, socket) do
    if connected?(socket), do: :timer.send_interval(1000, self(), :update)
    if connected?(socket), do: :timer.send_interval(1000, self(), :update)
    - {:ok, assign(socket, :count, 0)}
    - {:ok, assign(socket, :count, 0)}
    + socket =
    + socket =
    + socket
    + socket
    + |> assign(:count, 0)
    + |> assign(:count, 0)
    + |> assign(:diff, 1)
    + |> assign(:diff, 1)
    + {:ok, socket}
    + {:ok, socket}
    + end
    + end
    +
    +
    + def handle_event("reverse", _value, socket) do
    + def handle_event("reverse", _value, socket) do
    + diff = socket.assigns.diff
    + diff = socket.assigns.diff
    + {:noreply, assign(socket, :diff, -diff)}
    + {:noreply, assign(socket, :diff, -diff)}
    end
    end
    def handle_info(:update, socket) do
    def handle_info(:update, socket) do
    count = socket.assigns.count
    count = socket.assigns.count
    - {:noreply, assign(socket, :count, count + 1)}
    - {:noreply, assign(socket, :count, count + 1)}
    + diff = socket.assigns.diff
    + diff = socket.assigns.diff
    + {:noreply, assign(socket, :count, count + diff)}
    + {:noreply, assign(socket, :count, count + diff)}
    end
    end
    end
    end
    \ No newline at end of file
    \ No newline at end of file

    View Slide

  25. Playing time.
    Playing time.

    View Slide