この記事は、Elixir その2 Advent Calendar 2020 3日目です。
前日は、LiveView uploadsを動かす 🎉🎉🎉(Elixir/Phoenix)でした。
2021/07/29(月) 追記
この記事はSurface 0.1.0時点のものです。
2021/07/19(月)時点では、だいぶ変わっているようですので、公式のドキュメントご確認ください
@piacerex さんにコメントいただきました。ありがとうございます!
https://qiita.com/torifukukaiou/items/b5ae9eac42bd304b7aa3#comment-b883f2c4088f456d49a3
はじめに
- Surfaceをつかってみます
- つい先日、
0.1.0
がリリースされたばかりのHexです- 2020/11/28現在、最新は
0.1.1
です
- 2020/11/28現在、最新は
- この記事では、導入方法ととりあえず使ってみましたということまで書いておきます
- http://surface-demo.msaraiva.io/properties
- ↑このページのサンプルと同じことをやってみます
使ったバージョン
- Elixir: 1.10.4-otp-23
- mix phx.new -v: v1.5.6
- node -v: v12.18.3
- psql --version: psql (PostgreSQL) 12.4
ソースコード
デモ
-
https://triangular-basic-budgie.gigalixirapp.com/my-button
- Gigalixirで動かしていますのでどうぞ触ってみてください
- Gigalixirへのデプロイに興味のある方は、手間味噌な記事ですがHello Gigalixir (Phoenix/Elixir)などを参考に、公式ページをご参照ください
- しばらくはそのまま動かしておきます
- アクセスできませんでしたら、他に興味が移って他のものを動かしているのだとご理解ください
- ボタンがくるくるしたり、角が丸くなったりするだけのものです
- 今回公開している内容は以上です
0. 準備
- それではまずElixirをインストールしましょう
- 手前味噌な記事ですがインストールなどを参考にしてください
-
phx_new
、node.js
、PostgreSQL
などを公式ドキュメントを参考にインストールしてください
1. プロジェクトの作成
$ mix phx.new my_web --live
$ cd my_web
$ mix ecto.create
2. Surfaceの導入
- Getting Startedを参考に進めます
deps/0
mix.exs
@@ -37,7 +37,7 @@ defmodule MyApp.MixProject do
{:phoenix_ecto, "~> 4.1"},
{:ecto_sql, "~> 3.4"},
{:postgrex, ">= 0.0.0"},
- {:phoenix_live_view, "~> 0.14.6"},
+ {:phoenix_live_view, "~> 0.15.0", override: true},
{:floki, ">= 0.27.0", only: :test},
{:phoenix_html, "~> 2.11"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
@@ -46,7 +46,8 @@ defmodule MyApp.MixProject do
{:telemetry_poller, "~> 0.4"},
{:gettext, "~> 0.11"},
{:jason, "~> 1.0"},
- {:plug_cowboy, "~> 2.0"}
+ {:plug_cowboy, "~> 2.0"},
+ {:surface, "~> 0.1.0"}
]
end
import Surface
を追加します
lib/my_app_web.ex
def view do
quote do
use Phoenix.View,
root: "lib/my_app_web/templates",
namespace: MyAppWeb
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_flash: 1, get_flash: 2, view_module: 1, view_template: 1]
# Include shared imports and aliases for views
unquote(view_helpers())
import Surface
end
end
Bulmaを追加
lib/my_app_web/templates/layout/root.html.leex
@@ -8,6 +8,7 @@
<%= live_title_tag assigns[:page_title] || "MyApp", suffix: " · Phoenix Framework" %>
<link phx-track-static rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
<script defer phx-track-static type="text/javascript" src="<%= Routes.static_path(@conn, "/js/app.js") %>"></script>
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.8.0/css/bulma.min.css" />
</head>
<body>
<header>
.formatter.exs
.formatter.exs
[
- import_deps: [:ecto, :phoenix],
+ import_deps: [:ecto, :phoenix, :surface],
inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs}"],
subdirectories: ["priv/*/migrations"]
]
Visual Studio Code
- Visual Studio Codeをお使いの方はこちらのExtensionを追加しておくとよいでしょう
mix setup
$ mix setup
-
mix setup
はmix.exs
に定義されているaliasです -
["deps.get", "ecto.setup", "cmd npm install --prefix assets"]
をやってくれます-
ecto.setup
は["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"]
をやってくれます
-
- これで準備は整いました
2. ソースコードを書く
lib/my_app_web/live/components/my_button.ex
lib/my_app_web/live/components/my_button.ex
defmodule MyAppWeb.Components.MyButton do
use Surface.Component
prop loading, :boolean
prop rounded, :boolean
def render(assigns) do
~H"""
<button class={{ "button", "is-info", "is-loading": @loading, "is-rounded": @rounded }}>
<slot/>
</button>
"""
end
end
-
propとか
~H
とかPhoenixの経験がある方でもはじめてみるものではないかとおもいます -
Componentを
lib/my_app_web/live/components
の下に配置したのは、The Pragmatic StudioのPhoenix LiveView courseを参考にしてみました- 公開されているソースコード
lib/my_app_web/live/my_button_live.ex
lib/my_app_web/live/my_button_live.ex
defmodule MyAppWeb.MyButtonLive do
use Surface.LiveView
alias MyAppWeb.Components.MyButton
data loading, :boolean, default: false
data rounded, :boolean, default: false
def mount(_params, _session, socket) do
socket = Surface.init(socket)
{:ok, assign(socket, checkboxes: [])}
end
def render(assigns) do
~H"""
<MyButton loading={{ @loading }} rounded={{ @rounded }}>
Change my style!
</MyButton>
<form phx-change="check_changed" style="margin-top: 30px">
<input type="hidden" name="checkboxes[]" value="" />
<label class="checkbox">
<input type="checkbox" name="checkboxes[]" value="loading" checked={{ @loading }}>
Loading
</label>
<label class="checkbox" style="margin-left: 20px">
<input type="checkbox" name="checkboxes[]" value="rounded" checked={{ @rounded }}>
Rounded
</label>
</form>
<a href="https://qiita.com/torifukukaiou/items/b5ae9eac42bd304b7aa3">Surfaceをつかってみる(Elixir/Phoenix)</a>
"""
end
def handle_event(
"check_changed",
%{"_target" => ["checkboxes"], "checkboxes" => checkboxes},
socket
) do
loading = Enum.any?(checkboxes, &(&1 == "loading"))
rounded = Enum.any?(checkboxes, &(&1 == "rounded"))
{:noreply, assign(socket, loading: loading, rounded: rounded)}
end
end
lib/my_app_web/router.ex
lib/my_app_web/router.ex
scope "/", MyAppWeb do
pipe_through :browser
live "/", PageLive, :index
live "/my-button", MyButtonLive # add
end
3. Run
$ mix phx.server
Wrapping Up
- Surfaceをとりあえず使ってみました
- 大注目のHexです
- 私はVue.jsは詳しくない1のですが、ファミリアーな方は
<span v-once>This will never change: {{ msg }}</span>
こういう書き方と似ているようように感じていただけたのではないでしょうか - Enjoy Elixir !!!
-
たいていの他のこともたいして詳しいわけではない ↩