dillonkearns / elm-pages / BackendTask.Custom

In a vanilla Elm application, ports let you either send or receive JSON data between your Elm application and the JavaScript context in the user's browser at runtime.

With BackendTask.Custom, you send and receive JSON to JavaScript running in NodeJS. As with any BackendTask, Custom BackendTask's are either run at build-time (for pre-rendered routes) or at request-time (for server-rendered routes). See BackendTask for more about the lifecycle of BackendTask's.

This means that you can call shell scripts, run NPM packages that are installed, or anything else you could do with NodeJS to perform custom side-effects, get some data, or both.

A BackendTask.Custom will call an async JavaScript function with the given name from the definition in a file called custom-backend-task.js in your project's root directory. The function receives the input JSON value, and the Decoder is used to decode the return value of the async function.

run : String -> Json.Encode.Value -> Json.Decode.Decoder b -> BackendTask { fatal : FatalError, recoverable : Error } b

Performance

As with any JavaScript or NodeJS code, avoid doing blocking IO operations. For example, avoid using fs.readFileSync, because blocking IO can slow down your elm-pages builds and dev server. elm-pages performs all BackendTask's in parallel whenever possible. So if you do BackendTask.map2 Tuple.pair myHttpBackendTask myCustomBackendTask, it will resolve those two in parallel. NodeJS performs best when you take advantage of its ability to do non-blocking I/O (file reads, HTTP requests, etc.). If you use BackendTask.andThen, it will need to resolve them in sequence rather than in parallel, but it's still best to avoid blocking IO operations in your Custom BackendTask definitions.

Error Handling

There are a few different things that can go wrong when running a custom-backend-task. These possible errors are captured in the BackendTask.Custom.Error type.


type Error
    = Error
    | ErrorInCustomBackendTaskFile
    | MissingCustomBackendTaskFile
    | CustomBackendTaskNotDefined ({ name : String })
    | CustomBackendTaskException Json.Decode.Value
    | NonJsonException String
    | ExportIsNotFunction
    | DecodeError Json.Decode.Error

Decoding JS Date Objects

These decoders are for use with decoding JS values of type Date. If you have control over the format, it may be better to be more explicit with a Rata Die number value or an ISO-8601 formatted date string instead. But often JavaScript libraries and core APIs will give you JS Date objects, so this can be useful for working with those.

timeDecoder : Json.Decode.Decoder Time.Posix

dateDecoder : Json.Decode.Decoder Date

The same as timeDecoder, but it converts the decoded Time.Posix value into a Date with Date.fromPosix Time.utc.

JavaScript Date objects don't distinguish between values with only a date vs. values with both a date and a time. So be sure to use this decoder when you know the semantics represent a date with no associated time (or you're sure you don't care about the time).