Hi all
Before I come to the actual question, first the important background:
I’m working on a browser extension in Elm (WebExtension / Chrome Extension).
I want my extension to be running all the time in the background, so I created a Platform.program
and start it as a worker inside my background script. This works well so far.
Now, I want to have different views on the internal state of my worker, e.g. one for the popup of the extension, another simpler one to inject into the current tab.
I do have an idea how I could do this, but I don’t like it very much:
I could create a new elm Program
for each view that looks kinda like this:
port module Popup exposing (main)
import Html exposing (Html)
import Json.Encode exposing (Value)
import Background -- This is my background worker
import MainView -- A view of the background model
type alias Model =
Result String Background.Model
init : Value -> ( Model, Cmd Msg )
init model =
( Background.decodeModel model, Cmd.none )
type Msg
= NewState Value
| BackgroundMsg Background.Msg
update : Msg -> Model -> ( Model, Cmd msg )
update msg model =
case msg of
NewState bgModel ->
( Background.decodeModel bgModel, Cmd.none )
BackgroundMsg bgMsg ->
( model, sendMsgToBackground (Background.encodeMsg bgMsg) )
port sendMsgToBackground : Value -> Cmd msg
port newState : (Value -> msg) -> Sub msg
subs : Model -> Sub Msg
subs model =
[ Result.map Background.subs model
|> Result.withDefault Sub.none
|> Sub.map BackgroundMsg
, newState NewState
]
|> Sub.batch
view : Model -> Html Msg
view model =
Result.map MainView.view model
|> Result.withDefault (Html.text "")
|> Html.map BackgroundMsg
main : Program Value Model Msg
main =
Html.programWithFlags
{ init = init
, update = update
, view = view
, subscriptions = subs
}
Then, I could wire up those ports and let the background page communicate with those multiple frontends this way.
However I don’t like this solution.
Since my Model
and Msg
both contain union types, I would have to encode/decode the entire thing as a Json.Value
, as the automatic conversation elm does can’t deal with union types.
Plus, this is a lot of unnecessary encoding/decoding. I don’t know if that will impact performance.
Plus, an identical version of the state now lives at multiple locations in memory.
Additionally, that’s a lot of boilerplate…
My question now is the following:
Is there a better way?
Can I somehow share the state of one elm program with another?
I’m also prepared to write native/kernel code if that would help reduce the boilerplate.