Search code examples
elm

Elm browser application not displaying


I copied the HTML from here, and the Elm code from here. The only change I made to the Elm code was the addition of the first line - module Main exposing (..). My IDE was complaining. Yet when I open index.html in a browser, I get a blank screen and the title of the page is still "Main". What am I doing wrong?

Here is my project structure

new-project
  elm-stuff
  src
    Main.elm
  elm.json
  index.html
  main.js

Here is index.html:

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

Here is Main.elm:

module Main exposing (..)

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
    }



-- 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


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


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
  case msg of
    LinkClicked urlRequest ->
      case urlRequest of
        Browser.Internal url ->
          ( model, Nav.pushUrl model.key (Url.toString url) )

        Browser.External href ->
          ( model, Nav.load href )

    UrlChanged url ->
      ( { model | url = url }
      , Cmd.none
      )



-- SUBSCRIPTIONS


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



-- VIEW


view : Model -> Browser.Document Msg
view model =
  { title = "URL Interceptor"
  , body =
      [ text "The current URL is: "
      , b [] [ text (Url.toString model.url) ]
      , ul []
          [ 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 ] ]

EDIT per answer by @pdamoc. I am trying to use elm-live to compile and display the elm file. I am on Ubuntu 18.04.5 LTS, with npm version 6.14.9, node version v8.10.0.

I get this error using elm-live:

$ elm-live src/Main.elm --pushstate
events.js:239
    throw new TypeError('"listener" argument must be a function');
    ^

TypeError: "listener" argument must be a function
    at _addListener (events.js:239:11)
    at Server.addListener (events.js:297:10)
    at new Server (_http_server.js:269:10)
    at Object.createServer (http.js:34:10)
    at model (/usr/local/lib/node_modules/elm-live/lib/src/start.js:259:75)
    at /usr/local/lib/node_modules/elm-live/node_modules/crocks/core/compose.js:8:14
    at settle (/usr/local/lib/node_modules/elm-live/node_modules/crocks/Async/index.js:151:16)
    at /usr/local/lib/node_modules/elm-live/node_modules/crocks/Async/index.js:27:62
    at fork (/usr/local/lib/node_modules/elm-live/node_modules/crocks/Async/index.js:155:20)
    at /usr/local/lib/node_modules/elm-live/node_modules/crocks/Async/index.js:224:16

Solution

  • You need a webserver that would serve the index.html on every path that is requested. The easiest way is to install elm-live globally and then start it like elm-live src/Main.elm --pushstate

    Without serving index.html on every path (let's say you use live-server), if you navigate to an internal path and reload you will get a 404.