スポンサーリンク

『基礎からわかるElm』を写経してみる(5)ナビゲーション

2019年6月3日

以下の本を写経しています。以下の環境構築の後、elm-formatとVisualStudioCodeのElm拡張機能を用いて、『Alt + Shift + F』と『Ctrl + S』を使用しながらやっています。

今回は、p179の『ナビゲーション』を写経して、SPA(Single Page Application)として複数ページからなるサイトを作りたいと思います。

本家サイトのコード
https://github.com/jinjor/elm-book/tree/master/4_4_navigation

スポンサーリンク

開発環境

Windows 10 Pro
Chrome
VisualStudioCode 1.32.3
git version 2.20.1.windows.1
nvm 1.1.7
node 10.2.0
npm 6.4.1
elm 0.19.0-bugfix6
elm-format 0.8.1
VisualStudioCodeの拡張機能でelmをインストールして、settings.jsonに以下のようにelmを設定。
(『Alt + Shift + F』と『Ctrl + S』を使用。)

    "[elm]": {
        "editor.formatOnSave": true
    },

Elmの初期化方法として、Browser.applicationを用いる

Elmで複数ページからなるWEBアプリを作成したい場合は、Browser.applicationを用いるとのことです。

参考: https://qiita.com/jinjor/items/245959d2da710eda18fa
@jinjor
2018年12月03日に更新
Elm 0.19 の初期化方法 6 種類

新規Elmアプリの作成

C:/elm/ フォルダ内に、elm-navigation/ フォルダを作成し、
C:/elm/elm-navigation/ を、VisualStudioCodeで開き、Ctrl+@でターミナル画面を開き、以下を入力します。
(すべて、何か聞かれたらEnter を押します。)

elm init
elm install elm/http
elm install elm/json
elm install elm/url

src/Main.elmの新規作成

src/ フォルダにMain.elmを新規作成し、以下をコピペします。

module Main exposing (main)

import Browser
import Browser.Navigation as Nav
import Html exposing (..)
import Html.Attributes exposing (..)
import Url

-- MAIN

main : Program () Model Msg
main =
  Browser.application
    { init = init
    , view = view
    , update = update
    , subscriptions = subscriptions
    , onUrlChange = UrlChanged  
    , onUrlRequest = LinkClicked
    }

-- SUBSCRIPTIONS

subscriptions : Model -> Sub
subscriptions _ =
  Sub.none

MODEL

よくわかりませんが、アプリの持つ状態としては、URLでしょうか?とにかく、以下のようにMODELを定義するそうです。写経します。

-- MODEL

type alias MODEL =
  { key : Nav.Key
  , url : Url.Url
  }

init : () -> Url.Url -> Nav.Key -> ( Model, Cmd Msg)
init flags url key =
  ( Model key url, Cmd.none)

UPDATE

メッセージとしては、『リンクをクリックしたとき』しか個人的には思いつかなかったのですが、『URLが変更されたとき』も定義する必要があるそうです。写経します。

ちなみに、ここで、上の方の、alias type MODEL を alias type Model に修正しています。

-- UPDATE

type Msg
  = LinkClicked Browser.UrlRequest
  | UrlChanged Url.Url

update : Msg -> Model -> ( Model, Cmd Msg)
update msg model =
  case msg of
    -- (2)画面遷移のリクエストを受けたとき
    LinkClicked urlRequest ->
      case urlRequest of
        -- 内部リンクならブラウザのURLを更新する
        Browser.Internal url ->
          ( model, Nav.pushUrl model.key (Url.toString url))

        -- 外部リンクなら通常の画面遷移を行う
        Browser.External url ->
          ( model Nav.load href)
    -- (3)URLが変更されたとき
    UrlChanged url ->
      ( { model | url = url }
      -- 何もしていませんが、本当はここでサーバーからデータをもらうはず
      , Cmd.none
      )

VIEW

VIEWはいつも面倒です。今回は、まずはCSS無しでやってみます。


-- VIEW

view : Model -> Browser.Document Msg
view model =
    { title = "URL Interceptor"
    , body =
        [ text "The current URL is:"
        , b [] [ text (Url.toString model.url )]
        , ul []
            --(1)各リンクからのクリックイベントが発生する
            [ viewLink "/home"
            , viewLink "/profile"
            , viewLink "/reviews/the-century-of-the-self"
            , viewLink "/reviews/public-opinion"
            , viewLink "/reviews/shah-of-shahs"
            ]
        ]
    }

viewLink : String -> Html msg  
viewLink path =
    li [] [ a [href path] [text path ] ]

その後、VisualStudioCodeのPROBLEMSのところに表示されるエラーの付近のコードのタイプミスをいろいろ修正していき、エラーが出なくなったことを確認。

elm reactorで試す

SPAなので、elm makeだけではダメで、elm reactorでサーバを動かさないとうまくいかないとのことです。

ターミナル画面で以下を入力し、ブラウザで

http://localhost:8000

にアクセスします。

elm reactor

あれ、本と微妙に異なります。

この状態で、WEBブラウザの『更新』をクリックすると、Not Foundになります。

Ctrl+C → Enter でサーバを止めておきます。

Node.jsでサーバー処理を実装するためにserver.jsを新規作成

→結論から言うと、この、Node.jsを使った方法では、うまくページを表示することができませんでした。次のindex.htmlのところへ飛んでください。

SPAを実装するためには、常にindex.htmlを返すために、なんだか、サーバーも手を加えないといけないそうです。面倒ですね。写経します。

const http = require("http");
const fs = require("fs");
http
  .createServer((req, res) => {
    console.log(req.url);
    const html = fs.readFileSync("./index.html");
    res.writeHeader(200, { "Content-Type": "text/html" });
    res.write(html);
    res.end();
  })
  .listen(3000)

ターミナル画面に以下を入力して、Node.jsのサーバを起動します。

node server.js

http://localhost:3000 をブラウザで開いてみますが、ダメでした。

もとの 
https://github.com/jinjor/elm-book/tree/master/4_4_navigation  を見ても、index.htmlが見当たらない。。。

index.htmlの新規作成

とりあえず、index.htmlを作成し、main.js(src/Main.elmをmain.jsにコンパイルしようと思います)を読み込んでみようと思います。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>SPA</title>
    <script src="main.js"></script>
  </head>
  <body>
    <script>
      var app = Elm.Main.init();
    </script>
  </body>
</html>

ターミナル画面で以下を入力して、src/Main.elmをmain.jsにコンパイルします。

elm make src/Main.elm --output=main.js

localhost:3000 にアクセスしても、、、ダメでした、、、

ぜひ、
https://github.com/jinjor/elm-book/tree/master/4_4_navigation にindex.htmlをあげてほしいです。(.gitignoreのリストにindex.htmlが入っており、一般の人には見えません。)しかし、後の方を見てみると、https://github.com/jinjor/elm-book/blob/master/4_7_navigation-github/index.html があるので、これで代用できるのだと思われました。で、試してみたのですが、なぜかうまくいきませんでした。あきらめて、elm-liveを使いたいと思います。

elm-liveを使ってみる

開発環境でのサーバ構築のための、elm-liveなるものがあるらしいので、使ってみようと思います。elm-reactorと比べて、少しだけ使いやすいらしいです。

参考: https://qiita.com/miyamo_madoka/items/704dd4c4f6756265e3a5
@miyamo_madoka
2018年12月09日に投稿
elm-liveで簡単開発サーバー構築

コマンドプロンプトに以下を入力します

npm install -g elm-live
elm-live src/Main.elm --open -- --output=main.js

やっと動きました。本当はWebpackを使ってnpm run buildとかもごりごり設定したいのですが、またいつか。。。

Netlifyにデプロイするために、netlify.tomlを新規作成

Netlifyにデプロイしたいので、netlify.tomlを新規作成します。後は、以下の記事と同様に、GitHubへpushして、Netlifyで公開していきたいと思います。

netlify.toml

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

https://github.com にログインして、新規リポジトリを作成します。

今回は、elm-navigation という名前にしました。
コマンドプロンプトで以下を入力してソースコードをpushします。

git init
git add .
git commit -m "first commit"
git remote add origin https://github.com/adash333/elm-navigation.git
git push -u origin master

Production用のmain.jsの作成

以下を入力して、src/Main.elmから、本番用(production用)のmain.jsを作成(コンパイル)します。

elm make src/Main.elm --output main.js --optimize

git add .
git commit -m "production"
git push

Netlifyにデプロイ

https://www.netlify.com/ にログインして、 New site from Git から、上記GitHubのリポジトリを選択して、デプロイします。

Build commandやPublish directoryは空欄のままとしておきます。

うまくいったようです。

https://hungry-easley-7d0cf8.netlify.com/

ソースコードとDEMOサイト

ソースコード
https://github.com/adash333/elm-navigation

DEMOサイト
https://hungry-easley-7d0cf8.netlify.com/