日曜プログラマーが錬金術やってみた！Phoenix1.4 + vue-cli の組合せ。

どうも、はじめまして。「ぱか」と呼ばれております[@u3paka](https://twitter.com/u3paka?lang=ja)です。

いつもElixir界隈の諸先生方にTwitter等々で大変お世話になっているので、初心者ながらなにか貢献できないかと思いいたりQiita初投稿やってみる次第です。幾ばくかポエミーですがご容赦ください。

実は、技術コミュニティに属して何かコミットするのは初めてだったりします。(*´ω｀*) 
Elixir とても居心地がよいので、どうぞ末永くよろしくお願いいたします。

# おしながき
ぱかのアトリエ〜エリクサーの錬金術士〜第1回目次 = ""
|> 錬金術士－アルケミスト－を夢みる
|> Phoenixを召喚する
|> Vuejsを錬金釜に投げ込む
|> はばたけ！Phoenix&Vuejs
|> まとめ

(そのうちErlang三部作()とかやってみたいですね…)

# 錬金術士－アルケミスト－を夢みる
## 本稿の動機
- 私のような日曜趣味プログラマーでもElixirとPhoenixやれる！という一事例を示すことで、Elixirの敷居が下がればいいな、という思い。
- これからやろうかなという方々に「あっ、あんな素人でもやってるんだ！ やろうかな！」と思っていただければ幸い。
- 私個人的にもメモ書きのアウトプットをしたかった。

## 本稿の目標
- Phoenix 1.4 と vue-cliを組み合わせたサンプルの雛形を作ってみる。

## (いかに私が素人かの)自己紹介と初心者友人からのQ&A
### Q 何年くらいプログラミングやっているの？
A およそ6年くらい。ただ、完全にネット独学ですし、実務経験はありません。TestやGitのノウハウよくわかりません(汗) 以前は、Python、Typescript、golangでtwitterやLINEの自動応答bot等を作ったり、C#で少しWPFやUWPのサンプルアプリケーション書いたりしていた程度です。

### Q 情報系出身ですか？
A いいえ。ただの文系出身です。高校数学は平気ですが、圏論とかわかりません。ただ、コンピューターが大好きで、いろんな言語やパラダイムを学ぶのが面白いです。最近はreduceとか使いこなせたらかっこいいなぁと思っています。

### Q どうして、Elixirを勉強しようと思ったの？
#### A 不真面目な理由
- 錬金術士になってアトリエ開くぞぉ！！！
- 厨二病が疼く数々の厨二病ライブラリ！！
- 「えりくさ」ってひらがなかわいい(仲間内で「えりちゃん語」J(   '▽' )って読んでｷｬｯｷｬしていました。)。

#### A 真面目な理由
- パイプライン|> を追いかけてきた。F#で見かけて惚れたものの、F#は難しくて挫折...
- CSP的な並行処理を追いかけてきた。golangで感動したので、似た言語を探していた。これまでの記法が再現できる！
- Twitterで出会ったコミュニティがあたたかかった。
- fukuoka.ex が頑張ってはるので、安心して知り合いにオススメできる。

### Q ElixirってRubyに似てるよね？知らないとできない？
A わたし、まともにRuby書いたことありません。「RoRと似た○○の機能」と言われてもわからないだらけでした。⌒°( ･ω･)°⌒

## 環境
- Thinkpad X1 Carbon 2017
- Windows 10 Pro 1803
- Core i7-7500U @2.70GHz
- メモリ16.0G

普通のノートパソコンです。Windowsでもできる！

# Phoenixを召喚する！
Phoenix... 不死鳥ですよ！？ なんて厨二病なネーミングw ワクワクしないわけないでしょう。
エリクサーって霊薬ですから。不死鳥くらい呼び出せるのです。

では、本題に入ります。
ElixirとPhoenix1.4のインストールは、先人方を参考にどうぞ。
(参考: https://qiita.com/piacere_ex/items/7426cff6bd64ba02d0a5 )

```
mix phx.new phx_vue --no-webpack
```

以下のように聞かれるので、Yと押します。

```
Fetch and install dependencies? [Yn] Y
* running mix deps.get
* running mix deps.compile
```

---
ちなみに、ここで```--no-webpack```をつけ忘れると、```mix phx.server```時、以下のようなエラーが。ここで数時間ロス。

```
One CLI for webpack must be installed. These are recommended choices, delivered as separate packages:
 - webpack-cli (https://github.com/webpack/webpack-cli)
   The original webpack full-featured CLI.
We will use "yarn" to install the CLI via "yarn add -D".
Do you want to install 'webpack-cli' (yes/no): yes 
#ここでフリーズしました。何度やってもだめ。なぜ？
```
---

気を取り直して、フォルダを移動します。この中で作業します。

```
cd phx_vue
```

ここで、```phx_vue/config/dev.exs```の文末を編集します。
postgresqlと接続できるよう、パスワードやユーザー名を入力します。

```elixir:phx_vue/config/dev.exs
# Configure your database
config :phx_vue, PhxVue.Repo,
  username: "postgres",
  password: "ぱすわーど",
  database: "phx_vue_dev",
  hostname: "localhost",
  pool_size: 10
```
configは便利で、ymlやtomlの設定ファイルが不要になります。

Ectoでデータベースをつくります。

```
mix ecto.create
```

うまく行けばこんな出力がでます。

```
Compiling 13 files (.ex)
Generated phx_vue app
The database for PhxVue.Repo has already been created
```

この時点で、サーバーがもう立ち上がりますので、一旦たててみます。
この初回だけは、管理者権限でやります。

```
mix phx.server
```
http://localhost:4000 でいつもの初期画面がみられます。
![phoenix_standard.png](https://qiita-image-store.s3.amazonaws.com/0/318136/e77a307f-4e97-45a9-917a-8e4487e82e45.png)

不死鳥を手元に召喚することに成功しました！
ここまでは、先人方の解説をなぞったものです。

# Vue.jsを錬金釜に投げ込む！
ここからが、ポイント。
アルケミストって...違う素材を混ぜ合わせて、「錬金」するんですよね。
vue.jsを錬金釜に投げ込んでいきます。

Phoenixとvue.jsを混ぜ合わせるには、いくつか選択肢があります。

### Vueを組み合わせる選択肢
1. CDNを```lib/phx_vue_web/templates/page/index.html.eex```内にべた書き。（参考: https://qiita.com/koga1020/items/c02a0fd5ae11fb5da1e0 ）
1. ```assets/js```を作って```app.js```と```XXX.vue```のvueコンポーネントを組み合わせる。
1. ```vue-cli```を使う。

vue.jsを初利用ならば、CDNが気軽に試せてよいでしょう。[-> 1の選択肢]
また、先人の例では、2の方法もあります。[-> 2の選択肢]
（参考：https://qiita.com/KumanoT/items/ba3598baabd42861afdf ）
今回は、あまり日本語解説が出回っていない3の選択肢```vue-cli```で組み合わせてみます。

### vue-cliと組み合わせるメリット
1. vue-cliがよしなにvue関連の設定（Typescriptやscss）をやってくれるのでラク。
2. vue と Phoenix とで役割分担の明確化ができる(Phoenixでは、mix phx.gen.jsonに専念できる。)。

(参考: https://gist.github.com/jpbecotte/d37260ecd64fc4cbef7e9dbbf7f6bef3 )
しかし、リンク先のままではまともに動かないので、手を加えつつ説明を続けます。

## vue-cliのインストールからプロジェクト作成まで
まず、vue-cliをインストールします。yarnかnpmは使えるようにしてください。

```
yarn global add @vue/cli
npm install -g @vue/cli #(npmならば)
```

vueが使えるか確認。

```
vue -V
#=> 3.2.1
```

vueのプロジェクトを作ります。ここでは、便宜的にプロジェクト名を```assets```にしています。お好きなように読み替えてください。

```
vue create assets
```
Mannually select　を選ぶとずらずら選択肢が出てきます。Typescriptなり、Scssなりお好みでどうぞ。

```
Vue CLI v3.2.1
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, PWA, Router, Vuex, CSS Pre-processors, Linter,
Unit
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS
? Pick a linter / formatter config: TSLint
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
```
Jestとかよくわかってませんが、こんな感じで答えていきます。

とりあえずビルドやってみましょう。

まずは```vue.config.js```ファイルを```assets```直下に作ります。

```javascript:phx_vue/assets/vue.config.js
const path = require('path');

module.exports = {
  lintOnSave: true,
  outputDir: path.resolve(__dirname, '../priv/static'),
};

```
ビルド後のアウトプット先をphoenixがStatic Serveできる```phx_vue/priv/static```に指定します。

## phoenix側の微調整
出力されるindex.htmlをPageControllerで捌いてあげます。

（他にもテンプレート内に埋め込むとか書きようがありそう）。

```elixir:phx_vue/lib/phx_vue_web/controllers/page_controller.ex
defmodule PhxVueWeb.PageController do
  use PhxVueWeb, :controller

  # def index(conn, _params) do
  #   render(conn, "index.html")
  # end
  # 上を下に書き換える。
  def index(conn, _) do
    conn
    |> put_resp_header("content-type", "text/html; charset=utf-8")
    |> Plug.Conn.send_file(200, "priv/static/index.html")
    |> halt()
  end
end
```

ちなみに、この```index(conn, _)```は、```router.ex```につながっています。

```elixir:phx_vue/lib/phx_vue_web/router.ex
defmodule PhxVueWeb.Router do
##　～省略～
 scope "/", PhxVueWeb do
    pipe_through :browser

    get "/", PageController, :index # <- これ！
  end
end
```

# はばたけ！Phoenix&Vuejs！
それでは、Phoenixを起動してみます。
windowsではiex.bat なので注意！--werl つけるとTab補完が効くようになります。

```
iex.bat --werl -S mix phx.server
```

http://localhost:4000/ で以下のように表示されるはずです。
![vue-app_1.png](https://qiita-image-store.s3.amazonaws.com/0/318136/4c88004d-59fa-c7d1-9cab-44712e63dd8a.png)

あれ？ロゴがうまく処理できていませんね。
これは、Static Serveが上手くいっていないから。以下のようにエンドポイントを修正！
なお、priv/static以下をサーブしてくれます。

```elixir:/phx_vue/lib/phx_vue_web/endpoint.ex
  plug Plug.Static,
    at: "/",
    from: :phx_vue,
    gzip: false,
    # only: ~w(css fonts images js favicon.ico robots.txt)
    # img を加えてあげる。
    only: ~w(css fonts images img js favicon.ico robots.txt)

```
onlyの行をまるごとコメントアウトすると何でもサーブします。
(参考: https://qiita.com/sand/items/40a281e3f1f4467fd779 )

Elixir初めての人が思うこと。
~wってなんやねん！ これはSigilです。すなわち「印－In－」。呪文詠唱とかに組むアレです！なんて厨二病なんだ…  
> シジルまたはシギル（英: sigil, 羅: sigillum）は主に西洋魔術で使われる図形、記号、紋章、線形である。

(参考: https://ja.m.wikipedia.org/wiki/シジル_(オカルト) )

実際はいい感じに文字列やリストを生成してくれる便利機能です。

```
iex> ~w(foo bar bat)
["foo", "bar", "bat"]
```

(参考: https://elixir-lang.org/getting-started/sigils.html https://qiita.com/udzura/items/6bc11305b178ad65de8e )

## 成功！
話が脱線しました。
http://localhost:4000 を再読込してみます。
Phoenixのサーバーは何もしなくてもHot reloadが走ります。素晴らしい！！

下のように描写されれば成功です！

![vue-success.png](https://qiita-image-store.s3.amazonaws.com/0/318136/23709d5b-cf6d-cc3f-6a9c-3589731e920d.png)

## Vuejsの監視も加える
なお、vue側のwebpackは、elixirのwatcherで設定できます。
windowsだとnpmの権限がうまく通らないので、直に指定してあげるとうまくいきます。

```
config :phx_vue, PhxVue.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
+  watchers: [node: ["node_modules/@vue/cli-service/bin/vue-cli-service.js","serve", cd: Path.expand("../assets", __DIR__)]]
```

ただ、出力が混ざってあまり綺麗じゃないので、watcherを使わずに別窓で

```
yarn serve
```

するのもアリだと思います。

結果、vueコンポーネントを弄ろうが、Phoenix側を弄ろうが、再読み込みが走ってウェブに反映されます。

# まとめ
初心者の私でも、Elixir with vue-cliできました！

**私の思うElixir = 言語
|> (精神的に)気楽
|> (書いていて)楽しい
|> (データ変換が)気持ちいい
|> (パイプラインが)イケてる
|> (コミュニティが)あたたかい**

Elixir側のJSON API、Ectoとの付き合い方、Vueの書き方等々続くかも…

駄文失礼しました。読んでいただきありがとうございました。