スポンサーリンク

2016年4月20日

Using webpack with Phoenix-Framework

Goal

  • PhoenixへWebpackを導入する

Dev-Environment

  • OS: Windows8.1
  • Erlang: Eshell V7.3, OTP-Version 18.3
  • Elixir: v1.2.3
    • Phoenix: v1.1.4

Using webpack with Phoenix-Framework

昨日、WebpackをPhoenixへ導入したのですが、
エラーの嵐が起きたので自分が使う最小構成を忘れないための備忘録として残します。
しかしながら、フロントエンドについて私は詳しくないため、
間違えている可能性があります。その点は留意してください。
とりあえず、動かす分には問題ないです。
全体の流れとしては以下のようになります。
  1. 検証用プロジェクトを作成する。
  2. package.jsonを編集する。
  3. brunch-config.jsを削除する。
  4. app.cssをリネームする。(app.css -> app.scss)
  5. npmでwebpackをインストールする。(config/dev.exsも編集する)
  6. npmのパッケージを追加する。(app.scssも編集する)
  7. webpack.config.jsを作成する。
  8. 実行し確認する。

Create Project

検証用のプロジェクトを作成します。
> cd path/to/create/directory
> mix phoenix.new using_webpack
...

Fetch and install dependencies? [Yn] n
...

> cd using_webpack

Edit and delete files

package.jsonを以下のように編集します。

File: package.json

{
  "name": "using_webpack",
  "version": "1.0.0",
  "description": "To start your new Phoenix application:",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "compile": "webpack -p"
  },
  "repository": {
  },
  "dependencies": {
  }
}
brunch-config.jsを削除します。

Example:

> rm brunch-config.js
app.cssファイルをリネームします。

Before: web/static/css/app.css

After: web/static/css/app.scss

Install webpack

npmからwebpackをインストールします。

Example:

> npm install --save-dev webpack
...
Phoenixのconfigファイルを編集します。

File: config/dev.exs

use Mix.Config

# For development, we disable any cache and enable
# debugging and code reloading.
#
# The watchers configuration can be used to run external
# watchers to your application. For example, we use it
# with brunch.io to recompile .js and .css sources.
config :using_webpack, UsingWebpack.Endpoint,
  http: [port: 4000],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
  watchers: [node: ["node_modules/webpack/bin/webpack.js",
                   "--watch-stdin", "--progress", "--colors"]]

...

Package install

実行に必要となるパッケージをインストールします。
> npm install --save file:deps/phoenix_html file:deps/phoenix
...

> npm install --save-dev babel-loader babel-core babel-preset-es2015
...

> npm install --save-dev css-loader style-loader extract-text-webpack-plugin
...

> npm install --save-dev bootstrap-sass node-sass sass-loader url-loader file-loader
...

> npm install --save-dev copy-webpack-plugin
...
ここら辺は本当に知識がないので、不要なパッケージが入ってないかは検証していません。
現状のpackage.jsonの中身は以下のようになっています。

File: package.json

{
  "name": "using_webpack",
  "version": "1.0.0",
  "description": "To start your new Phoenix application:",
  "main": "index.js",
  "directories": {
    "test": "test"
  },
  "scripts": {
    "compile": "webpack -p"
  },
  "repository": {},
  "dependencies": {
    "phoenix": "file:deps\\phoenix",
    "phoenix_html": "file:deps\\phoenix_html"
  },
  "devDependencies": {
    "babel-core": "^6.7.6",
    "babel-loader": "^6.2.4",
    "babel-preset-es2015": "^6.6.0",
    "bootstrap-sass": "^3.3.6",
    "copy-webpack-plugin": "^2.1.1",
    "css-loader": "^0.23.1",
    "extract-text-webpack-plugin": "^1.0.1",
    "file-loader": "^0.8.5",
    "node-sass": "^3.4.2",
    "sass-loader": "^3.2.0",
    "style-loader": "^0.13.1",
    "url-loader": "^0.5.7",
    "webpack": "^1.13.0"
  }
}
app.scssを編集します。
app.scssの1~5行目を削除し、
コメントでbootstrap-sassと記述している部分の追加してください。

File: web/static/css/app.scss

/* bootstrap-sass */
$icon-font-path: "~bootstrap-sass/assets/fonts/bootstrap/";
@import "~bootstrap-sass/assets/stylesheets/_bootstrap.scss";

/* Space out content a bit */
...

Note:

1~5行目があると何故かコンパイルが通らないんですよね...何ででしょう?
私の環境の構成に問題があるのでしょうか?

Create webpack.config.js

webpack.config.jsを新しく作成し、以下のように編集してください。
コピペでいいと思います。私も内容については何となく程度にしか分かってないです(汗顔の至り)

File: webpack.config.js

var ExtractTextPlugin = require("extract-text-webpack-plugin");
var CopyWebpackPlugin = require("copy-webpack-plugin");

module.exports = {
  devtool: "source-map",
  entry: [
    "./web/static/js/app.js",
    "./web/static/css/app.scss"
  ],
  output: {
    path: "./priv/static",
    filename: "js/app.js"
  },

  resolve: {
    modulesDirectories: [
      __dirname + "/web/static/js",
      __dirname + "/node_modules"
    ],
    extensions: ["", ".js"],
    alias: {
      phoenix_html:
        __dirname + "/deps/phoenix_html/web/static/js/phoenix_html.js",
      phoenix:
        __dirname + "/deps/phoenix/web/static/js/phoenix.js"
    }
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel",
        query: {
          presets: ["es2015"]
        }
      },
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract("style", "css")
      },
      {
        test: /\.scss$/,
        loader: ExtractTextPlugin.extract("style", "css!sass")
      },
      {
        test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/font-woff"
      },
      {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=application/octet-stream"
      },
      {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        loader: "file"
      },
      {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        loader: "url?limit=10000&mimetype=image/svg+xml"
      }
    ]
  },

  plugins: [
    new ExtractTextPlugin("css/app.css"),
    new CopyWebpackPlugin([{ from: "./web/static/assets" }])
  ]
}

Let’s “mix phoenix.server”

色々と設定ばかりでしたが、ようやっと実行です。

Example:

> mix phoenix.server
[info] Running UsingWebpack.Endpoint with Cowboy using http on port 4000
Hash:  [1m55c4b6e6e179ce4eac89 [22m
Version: webpack  [1m1.13.0 [22m
Time:  [1m16172 [22mms
                                  [1mAsset [22m        [1mSize [22m   [1mChunks [22m   [1m [22m            [1mChunk Names [22m
                            [1m [32mcss/app.css [39m [22m     153 kB        [1m0 [22m   [1m [32m[emitted] [39m [22m  main
   [1m [32mf4769f9bdb7466be65088239c12046d1.eot [39m [22m    20.1 kB         [1m [22m   [1m [32m[emitted] [39m [22m
  [1m [32mfa2772327f55d8198301fdb8bcfc8158.woff [39m [22m    23.4 kB         [1m [22m   [1m [32m[emitted] [39m [22m
   [1m [32me18bbf611f2a2e43afc071aa2f4e1512.ttf [39m [22m    45.4 kB         [1m [22m   [1m [32m[emitted] [39m [22m
   [1m [32m89889688147bd7575d6327160d64e760.svg [39m [22m     109 kB         [1m [22m   [1m [32m[emitted] [39m [22m
                              [1m [32mjs/app.js [39m [22m    2.38 kB        [1m0 [22m   [1m [32m[emitted] [39m [22m  main
 [1m [32m448c34a56d699c29117adc64c43affeb.woff2 [39m [22m      18 kB         [1m [22m   [1m [32m[emitted] [39m [22m
                          [1m [32mjs/app.js.map [39m [22m    3.54 kB        [1m0 [22m   [1m [32m[emitted] [39m [22m  main
                        [1m [32mcss/app.css.map [39m [22m   88 bytes        [1m0 [22m   [1m [32m[emitted] [39m [22m  main
                            [1m [32mfavicon.ico [39m [22m    1.26 kB         [1m [22m   [1m [32m[emitted] [39m [22m
                             [1m [32mrobots.txt [39m [22m  202 bytes         [1m [22m   [1m [32m[emitted] [39m [22m
                     [1m [32mimages/phoenix.png [39m [22m    13.9 kB         [1m [22m   [1m [32m[emitted] [39m [22m
   [0]  [1mmulti main [22m 40 bytes { [1m [33m0 [39m [22m} [1m [32m [built] [39m [22m
    + 11 hidden modules
Child  [1mextract-text-webpack-plugin [22m:
        + 7 hidden modules
コンパイルエラーなしを確認したら、ブラウザからも実行を確認しましょう。
いつものWelcomeページが表示されていれば問題なしです。

Note:

少し疑問が残りました。

PhoenixではデフォルトでBootstrapを使っているので、
bootstrap-sassパッケージを入れないとbootsrapのディレクトリやファイルがないとエラーが出ます。
しかし、Phoenixがデフォルトで使っているbrunchでは、上記のパッケージを使ってないんですよね。
何れかのパッケージに入っているのか、どこから参照しているのかさっぱり分からないんです。

まぁ、いずれ必要があれば調べます。
フロントエンド周りはさっぱりなので、できれば最小限の知識だけで切り抜けたい...
昨日のAM03:00くらいまでエラーとりしてました。
ここまでコンパイルエラーで止まったの久々です。
誰かの参考になったら、この上ない喜びです><

Bibliography

2016年4月19日

How to use SASS/SCSS in phoenix-framework.

Goal

  • PhoenixでSASS/SCSSを使う

Dev-Environment

  • OS: Windows8.1
  • Erlang: Eshell V7.3, OTP-Version 18.3
  • Elixir: v1.2.3
    • Phoenix: v1.1.4

How to use SASS/SCSS in phoenix-framework.

PhoenixでSASS/SCSSを使ってみたいと思います。
何故いきなり、SASSやSCSSを使おうと考えたのかといいますと、
Bootstrap4からSASSが使えるようになったからですね。
そこで、せっかくなのでPhoenixでも使えないかと思い調べたのですが、
かなり簡単にできることが分かりましたので使ってみようと思います。
全体の流れとしては以下のようになります。
  1. 検証用プロジェクトを作成する。
  2. npmのパッケージを追加する。(Package: sass-brunch)
  3. app.cssファイルを.sassまたは.scssにリネームする。
  4. 実行し、デザインに反映されているか確認する。
  5. .sass/.scssファイルがコンパイルされ、.cssファイルが生成されていることを確認する。
パッケージを追加する際のやり方ですが、二通りあります。
一つは、—no-brunchオプションを使い、package.jsonに追記を行った後に”npm install”する。
もう一つは、通常のとおりプロジェクトを作成し、個別でsass-brunchパッケージを追加する方法です。
大した違いではないですが、お好きな方を使えばいいと思います。
今回は、後者の方法を使って検証していきます。

Create Project

検証用のプロジェクトを作成します。
> cd path/to/create/directory
> mix phoenix.new sass_support
...

> cd sass_support

Add npm package

パッケージを追加する前にpackage.jsonを確認してみます。

File: package.json

{
  "repository": {
  },
  "dependencies": {
    "babel-brunch": "~6.0.0",
    "brunch": "~2.1.3",
    "clean-css-brunch": "~1.8.0",
    "css-brunch": "~1.7.0",
    "javascript-brunch": "~1.8.0",
    "uglify-js-brunch": "~1.7.0",
    "phoenix": "file:deps/phoenix",
    "phoenix_html": "file:deps/phoenix_html"
  }
}
上記のパッケージへsass-brunchが追加されれば良いわけですね。
“dependencies”に追記もして欲しいので、—saveオプションを使います。
また、今回はローカルのプロジェクトのみで利用できればよいので、-gオプションは使いません。

Example:

> npm install sass-brunch --save
...長いので割愛
package.jsonにも追加されているか確認してみましょう。

File: package.json

{
  "repository": {},
  "dependencies": {
    ...
    "sass-brunch": "^2.6.2",
    ...
  }
}
問題なく追加されていますね。
ちゃんとインストールされたか気になるようであれば、
パッケージの一覧を見てみるのもいいと思います。
(コマンド実行時にパッケージの一覧も表示されています)

Rename app.css -> app.sass or app.scss

Phoenixのプロジェクト作成時、デフォルトで生成されているapp.cssをリネームします。
自前で.sass/.scssファイルを用意してもいいのですが、ちょっと面倒くさいので…

Before: priv/static/css/app.css

After: priv/static/css/app.scss

Let’s “mix phoenix.server”.

さてさて、ようやっと実行まできました。
何も考えないで実行してみましょう。

Example:

> mix phoenix.server
...
ブラウザから確認してみましょう…問題なしですね!
また、priv/static/css配下にapp.cssが生成されています。
こちらも合わせ確認してみてください。
今回は以上になります。
誰かの参考になったら、この上ない喜びです><

Bibliography

2016年4月18日

Using gen_udp module in elixir

とある錬金術師の万能薬(Elixir)

Goal

  • gen_udpの簡単なサンプルを実装する

Dev-Environment

  • OS: Windows8.1
  • Erlang: Eshell V7.3, OTP-Version 18.3
  • Elixir: v1.2.3

Using gen_udp module in elixir

gen_udpを使ってみたいと思います。
pingと文字列を渡して、pongと文字列を返すだけの簡単なサンプルの実装になります。
(ローカルホスト内で行っています)

gen_udp module sample

コネクションレスなUDPを使ってサーバとクライアントで通信を取ってみましょう。
全体の処理における流れは以下のようになります。
  1. [server]:gen_udp.open/2でUDPソケットをオープンにする。
  2. [client]:gen_udp.open/2でUDPソケットをオープンにする。
  3. [client]:gen_udp.send/4でサーバへデータを送信する。
  4. [server]クライアント側からのデータを受信し処理する。
  5. [server]:gen_udp.send/4でクライアント側へデータを送信する。
  6. [client]サーバ側からのデータを受信し処理する。(応答が確実ではないのでタイムアウトを設定しています)
  7. [client]:gen_udp.close/1でソケットを閉じる。
ざっと処理を書いていくとこんな感じになります。
サーバの実装は以下のようになります。

File: simple_udp_server.ex

defmodule SimpleUdpServer do
  def start_server do
    {:ok, socket} = :gen_udp.open(1234, [:binary])
    loop
  end

  defp loop do
    receive do
      {:udp, socket, host, port, bin} ->
        :io.format("server receive binary = ~p~n", [bin])
        str = :erlang.binary_to_term(bin)
        :io.format("server unpacked = ~p~n", [str])
        :gen_udp.send(socket, host, port, :erlang.term_to_binary('pong'))
        loop
    end
  end
end
次は、クライアントの実装になります。

File: simple_udp_client.ex

defmodule SimpleUdpClient do
  def ping do
    {:ok, socket} = :gen_udp.open(4321, [:binary])
    :ok = :gen_udp.send(socket, 'localhost', 1234,
                        String.to_char_list("ping") |> :erlang.term_to_binary)

    value = receive do
      {:udp, _socket, _, _, bin} ->
        :io.format("Client received binary = ~p~n", [bin])
        str = :erlang.binary_to_term(bin)
        :io.format("Client result = ~p~n", [str])
        {:ok, str}
    after
      2_000 -> :error
    end

    :gen_udp.close(socket)
    value
  end
end
gen_tcpと同じく注意点としては、バイナリでやり取りしているのでバイナリへ変換していることと、
stringではなく、char_listで送っている点です。
またgen_tcpと違って、”socket closed”のメッセージを受け取ることを考えなくてよい。
実行してみましょう。ターミナルが二つ必要になります。

Example:

  • ターミナル1(Server)
iex> SimpleUdpServer.start_server
...

# ターミナル2を実行すると下記のように出力される
server receive binary = <<131,107,0,4,112,105,110,103>>
server unpacked = "ping"
  • ターミナル2(Client)
iex> SimpleUdpClient.ping
Client received binary = <<131,107,0,4,112,111,110,103>>
Client result = "pong"
{:ok, 'pong'}

Note:

こっちもinetモジュールを使って色々とアクセス元の情報を取得できる。

Bibliography

人気の投稿