lobanov / elm-taskport Goto Github PK
View Code? Open in Web Editor NEWElm package for JavaScript interop using Elm's Task abstraction
Home Page: https://package.elm-lang.org/packages/lobanov/elm-taskport/latest/
License: Apache License 2.0
Elm package for JavaScript interop using Elm's Task abstraction
Home Page: https://package.elm-lang.org/packages/lobanov/elm-taskport/latest/
License: Apache License 2.0
Add helpful diagnostic information to all variants of InteropError
:
FunctionNotFound
: add a list of registered functions to help understanding if there is a typo or a problem with registrationVersionMismatch
: report back what version is installedValue
to aidA nice to have would be an ability to generate code that could be executed in the browser's JavaScript console to simulate the failing TaskPort call and identify what might be causing the issue.
There is an elm-test suite embedded into the package, which drags in unnecessary dependencies and is of questinable value now with other tests around the Elm code. Consider removing it
Issue #3 introduces JSError
type which faithfully represents an Error
object that could be thrown by JavaScript code. It also has a bunch of helpers to work with it, such as jsErrorDecoder
(JSON decoder) and jsErrorToString
(pretty printer for diagnostic messages). Still, one has to explicitly pass the decoder into the call
function to get the benefits of this.
JSError
type has an escape hatch representing the error as a JSON Value
if it does not conform to JavaScript standard, which seems more than enough for any non-conventional error handling, such as JS function returning a promise rejecting with a string. It is, therefore, very unlikely that anyone would be implementing a custom error decoder for the interop calls.
The developer experience would be simplified if TaskPort module API uses JSError
as the only way to report call errors, and stops requiring an errorDecoder
to be provided.
Currently all JS functions registered with TaskPort for interop calls form a flat namespace, which is sufficient for most applications. However, if Elm packages start using TaskPort, the risk of name clashes will increase. Currently, an attempt to register a function with the same name will throw an error "<> is already used". Application developers can always chose a different name if their function names clash with each other, or with names taken by a package, but if two separate packages attempt to register an interop function with the same name, it would be impossible for application developer to fix without changing the package code.
As of version 1.0.3 TaskPort incorrectly reports the fact that the function is not registered. The error is of type InteropError NotInstalled
, but should be InteropError FunctionNotFound
. Need to write a test for this and fix the interop code.
To aid future code readability, I'd like to request the use of records when specifying the function name and JSON decoder/encoder arguments for call
and callNoArgs
(since I believe they would always be specified together).
Below are examples of how calls with the current & proposed API would look:
-- current API: I don't find this clear enough at a glance when reading the code
testProcedureConfusing : Int -> Task.Task (Error String) Int
testProcedureConfusing =
TaskPort.call "testProcedure" JD.int JD.string JE.int
-- proposed API: define my test procedure
testProcedure : Int -> Task.Task (Error String) Int
testProcedure =
TaskPort.call
{ functionName = "testProcedure"
, argsEncoder = JE.int
, bodyDecoder = JD.int
, errorDecoder = JD.string
}
-- an example task to call the test procedure with an argument
taskForTestProcedureSpecifying3 : Task.Task (Error String) Int
taskForTestProcedureSpecifying3 =
testProcedure 3
Here's one way call
could be defined to support this:
call :
{ functionName : String
, argsEncoder : args -> JE.Value
, bodyDecoder : JD.Decoder body
, errorDecoder : JD.Decoder error
}
-> args
-> Task.Task (Error error) body
call { functionName, bodyDecoder, errorDecoder, argsEncoder } args =
callWithJson functionName bodyDecoder errorDecoder <| argsEncoder args
I've been having some trouble getting elm/http
and taskports to play nicely when using elm as a worker in nodejs.
Say I've got this program:
module Main exposing (main)
import Http
type alias Model =
{}
type Msg
= GotResponse (Result Http.Error String)
init : ( Model, Cmd Msg )
init =
( {}
, Http.get
{ url = "https://httpbin.org/get"
, expect = Http.expectString GotResponse
}
)
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotResponse res ->
let
_ =
Debug.log "RESPONSE" res
in
( model, Cmd.none )
main : Program {} Model Msg
main =
Platform.worker
{ init = always init
, update = update
, subscriptions = always Sub.none
}
With TaskPort
installed on the js side (as mentioned in the guide) - when the worker gets the response from the elm/http
request it prints:
RESPONSE: Ok <internals>
I'm not quite sure what's going on here, but I found a workaround that works for both using the xhr2 package instead of xmlhttprequest
import * as TaskPort from "elm-taskport";
import xhr from "xhr2";
global.XMLHttpRequest = xhr;
global.ProgressEvent = xhr.ProgressEvent;
export function init() {
TaskPort.install();
...register taskport functions
}
elm-taskport
is a great package btw! It makes elm on the server a lot more attractive, and the safety you've built in around the JS side is really nice ๐
I'd like to use this in Elm programs for some Javascript environments (Deno, Scriptable for iOS) where no XMLHttpRequest constructor exists. Currently, taskport.js appears to require an already-existing XMLHttpRequest in its environment. Can your documentation address this, and (if possible) point to an existing "mock" XMLHttpRequest that could be loaded into those environments prior to loading taskport.js?
At the moment client code must define it's own errorDecoder, even though I think in most cases it'll need to face something like new Error('message')
. This can be handled by a generic decoder in TaskPort module.
There is currently to mechanism allowing to distribute JavaScript code alongside Elm packages, so developers of packages requiring JS-side companion code to come up with practical mechanisms for that. For example, JavaScript code required for elm-taskport itself is bundled into a companion NPM module, which is distributed via the NPM repo.
By their nature, any separate distribution mechanism for JS code required for an Elm package to work poses a risk of ending up with incompatible versions of Elm and JS code in an application. TaskPort itself implements a safeguard that detects such situation and fails eagerly with a helpful error message, as opposed to leaving room for obscure failures. However, developers of Elm packages using taskports would be facing the same issue, at least until Elm package registry would allow to distribute JS code.
Developers of Elm packages are free to implement their own safeguards ensuring compatible versions of Elm and JS code, but all such mechanisms would be very similar. The experience of developing Elm packages using TaskPort would be improved if it provided out-of-the-box support for such a safeguard.
There is a class of errors that is caused by the interop mechanism itself expressed in the Error
type variant InteropError
. For example, there could be errors indicating JS and Elm code version mismatch. There wouldn't be much that Elm code could do to recover from such errors other than to gracefully handle it and perhaps show a somewhat helpful error message. To make it easier to do the latter, would be good to have a way to convert InteropError
variants into a text message.
After updating to elm-taskport 2.0.0 I get this error during initialization:
SyntaxError: Importing binding name 'default' cannot be resolved by star export entries.
The stack trace is:
[N] link
[N] linkAndEvaluateModule
[N] (anonymouse function)
[N] promiseReactionJob
I'm running the code inside a webview managed by tauri-studio
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.