TypeError: app.ports is undefined
ports property for the
app object that
If you’ve found this article because you got stuck writing your first port in an Elm application, then I hope this suffices to get you unstuck. If so, I’m glad! If you’re interested in how I got here, then read on.
How Did I Get Here?
I typically like to write code incrementally, because that feels safer to me. I like to take small steps and check my work frequently, especially in unfamiliar environments. I don’t know Elm very well yet and I certainly don’t feel like I can write Elm fluently, so I take smaller steps when I build something in Elm. In particular, I’d never used ports before, so I chose to take even smaller steps to write my first port. Sadly, I fell into a well-meaning trap: I expected there to be code that the Elm compiler helpfully optimized out of existence.
The Steps That Led Me Here
When I looked for examples of playing sounds in Elm, I only found code that generates an HTML
Since I wanted to work incrementally, I chose this strategy:
- Add a port to the Elm code, but don’t send any messages to it yet.
How To (Correctly) Add Your First Port To An Elm Application
Mark your main module as a
- Add a port.
Use the new port by sending a message to it from at least one branch of your application’s
updatefunction. (This is the step that I missed the first time.)
A Contract Failure
An Example Would Be Handy Right Now
I started with an Elm application that runs a singleton countdown timer. It has two modules:
Main module exposes
elm make generates. If you have the energy to show me a way to achieve the same thing without Jekyll, then I’m happy to see it. Please submit a pull request!
Next, I added a port to the Elm code without writing any messages to it yet. This requires two steps:
Mark the module with
port moduleinstead of merely
portas a function that turns some message payload into a command value of type
For my first port, I chose one without payload, so the input type is
() (unit/void/nothing). The return type is
Cmd unusedType, and not
Cmd Msg. The Elm guide (as of the time of writing this article) describes this type as
Cmd msg with a lowercase
msg, which I misread the first time as
Cmd Msg. This led to a few minutes of confusion over an unexpected compile error.
Detected problems in 1 module. -- BAD PORT ------------------------------------------------------- src/Main.elm The `ping` port cannot send any messages to the `update` function. 14| port ping : () -> Cmd Msg ^^^^ It must produce a (Cmd msg) type. Notice the lower case `msg` type variable. The command will trigger some JS code, but it will not send anything particular back to Elm.
I don’t yet know why calling this type
Cmd msg expresses intent better than, say,
Cmd someArbitraryType, so I chose
Cmd unusedType to more-clearly express the role, if not yet the intent. Please add a comment if you can describe the intent of this type parameter.
If I subscribed to this new port in my HTML page now, then the Elm compiler would not have generated any ports-related code (the compiler considers it dead code), leading to the error message that originally prompted me to write this article. Instead, I need to add code to at least one branch of the
PING message in the console. By this time I had a port working end to end and could resume trying to add the features that I cared about: playing a “warning” sound each second once the timer reaches 10 seconds remaining, then an “expired” sound once the timer expires.
If you’ve become stuck trying to write your first port in an Elm application, then I hope this helped you fix the problem, understand how you got there, and helps you avoid the problem in the future.