LoginSignup
4
6

More than 5 years have passed since last update.

ElmのチュートリアルアプリをDocker + Webpack4 で試してみたメモ

Last updated at Posted at 2018-02-27

elmチュートリアルアプリケーションの開始を試してみた時に、つまづいたりしたのでメモ。

動作環境

  • windows10
  • vagrant2.0.2
  • virtualbox5.1.26
  • ubuntu-16.04
  • Docker version 17.09.0-ce, build 19e2cf6
  • docker-compose version 1.18.0, build 8dd22a9

動かした環境のpackage.json

チュートリアルと異なるのはwebpackのバージョンが4になっていること。
これで結構ハマった。

package.json
{
  "name": "app",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start":  "nf start", 
    "client": "webpack-dev-server", 
    "build":  "webpack", 
    "api":    "node api.js", 
    "test":   "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "ace-css": "^1.1.0",
    "css-loader": "^0.28.10",
    "elm": "^0.18.0",
    "elm-webpack-loader": "^4.4.0",
    "file-loader": "^1.1.10",
    "font-awesome": "^4.7.0",
    "sanitize.css": "^5.0.0",
    "style-loader": "^0.20.2",
    "url-loader": "^0.6.2",
    "webpack": "^4.0.1"
  },
  "devDependencies": {
    "elm-test": "^0.18.12",
    "foreman": "^2.0.0",
    "json-server": "^0.12.1",
    "webpack-cli": "^2.0.9",
    "webpack-dev-server": "^3.0.0"
  }
}

ソースコード

環境

チュートリアルのままでは、elm-webpack-loaderでエラーが起こりwebpack4で動かなかった。
エラーの原因であるwebpack3でdeprecateで4で消えたthis.optionsを、this.queryに置換している。*
これ、プルリクとか出したほうがいいのだろうか。やったことないけれど。

docker/elm-dev/Dockerfile
FROM node:9.6.0

# コンテナ上の作業ディレクトリ作成
WORKDIR /app

# 後で確認出来るようにpackage.jsonを作成
RUN npm init -y

# elmインストール
RUN npm i -S elm
RUN npm i -D elm-test
RUN npx elm package install elm-lang/html -y

# webpackv4
RUN npm i -S webpack
# v4から追加
RUN npm i -D webpack-cli
# 開発サーバ
RUN npm i -D webpack-dev-server
# loader
RUN npm i -S elm-webpack-loader
RUN npm i -S file-loader
RUN npm i -S css-loader
RUN npm i -S style-loader
RUN npm i -S url-loader

# バックエンド
RUN npm i -D json-server

# サーバ複数起動用
RUN npm i -D foreman

# フロントエンド
RUN npm i -S sanitize.css
RUN npm i -S ace-css
RUN npm i -S font-awesome

# "source-directories": [ "src" ], に変更
RUN sed -i -e "s/\".\"/\"src\"/" /app/elm-package.json

# package.json設定
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n    \"api\": \"node api.js\", /" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n    \"build\": \"webpack\", /" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n    \"client\": \"webpack-dev-server\", /" /app/package.json
RUN sed -i -e "s/\(\"scripts\": {\)/\1\n    \"start\": \"nf start\", /" /app/package.json

# https://medium.com/webpack/webpack-4-migration-guide-for-plugins-loaders-20a79b927202
# deprecateなthis.optionsをthis.queryに置き換え。
RUN sed -i -e "s/this\.options/this\.query/g" /app/node_modules/elm-webpack-loader/index.js
docker/docker-compose.yml
version: '3'
services:
  elm-dev:
    build: ./elm-dev
    volumes:
      - ../tutorial/webpack.config.js:/app/webpack.config.js
      - ../tutorial/api.js:/app/api.js
      - ../tutorial/db.json:/app/db.json
      - ../tutorial/src:/app/src
      - ../tutorial/Procfile:/app/Procfile
      - ../tutorial/dist:/app/dist
    ports:
      - 3000:3000
      - 4000:4000
    command: [yarn, start]

dev-serverの設定をdockerとvagrantを使用したときの書き方に。

tutorial/webpack.config.js
var path = require("path");

const env = process.env.NODE_ENV;

module.exports = {
  mode: env || `development`,
  entry: {
    app: [
      './src/index.js'
    ]
  },

  output: {
    path: path.resolve(__dirname + '/dist'),
    filename: '[name].js',
  },

  module: {
    rules: [
      {
        test: /\.(css|scss)$/,
        use: [
          'style-loader',
          'css-loader',
        ]
      },
      {
        test:    /\.html$/,
        exclude: /node_modules/,
        loader:  'file-loader?name=[name].[ext]',
      },
      {
        test:    /\.elm$/,
        exclude: [/elm-stuff/, /node_modules/],
        loader:  'elm-webpack-loader?verbose=true&warn=true',
      },
      {
        test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'url-loader?limit=10000&mimetype=application/font-woff',
      },
      {
        test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
        loader: 'file-loader',
      },
    ],

    noParse: /\.elm$/,
  },

  // 開発サーバの設定
  devServer: {
    // インラインモード
    inline: true,
    stats: { colors: true },
    // 3000番ポートで起動
    port: 3000,
    // dockerのコンテナ上でサーバを動かすときは以下の設定で全ての接続を受け入れる
    host:"0.0.0.0",
  },
  // Windowsのvagrantの仕様でポーリングしないとファイルの変更を感知できない
  watchOptions: {
    aggregateTimeout: 300,
    // 5秒毎にポーリング
    poll: 5000
  },
};

foreman用の設定。
yarnはdockerのnode9.6だと最初から入っている。

tutorial/Procfile
api: yarn api
client: yarn client

バックエンド

ここはチュートリアルどおり。

tutorial/api.js
var jsonServer = require('json-server')

// Returns an Express server
var server = jsonServer.create()

// Set default middlewares (logger, static, cors and no-cache)
server.use(jsonServer.defaults())

var router = jsonServer.router('db.json')
server.use(router)

console.log('Listening at 4000')
server.listen(4000)
tutorial/db.json
{
  "players": [
    { "id": "1", "name": "Sally", "level": 2 },
    { "id": "2", "name": "Lance", "level": 1 },
    { "id": "3", "name": "Aki", "level": 3 },
    { "id": "4", "name": "Maria", "level": 4 },
    { "id": "5", "name": "Julian", "level": 1 },
    { "id": "6", "name": "Jaime", "level": 1 }
  ]
}

フロントエンド

こちらもチュートリアルどおり。

tutorial/src/index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Elm SPA example</title>
  </head>
  <body>
    <div id="main"></div>
    <script src="/app.js"></script>
  </body>
</html>
tutorial/src/index.js
'use strict';

require('ace-css/css/ace.css');
require('font-awesome/css/font-awesome.css');

// index.htmlがdistにコピーされるようにRequireする
require('./index.html');

var Elm = require('./Main.elm');
var mountNode = document.getElementById('main');

// .embed()はオプションの第二引数を取り、プログラム開始に必要なデータを与えられる。たとえばuserIDや何らかのトークンなど
var app = Elm.Main.embed(mountNode);
tutorial/src/Main.elm
module Main exposing (..)

import Html exposing (Html, div, text, program)

-- モデル


type alias Model =
    String


init : ( Model, Cmd Msg )
init =
    ( "Hello", Cmd.none )



-- メッセージ


type Msg
    = NoOp



-- ビュー


view : Model -> Html Msg
view model =
    div []
        [ text model ]



-- 更新


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        NoOp ->
            ( model, Cmd.none )



-- サブスクリプション(購読)


subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.none



-- MAIN


main : Program Never Model Msg
main =
    program
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }

確認

docker-compose upで起動。
vagrantで作った仮想環境のIPが192.168.50.10だとして以下のように確認。

サーバのテスト。db.jsonのid:1のデータが表示されればOK
http://192.168.50.10:4000/players/1

フロントエンドのテスト。Helloと出力されていればOK
http://192.168.50.10:3000

webpack-dev-server3.0ではホットロードがデフォルトらしく、Main.elmのHelloを書き換えるとブラウザが自動的に更新される。

この時点のソース

チュートリアル終了時のソース

参考

elmチュートリアル
elm思考法
tutorial source
アプリケーションの開始
最新版で学ぶWebpack4のモジュールハンドラ
gulpでwebpack4
次のリリースであるwebpack 4の主な変更点まとめ
webpack 4: migration guide for plugins/loaders
elm-webpack-loader
example
Elmでオブジェクト指向プログラマのための関数型入門
webpack4が出たのでメモ

4
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
6