elm/core

Unused port call breaks subscriptions

maxhille opened this issue · 1 comments

I was hunting down a weird issue in one of our apps and came up with what I think it an Elm bug. In the following minimal example (also at https://ellie-app.com/p3n2dB2JKtJa1), the ping count should be the same as the pong count.

Please notice the comments in init and also in the JS code.

I think this might be the same underlying issue as #1128 and thus a regression from the changes in elm/core-1.0.{3,4,5}

port module Main exposing (main)

import Browser
import Html exposing (Html, button, div, p, text)
import Html.Attributes exposing (id)
import Html.Events exposing (onClick)


port ping : () -> Cmd msg


port pong : (() -> msg) -> Sub msg


type alias Model =
    { subscribed : Bool
    , pings : Int
    , pongs : Int
    }


type Msg
    = SubscribeAndPing
    | Pong ()


main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , update = update
        , subscriptions = subscriptions
        }


init : () -> ( Model, Cmd Msg )
init _ =
    let
        -- remove unused assignment to fix the program
        _ =
            ping ()
    in
    ( { subscribed = False
      , pings = 0
      , pongs = 0
      }
    , Cmd.none
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        SubscribeAndPing ->
            ( { model | subscribed = True, pings = model.pings + 1 }
            , ping ()
            )

        Pong _ ->
            ( { model | pongs = model.pongs + 1 }, Cmd.none )


view : Model -> Html Msg
view model =
    div []
        [ button [ onClick SubscribeAndPing ] [ text "ping" ]
        , if model.subscribed then
            div []
                [ p [] [ text <| String.fromInt model.pings ++ " pings sent" ]
                , p [] [ text <| String.fromInt model.pongs ++ " pongs received" ]
                ]

          else
            p [] [ text "push button to subscribe to port and ping" ]
        ]


subscriptions : Model -> Sub Msg
subscriptions model =
    if model.subscribed then
        pong Pong

    else
        Sub.none
<html>
<head>
  <style>
    /* you can style your program here */
  </style>
</head>
<body>
  <main></main>
  <script>
    var app = Elm.Main.init({ node: document.querySelector('main') })


    app.ports.ping.subscribe(() => {
      // workaround seems to be wrapping the "send" in a requestAnimationFrame()
      // requestAnimationFrame(() => { app.ports.pong.send(null) })
       app.ports.pong.send(null)
    })
  </script>
</body>
</html>

Thanks for reporting this! To set expectations:

  • Issues are reviewed in batches, so it can take some time to get a response.
  • Ask questions a community forum. You will get an answer quicker that way!
  • If you experience something similar, open a new issue. We like duplicates.

Finally, please be patient with the core team. They are trying their best with limited resources.