mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2024-12-26 21:31:32 +03:00
Update docs and rename a BackendTask.Port Error variant.
This commit is contained in:
parent
5ab296f91c
commit
be32cbd2be
@ -83,7 +83,7 @@ function lookupOrPerform(portsFile, mode, rawRequest, hasFsAccess, useCache) {
|
||||
resolve({
|
||||
kind: "response-json",
|
||||
value: jsonResponse({
|
||||
"elm-pages-internal-error": "PortCallError",
|
||||
"elm-pages-internal-error": "PortCallException",
|
||||
error: portCallError,
|
||||
}),
|
||||
});
|
||||
|
@ -3,30 +3,19 @@ module BackendTask.Port exposing
|
||||
, Error(..)
|
||||
)
|
||||
|
||||
{-|
|
||||
{-| 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.Port`, you send and receive JSON to JavaScript running in NodeJS. As with any `BackendTask`, Port BackendTask's are either run at build-time (for pre-rendered routes) or at request-time (for server-rendered routes). See [`BackendTask`](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.Port` will call an async JavaScript function with the given name from the definition in a file called `port-data-source.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.
|
||||
|
||||
@docs get
|
||||
|
||||
@docs Error
|
||||
|
||||
-}
|
||||
|
||||
import BackendTask
|
||||
import BackendTask.Http
|
||||
import BackendTask.Internal.Request
|
||||
import Exception exposing (Exception)
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Json.Encode as Encode
|
||||
import TerminalText
|
||||
|
||||
|
||||
{-| 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.Port`, you send and receive JSON to JavaScript running in NodeJS during build-time. This means that you can call shell scripts, or run NPM packages that are installed, or anything else you could do with NodeJS.
|
||||
|
||||
A `BackendTask.Port` will call an async JavaScript function with the given name. The function receives the input JSON value, and the Decoder is used to decode the return value of the async function.
|
||||
|
||||
Here is the Elm code and corresponding JavaScript definition for getting an environment variable (or a build error if it isn't found).
|
||||
Here is the Elm code and corresponding JavaScript definition for getting an environment variable (or an `Exception BackendTask.Port.Error` if it isn't found). In this example,
|
||||
we're using `BackendTask.throw` to let the framework treat that as an unexpected exception, but we could also handle the possible failures of the `Exception` (see [`Exception`](Exception)).
|
||||
|
||||
import BackendTask exposing (BackendTask)
|
||||
import BackendTask.Port
|
||||
@ -43,8 +32,7 @@ Here is the Elm code and corresponding JavaScript definition for getting an envi
|
||||
-- will resolve to "VIM" if you run `EDITOR=vim elm-pages dev`
|
||||
|
||||
```javascript
|
||||
const kleur = require("kleur");
|
||||
|
||||
// port-data-source.js
|
||||
|
||||
module.exports =
|
||||
/**
|
||||
@ -57,31 +45,46 @@ module.exports =
|
||||
if (result) {
|
||||
return result;
|
||||
} else {
|
||||
throw `No environment variable called ${kleur
|
||||
.yellow()
|
||||
.underline(name)}\n\nAvailable:\n\n${Object.keys(process.env).join(
|
||||
"\n"
|
||||
)}`;
|
||||
throw `No environment variable called ${name}
|
||||
|
||||
Available:
|
||||
|
||||
${Object.keys(process.env).join("\n")}
|
||||
`;
|
||||
}
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Error Handling
|
||||
|
||||
`port-data-source.js`
|
||||
|
||||
Any time you throw an exception from a BackendTask.Port definition, it will result in a build error in your `elm-pages build` or dev server. In the example above, if the environment variable
|
||||
is not found it will result in a build failure. Notice that the NPM package `kleur` is being used in this example to add color to the output for that build error. You can use any tool you
|
||||
prefer to add ANSI color codes within the error string in an exception and it will show up with color output in the build output and dev server.
|
||||
|
||||
|
||||
## 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.
|
||||
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` performances all `BackendTask`'s in parallel whenever possible.
|
||||
So if you do `BackendTask.map2 Tuple.pair myHttpBackendTask myPortBackendTask`, 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 BackendTask Port definitions.
|
||||
|
||||
|
||||
## Error Handling
|
||||
|
||||
There are a few different things that can go wrong when running a port-data-source. These possible errors are captured in the `BackendTask.Port.Error` type.
|
||||
|
||||
@docs Error
|
||||
|
||||
Any time you throw a JavaScript exception from a BackendTask.Port definition, it will give you a `PortCallException`. It's usually easier to add a `try`/`catch` in your JavaScript code in `port-data-source.js`
|
||||
to handle possible errors, but you can throw a JSON value and handle it in Elm in the `PortCallException` call error.
|
||||
|
||||
-}
|
||||
|
||||
import BackendTask
|
||||
import BackendTask.Http
|
||||
import BackendTask.Internal.Request
|
||||
import Exception exposing (Exception)
|
||||
import Json.Decode as Decode exposing (Decoder)
|
||||
import Json.Encode as Encode
|
||||
import TerminalText
|
||||
|
||||
|
||||
{-| -}
|
||||
get : String -> Encode.Value -> Decoder b -> BackendTask.BackendTask (Exception Error) b
|
||||
get portName input decoder =
|
||||
BackendTask.Internal.Request.request
|
||||
@ -155,19 +158,19 @@ get portName input decoder =
|
||||
}
|
||||
)
|
||||
|
||||
else if errorKind == "PortCallError" then
|
||||
else if errorKind == "PortCallException" then
|
||||
Decode.field "error" Decode.value
|
||||
|> Decode.maybe
|
||||
|> Decode.map (Maybe.withDefault Encode.null)
|
||||
|> Decode.map
|
||||
(\portCallError ->
|
||||
Exception.Exception
|
||||
(PortCallError portCallError)
|
||||
(PortCallException portCallError)
|
||||
{ title = "Port Error"
|
||||
, body =
|
||||
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I couldn't import the port definitions file, because of this exception:\n\n"
|
||||
[ TerminalText.text "Something went wrong in a call to BackendTask.Port.get. I was able to import the port definitions file, but when running it I encountered this exception:\n\n"
|
||||
, TerminalText.red (Encode.encode 2 portCallError)
|
||||
, TerminalText.text "\n\nAre there syntax errors or exceptions thrown during import?"
|
||||
, TerminalText.text "\n\nYou could add a `try`/`catch` in your `port-data-source` JavaScript code to handle that error."
|
||||
]
|
||||
|> TerminalText.toString
|
||||
}
|
||||
@ -199,5 +202,5 @@ type Error
|
||||
| ErrorInPortsFile
|
||||
| MissingPortsFile
|
||||
| PortNotDefined { name : String }
|
||||
| PortCallError Decode.Value
|
||||
| PortCallException Decode.Value
|
||||
| ExportIsNotFunction
|
||||
|
Loading…
Reference in New Issue
Block a user