Elm ports automatic public export and internal visibility boundary
0 reputation · 17 Oct 2020, 18:07 UTC
0 reputation · 17 Oct 2020, 18:07 UTC
Elm ports provide typed channels for JavaScript interop. The compiler validates port types at compile time, but does not enforce a visibility boundary for which ports are exposed to JavaScript.
All ports defined in a module are automatically exported from the module and become accessible to JavaScript consumers. There is no built-in mechanism to mark a port as internal or to restrict its JavaScript accessibility. The design was chosen to keep the module system simple and avoid complex visibility rules.
The goal is to define implementation-only ports without making them part of the public JavaScript API surface, while still using the documented port feature. The current constraint is that developers must manually ensure sensitive ports are not called from public JavaScript contexts.
Is there a documented way to restrict port visibility in Elm? Does the compiler provide any configuration or module boundary to treat ports as private? What permission boundary is recommended for modules that mix public and internal ports?
33775 reputation · 17 Oct 2020, 20:39 UTC
No. In current Elm releases, there is no documented way to restrict port visibility. Every port declared in a port module is automatically exported and becomes accessible to JavaScript consumers through the application instance. The compiler offers no configuration, annotation, or module boundary to treat ports as private.
The exposing clause in an Elm module governs only Elm-to-Elm imports. It has no effect on JavaScript accessibility. A port omitted from a module's exposing list remains fully reachable from JavaScript via app.ports. Separating ports into different modules does not create a permission boundary; all ports in the compiled program remain exposed.
Because the compiler cannot enforce privacy, the boundary must be architectural:
app.ports. Treat this wrapper as the permission boundary.update functions, since JavaScript can invoke any declared port regardless of module structure.To confirm this behavior, create a small port module with two ports, compile with elm make, and inspect app.ports in the browser console. Both ports will be accessible. In a multi-module project, initialize the app and enumerate app.ports to verify that ports declared outside the main module are still exposed.
The design keeps the module system simple at the cost of JavaScript-side privacy. Plan your interop surface accordingly.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.