elm-pages 3.0.0-beta.14 → 3.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/codegen/elm-pages-codegen.js +66 -118
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +20 -20
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +5 -5
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +21 -21
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/src/RouteBuilder.elm +23 -23
- package/generator/src/SharedTemplate.elm +2 -2
- package/generator/src/SiteConfig.elm +2 -2
- package/generator/src/cli.js +2 -2
- package/generator/src/compatibility-key.js +1 -1
- package/generator/src/error-formatter.js +7 -3
- package/generator/src/render.js +6 -15
- package/generator/src/request-cache.js +34 -4
- package/generator/static-code/hmr.js +16 -2
- package/package.json +1 -1
- package/src/ApiRoute.elm +13 -16
- package/src/BackendTask/Env.elm +11 -8
- package/src/BackendTask/File.elm +49 -10
- package/src/BackendTask/Glob.elm +6 -6
- package/src/BackendTask/Http.elm +49 -13
- package/src/BackendTask/Port.elm +59 -47
- package/src/BackendTask.elm +8 -22
- package/src/FatalError.elm +101 -0
- package/src/Form.elm +3 -2
- package/src/Internal/ApiRoute.elm +5 -5
- package/src/Pages/Generate.elm +300 -103
- package/src/Pages/Internal/FatalError.elm +5 -0
- package/src/Pages/Internal/Platform/Cli.elm +21 -41
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +1 -1
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +24 -48
- package/src/Pages/Internal/Platform/StaticResponses.elm +18 -31
- package/src/Pages/Internal/Script.elm +2 -2
- package/src/Pages/Manifest.elm +2 -2
- package/src/Pages/ProgramConfig.elm +7 -7
- package/src/Pages/Script.elm +4 -4
- package/src/Pages/SiteConfig.elm +2 -2
- package/src/Pages/StaticHttpRequest.elm +1 -23
- package/src/Server/Request.elm +3 -2
- package/src/Exception.elm +0 -37
- package/src/MultiDict.elm +0 -49
- package/src/PairingHeap.elm +0 -137
- package/src/Parser/Extra/String.elm +0 -33
- package/src/Parser/Extra.elm +0 -69
- package/src/ProgramTest/ComplexQuery.elm +0 -360
- package/src/ProgramTest/EffectSimulation.elm +0 -122
- package/src/ProgramTest/Failure.elm +0 -367
- package/src/ProgramTest/HtmlHighlighter.elm +0 -116
- package/src/ProgramTest/HtmlParserHacks.elm +0 -58
- package/src/ProgramTest/HtmlRenderer.elm +0 -73
- package/src/ProgramTest/Program.elm +0 -30
- package/src/ProgramTest/StringLines.elm +0 -26
- package/src/ProgramTest/TestHtmlHacks.elm +0 -132
- package/src/ProgramTest/TestHtmlParser.elm +0 -201
- package/src/ProgramTest.elm +0 -2339
- package/src/Query/Extra.elm +0 -55
- package/src/SimulatedEffect/Cmd.elm +0 -69
- package/src/SimulatedEffect/Http.elm +0 -330
- package/src/SimulatedEffect/Navigation.elm +0 -69
- package/src/SimulatedEffect/Ports.elm +0 -62
- package/src/SimulatedEffect/Process.elm +0 -24
- package/src/SimulatedEffect/Sub.elm +0 -48
- package/src/SimulatedEffect/Task.elm +0 -252
- package/src/SimulatedEffect/Time.elm +0 -25
- package/src/SimulatedEffect.elm +0 -42
- package/src/String/Extra.elm +0 -6
- package/src/Test/Http.elm +0 -145
- package/src/TestResult.elm +0 -35
- package/src/TestState.elm +0 -305
- package/src/Url/Extra.elm +0 -100
- package/src/Vendored/Diff.elm +0 -321
- package/src/Vendored/Failure.elm +0 -217
- package/src/Vendored/FormatMonochrome.elm +0 -44
- package/src/Vendored/Highlightable.elm +0 -53
package/src/ApiRoute.elm
CHANGED
|
@@ -173,7 +173,7 @@ You define your ApiRoute's in `app/Api.elm`. Here's a simple example:
|
|
|
173
173
|
-}
|
|
174
174
|
|
|
175
175
|
import BackendTask exposing (BackendTask)
|
|
176
|
-
import
|
|
176
|
+
import FatalError exposing (FatalError)
|
|
177
177
|
import Head
|
|
178
178
|
import Internal.ApiRoute exposing (ApiRoute(..), ApiRouteBuilder(..))
|
|
179
179
|
import Json.Decode as Decode
|
|
@@ -192,14 +192,14 @@ type alias ApiRoute response =
|
|
|
192
192
|
{-| Same as [`preRender`](#preRender), but for an ApiRoute that has no dynamic segments. This is just a bit simpler because
|
|
193
193
|
since there are no dynamic segments, you don't need to provide a BackendTask with the list of dynamic segments to pre-render because there is only a single possible route.
|
|
194
194
|
-}
|
|
195
|
-
single : ApiRouteBuilder (BackendTask
|
|
195
|
+
single : ApiRouteBuilder (BackendTask FatalError String) (List String) -> ApiRoute Response
|
|
196
196
|
single handler =
|
|
197
197
|
handler
|
|
198
198
|
|> preRender (\constructor -> BackendTask.succeed [ constructor ])
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
{-| -}
|
|
202
|
-
serverRender : ApiRouteBuilder (Server.Request.Parser (BackendTask
|
|
202
|
+
serverRender : ApiRouteBuilder (Server.Request.Parser (BackendTask FatalError (Server.Response.Response Never Never))) constructor -> ApiRoute Response
|
|
203
203
|
serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
204
204
|
ApiRoute
|
|
205
205
|
{ regex = Regex.fromString ("^" ++ pattern ++ "$") |> Maybe.withDefault Regex.never
|
|
@@ -218,14 +218,13 @@ serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
|
218
218
|
|> BackendTask.onError
|
|
219
219
|
(\stringError ->
|
|
220
220
|
-- TODO make error with title and better context/formatting
|
|
221
|
-
|
|
221
|
+
FatalError.fromString stringError |> BackendTask.fail
|
|
222
222
|
)
|
|
223
223
|
|> BackendTask.andThen
|
|
224
224
|
(\rendered ->
|
|
225
225
|
case rendered of
|
|
226
226
|
Just (Ok okRendered) ->
|
|
227
227
|
okRendered
|
|
228
|
-
|> BackendTask.onError never
|
|
229
228
|
|
|
230
229
|
Just (Err errors) ->
|
|
231
230
|
errors
|
|
@@ -233,13 +232,11 @@ serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
|
233
232
|
|> Server.Response.plainText
|
|
234
233
|
|> Server.Response.withStatusCode 400
|
|
235
234
|
|> BackendTask.succeed
|
|
236
|
-
|> BackendTask.onError never
|
|
237
235
|
|
|
238
236
|
Nothing ->
|
|
239
237
|
Server.Response.plainText "No matching request handler"
|
|
240
238
|
|> Server.Response.withStatusCode 400
|
|
241
239
|
|> BackendTask.succeed
|
|
242
|
-
|> BackendTask.onError never
|
|
243
240
|
)
|
|
244
241
|
)
|
|
245
242
|
|> Maybe.map (BackendTask.map (Server.Response.toJson >> Just))
|
|
@@ -263,10 +260,10 @@ serverRender ((ApiRouteBuilder patterns pattern _ _ _) as fullHandler) =
|
|
|
263
260
|
|
|
264
261
|
|
|
265
262
|
{-| -}
|
|
266
|
-
preRenderWithFallback : (constructor -> BackendTask
|
|
263
|
+
preRenderWithFallback : (constructor -> BackendTask FatalError (List (List String))) -> ApiRouteBuilder (BackendTask FatalError (Server.Response.Response Never Never)) constructor -> ApiRoute Response
|
|
267
264
|
preRenderWithFallback buildUrls ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
|
|
268
265
|
let
|
|
269
|
-
buildTimeRoutes__ : BackendTask
|
|
266
|
+
buildTimeRoutes__ : BackendTask FatalError (List String)
|
|
270
267
|
buildTimeRoutes__ =
|
|
271
268
|
buildUrls (constructor [])
|
|
272
269
|
|> BackendTask.map (List.map toString)
|
|
@@ -305,15 +302,15 @@ encodeStaticFileBody fileBody =
|
|
|
305
302
|
|
|
306
303
|
|
|
307
304
|
{-| -}
|
|
308
|
-
preRender : (constructor -> BackendTask
|
|
305
|
+
preRender : (constructor -> BackendTask FatalError (List (List String))) -> ApiRouteBuilder (BackendTask FatalError String) constructor -> ApiRoute Response
|
|
309
306
|
preRender buildUrls ((ApiRouteBuilder patterns pattern _ toString constructor) as fullHandler) =
|
|
310
307
|
let
|
|
311
|
-
buildTimeRoutes__ : BackendTask
|
|
308
|
+
buildTimeRoutes__ : BackendTask FatalError (List String)
|
|
312
309
|
buildTimeRoutes__ =
|
|
313
310
|
buildUrls (constructor [])
|
|
314
311
|
|> BackendTask.map (List.map toString)
|
|
315
312
|
|
|
316
|
-
preBuiltMatches : BackendTask
|
|
313
|
+
preBuiltMatches : BackendTask FatalError (List (List String))
|
|
317
314
|
preBuiltMatches =
|
|
318
315
|
buildUrls (constructor [])
|
|
319
316
|
in
|
|
@@ -326,7 +323,7 @@ preRender buildUrls ((ApiRouteBuilder patterns pattern _ toString constructor) a
|
|
|
326
323
|
matches =
|
|
327
324
|
Internal.ApiRoute.pathToMatches path fullHandler
|
|
328
325
|
|
|
329
|
-
routeFound : BackendTask
|
|
326
|
+
routeFound : BackendTask FatalError Bool
|
|
330
327
|
routeFound =
|
|
331
328
|
preBuiltMatches
|
|
332
329
|
|> BackendTask.map (List.member matches)
|
|
@@ -434,19 +431,19 @@ capture (ApiRouteBuilder patterns pattern previousHandler toString constructor)
|
|
|
434
431
|
|
|
435
432
|
{-| For internal use by generated code. Not so useful in user-land.
|
|
436
433
|
-}
|
|
437
|
-
getBuildTimeRoutes : ApiRoute response -> BackendTask
|
|
434
|
+
getBuildTimeRoutes : ApiRoute response -> BackendTask FatalError (List String)
|
|
438
435
|
getBuildTimeRoutes (ApiRoute handler) =
|
|
439
436
|
handler.buildTimeRoutes
|
|
440
437
|
|
|
441
438
|
|
|
442
439
|
{-| Include head tags on every page's HTML.
|
|
443
440
|
-}
|
|
444
|
-
withGlobalHeadTags : BackendTask
|
|
441
|
+
withGlobalHeadTags : BackendTask FatalError (List Head.Tag) -> ApiRoute response -> ApiRoute response
|
|
445
442
|
withGlobalHeadTags globalHeadTags (ApiRoute handler) =
|
|
446
443
|
ApiRoute { handler | globalHeadTags = Just globalHeadTags }
|
|
447
444
|
|
|
448
445
|
|
|
449
446
|
{-| -}
|
|
450
|
-
getGlobalHeadTagsBackendTask : ApiRoute response -> Maybe (BackendTask
|
|
447
|
+
getGlobalHeadTagsBackendTask : ApiRoute response -> Maybe (BackendTask FatalError (List Head.Tag))
|
|
451
448
|
getGlobalHeadTagsBackendTask (ApiRoute handler) =
|
|
452
449
|
handler.globalHeadTags
|
package/src/BackendTask/Env.elm
CHANGED
|
@@ -8,22 +8,23 @@ down into the final `Data` value, it won't end up in the client!
|
|
|
8
8
|
|
|
9
9
|
import BackendTask exposing (BackendTask)
|
|
10
10
|
import BackendTask.Env
|
|
11
|
+
import FatalError exposing (FatalError)
|
|
11
12
|
|
|
12
13
|
type alias EnvVariables =
|
|
13
14
|
{ sendGridKey : String
|
|
14
15
|
, siteUrl : String
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
sendEmail : Email -> BackendTask ()
|
|
18
|
+
sendEmail : Email -> BackendTask FatalError ()
|
|
18
19
|
sendEmail email =
|
|
19
20
|
BackendTask.map2 EnvVariables
|
|
20
|
-
(BackendTask.Env.expect "SEND_GRID_KEY")
|
|
21
|
+
(BackendTask.Env.expect "SEND_GRID_KEY" |> BackendTask.allowFatal)
|
|
21
22
|
(BackendTask.Env.get "BASE_URL"
|
|
22
23
|
|> BackendTask.map (Maybe.withDefault "http://localhost:1234")
|
|
23
24
|
)
|
|
24
25
|
|> BackendTask.andThen (sendEmailBackendTask email)
|
|
25
26
|
|
|
26
|
-
sendEmailBackendTask : Email -> EnvVariables -> BackendTask ()
|
|
27
|
+
sendEmailBackendTask : Email -> EnvVariables -> BackendTask FatalError ()
|
|
27
28
|
sendEmailBackendTask email envVariables =
|
|
28
29
|
Debug.todo "Not defined here"
|
|
29
30
|
|
|
@@ -39,7 +40,7 @@ down into the final `Data` value, it won't end up in the client!
|
|
|
39
40
|
import BackendTask exposing (BackendTask)
|
|
40
41
|
import BackendTask.Http
|
|
41
42
|
import BackendTask.Internal.Request
|
|
42
|
-
import
|
|
43
|
+
import FatalError exposing (FatalError)
|
|
43
44
|
import Json.Decode as Decode
|
|
44
45
|
import Json.Encode as Encode
|
|
45
46
|
import TerminalText
|
|
@@ -50,7 +51,8 @@ type Error
|
|
|
50
51
|
= MissingEnvVariable String
|
|
51
52
|
|
|
52
53
|
|
|
53
|
-
{-| Get an environment variable, or Nothing if there is no environment variable matching that name.
|
|
54
|
+
{-| Get an environment variable, or Nothing if there is no environment variable matching that name. This `BackendTask`
|
|
55
|
+
will never fail, but instead will return `Nothing` if the environment variable is missing.
|
|
54
56
|
-}
|
|
55
57
|
get : String -> BackendTask error (Maybe String)
|
|
56
58
|
get envVariableName =
|
|
@@ -63,9 +65,9 @@ get envVariableName =
|
|
|
63
65
|
}
|
|
64
66
|
|
|
65
67
|
|
|
66
|
-
{-| Get an environment variable, or a BackendTask
|
|
68
|
+
{-| Get an environment variable, or a BackendTask FatalError if there is no environment variable matching that name.
|
|
67
69
|
-}
|
|
68
|
-
expect : String -> BackendTask
|
|
70
|
+
expect : String -> BackendTask { fatal : FatalError, recoverable : Error } String
|
|
69
71
|
expect envVariableName =
|
|
70
72
|
envVariableName
|
|
71
73
|
|> get
|
|
@@ -73,7 +75,7 @@ expect envVariableName =
|
|
|
73
75
|
(\maybeValue ->
|
|
74
76
|
maybeValue
|
|
75
77
|
|> Result.fromMaybe
|
|
76
|
-
(
|
|
78
|
+
(FatalError.recoverable
|
|
77
79
|
{ title = "Missing Env Variable"
|
|
78
80
|
, body =
|
|
79
81
|
[ TerminalText.text "BackendTask.Env.expect was expecting a variable `"
|
|
@@ -82,6 +84,7 @@ expect envVariableName =
|
|
|
82
84
|
]
|
|
83
85
|
|> TerminalText.toString
|
|
84
86
|
}
|
|
87
|
+
(MissingEnvVariable envVariableName)
|
|
85
88
|
)
|
|
86
89
|
|> BackendTask.fromResult
|
|
87
90
|
)
|
package/src/BackendTask/File.elm
CHANGED
|
@@ -51,7 +51,7 @@ plain old JSON in Elm.
|
|
|
51
51
|
import BackendTask exposing (BackendTask)
|
|
52
52
|
import BackendTask.Http
|
|
53
53
|
import BackendTask.Internal.Request
|
|
54
|
-
import
|
|
54
|
+
import FatalError exposing (FatalError)
|
|
55
55
|
import Json.Decode as Decode exposing (Decoder)
|
|
56
56
|
import TerminalText
|
|
57
57
|
|
|
@@ -141,7 +141,15 @@ It's common to parse the body with a markdown parser or other format.
|
|
|
141
141
|
)
|
|
142
142
|
|
|
143
143
|
-}
|
|
144
|
-
bodyWithFrontmatter :
|
|
144
|
+
bodyWithFrontmatter :
|
|
145
|
+
(String -> Decoder frontmatter)
|
|
146
|
+
-> String
|
|
147
|
+
->
|
|
148
|
+
BackendTask
|
|
149
|
+
{ fatal : FatalError
|
|
150
|
+
, recoverable : FileReadError Decode.Error
|
|
151
|
+
}
|
|
152
|
+
frontmatter
|
|
145
153
|
bodyWithFrontmatter frontmatterDecoder filePath =
|
|
146
154
|
read filePath
|
|
147
155
|
(body
|
|
@@ -213,7 +221,15 @@ the [`BackendTask`](BackendTask) API along with [`BackendTask.Glob`](BackendTask
|
|
|
213
221
|
|> BackendTask.resolve
|
|
214
222
|
|
|
215
223
|
-}
|
|
216
|
-
onlyFrontmatter :
|
|
224
|
+
onlyFrontmatter :
|
|
225
|
+
Decoder frontmatter
|
|
226
|
+
-> String
|
|
227
|
+
->
|
|
228
|
+
BackendTask
|
|
229
|
+
{ fatal : FatalError
|
|
230
|
+
, recoverable : FileReadError Decode.Error
|
|
231
|
+
}
|
|
232
|
+
frontmatter
|
|
217
233
|
onlyFrontmatter frontmatterDecoder filePath =
|
|
218
234
|
read filePath
|
|
219
235
|
(frontmatter frontmatterDecoder)
|
|
@@ -240,7 +256,14 @@ Hey there! This is my first post :)
|
|
|
240
256
|
Then data will yield the value `"Hey there! This is my first post :)"`.
|
|
241
257
|
|
|
242
258
|
-}
|
|
243
|
-
bodyWithoutFrontmatter :
|
|
259
|
+
bodyWithoutFrontmatter :
|
|
260
|
+
String
|
|
261
|
+
->
|
|
262
|
+
BackendTask
|
|
263
|
+
{ fatal : FatalError
|
|
264
|
+
, recoverable : FileReadError decoderError
|
|
265
|
+
}
|
|
266
|
+
String
|
|
244
267
|
bodyWithoutFrontmatter filePath =
|
|
245
268
|
read filePath
|
|
246
269
|
body
|
|
@@ -264,7 +287,7 @@ You could read a file called `hello.txt` in your root project directory like thi
|
|
|
264
287
|
File.rawFile "hello.txt"
|
|
265
288
|
|
|
266
289
|
-}
|
|
267
|
-
rawFile : String -> BackendTask
|
|
290
|
+
rawFile : String -> BackendTask { fatal : FatalError, recoverable : FileReadError decoderError } String
|
|
268
291
|
rawFile filePath =
|
|
269
292
|
read filePath (Decode.field "rawFile" Decode.string)
|
|
270
293
|
|
|
@@ -286,7 +309,15 @@ The Decode will strip off any unused JSON data.
|
|
|
286
309
|
"elm.json"
|
|
287
310
|
|
|
288
311
|
-}
|
|
289
|
-
jsonFile :
|
|
312
|
+
jsonFile :
|
|
313
|
+
Decoder a
|
|
314
|
+
-> String
|
|
315
|
+
->
|
|
316
|
+
BackendTask
|
|
317
|
+
{ fatal : FatalError
|
|
318
|
+
, recoverable : FileReadError Decode.Error
|
|
319
|
+
}
|
|
320
|
+
a
|
|
290
321
|
jsonFile jsonFileDecoder filePath =
|
|
291
322
|
rawFile filePath
|
|
292
323
|
|> BackendTask.andThen
|
|
@@ -295,13 +326,14 @@ jsonFile jsonFileDecoder filePath =
|
|
|
295
326
|
|> Decode.decodeString jsonFileDecoder
|
|
296
327
|
|> Result.mapError
|
|
297
328
|
(\jsonDecodeError ->
|
|
298
|
-
|
|
329
|
+
FatalError.recoverable
|
|
299
330
|
{ title = "JSON Decoding Error"
|
|
300
331
|
, body =
|
|
301
332
|
[ TerminalText.text (Decode.errorToString jsonDecodeError)
|
|
302
333
|
]
|
|
303
334
|
|> TerminalText.toString
|
|
304
335
|
}
|
|
336
|
+
(DecodingError jsonDecodeError)
|
|
305
337
|
)
|
|
306
338
|
|> BackendTask.fromResult
|
|
307
339
|
)
|
|
@@ -314,7 +346,7 @@ body =
|
|
|
314
346
|
Decode.field "withoutFrontmatter" Decode.string
|
|
315
347
|
|
|
316
348
|
|
|
317
|
-
read : String -> Decoder a -> BackendTask
|
|
349
|
+
read : String -> Decoder a -> BackendTask { fatal : FatalError, recoverable : FileReadError error } a
|
|
318
350
|
read filePath decoder =
|
|
319
351
|
BackendTask.Internal.Request.request
|
|
320
352
|
{ name = "read-file"
|
|
@@ -330,10 +362,16 @@ read filePath decoder =
|
|
|
330
362
|
|> BackendTask.andThen BackendTask.fromResult
|
|
331
363
|
|
|
332
364
|
|
|
333
|
-
errorDecoder :
|
|
365
|
+
errorDecoder :
|
|
366
|
+
String
|
|
367
|
+
->
|
|
368
|
+
Decoder
|
|
369
|
+
{ fatal : FatalError.FatalError
|
|
370
|
+
, recoverable : FileReadError decoding
|
|
371
|
+
}
|
|
334
372
|
errorDecoder filePath =
|
|
335
373
|
Decode.succeed
|
|
336
|
-
(
|
|
374
|
+
(FatalError.recoverable
|
|
337
375
|
{ title = "File Doesn't Exist"
|
|
338
376
|
, body =
|
|
339
377
|
[ TerminalText.text "Couldn't find file at path `"
|
|
@@ -342,4 +380,5 @@ errorDecoder filePath =
|
|
|
342
380
|
]
|
|
343
381
|
|> TerminalText.toString
|
|
344
382
|
}
|
|
383
|
+
FileDoesntExist
|
|
345
384
|
)
|
package/src/BackendTask/Glob.elm
CHANGED
|
@@ -229,7 +229,7 @@ import BackendTask exposing (BackendTask)
|
|
|
229
229
|
import BackendTask.Http
|
|
230
230
|
import BackendTask.Internal.Glob exposing (Glob(..))
|
|
231
231
|
import BackendTask.Internal.Request
|
|
232
|
-
import
|
|
232
|
+
import FatalError exposing (FatalError, Recoverable)
|
|
233
233
|
import Json.Decode as Decode
|
|
234
234
|
import Json.Encode as Encode
|
|
235
235
|
import List.Extra
|
|
@@ -1054,7 +1054,7 @@ so it's ideal to make this kind of assertion rather than having fallback behavio
|
|
|
1054
1054
|
issues (like if we had instead ignored the case where there are two or more matching blog post files).
|
|
1055
1055
|
|
|
1056
1056
|
-}
|
|
1057
|
-
expectUniqueMatch : Glob a -> BackendTask (
|
|
1057
|
+
expectUniqueMatch : Glob a -> BackendTask (Recoverable String) a
|
|
1058
1058
|
expectUniqueMatch glob =
|
|
1059
1059
|
glob
|
|
1060
1060
|
|> toBackendTask
|
|
@@ -1066,14 +1066,14 @@ expectUniqueMatch glob =
|
|
|
1066
1066
|
|
|
1067
1067
|
[] ->
|
|
1068
1068
|
BackendTask.fail <|
|
|
1069
|
-
|
|
1070
|
-
|
|
1069
|
+
FatalError.recoverable
|
|
1070
|
+
{ title = "Non-Unique Glob", body = "No files matched the pattern: " ++ toPatternString glob }
|
|
1071
1071
|
("No files matched the pattern: " ++ toPatternString glob)
|
|
1072
1072
|
|
|
1073
1073
|
_ ->
|
|
1074
1074
|
BackendTask.fail <|
|
|
1075
|
-
|
|
1076
|
-
"
|
|
1075
|
+
FatalError.recoverable
|
|
1076
|
+
{ title = "Non-Unique Glob", body = "Expected a unique match, but more than one file matched." }
|
|
1077
1077
|
"More than one file matched."
|
|
1078
1078
|
)
|
|
1079
1079
|
|
package/src/BackendTask/Http.elm
CHANGED
|
@@ -71,7 +71,22 @@ and describe your use case!
|
|
|
71
71
|
|
|
72
72
|
## Caching Options
|
|
73
73
|
|
|
74
|
-
`elm-pages` performs GET requests using a local HTTP cache by default.
|
|
74
|
+
`elm-pages` performs GET requests using a local HTTP cache by default. These requests are not performed using Elm's `elm/http`,
|
|
75
|
+
but rather are performed in NodeJS. Under the hood it uses [the NPM package `make-fetch-happen`](https://github.com/npm/make-fetch-happen).
|
|
76
|
+
Only GET requests made with `get`, `getJson`, or `getWithOptions` use local caching. Requests made with [`BackendTask.Http.request`](#request)
|
|
77
|
+
are not cached, even if the method is set to `GET`.
|
|
78
|
+
|
|
79
|
+
In dev mode, assets are cached more aggressively by default, whereas for a production build assets use a default to revalidate each cached response's freshness before using it (the `ForceRevalidate` [`CacheStrategy`](#CacheStrategy)).
|
|
80
|
+
|
|
81
|
+
The default caching behavior for GET requests is to use a local cache in `.elm-pages/http-cache`. This uses the same caching behavior
|
|
82
|
+
that browsers use to avoid re-downloading content when it hasn't changed. Servers can set HTTP response headers to explicitly control
|
|
83
|
+
this caching behavior.
|
|
84
|
+
|
|
85
|
+
- [`cache-control` HTTP response headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control) let you set a length of time before considering an asset stale. This could mean that the server considers it acceptable for an asset to be somewhat outdated, or this could mean that the asset is guaranteed to be up-to-date until it is stale - those semantics are up to the server.
|
|
86
|
+
- `Last-Modified` and `ETag` HTTP response headers can be returned by the server allow [Conditional Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests). Conditional Requests let us send back the `Last-Modified` timestamp or `etag` hash for assets that are in our local cache to the server to check if the asset is fresh, and skip re-downloading it if it is unchanged (or download a fresh one otherwise).
|
|
87
|
+
|
|
88
|
+
It's important to note that depending on how the server sets these HTTP response headers, we may have outdated data - either because the server explicitly allows assets to become outdated with their cache-control headers, OR because cache-control headers are not set. When these headers aren't explicitly set, [clients are allowed to cache assets for 10% of the amount of time since it was last modified](https://httpwg.org/specs/rfc7234.html#heuristic.freshness).
|
|
89
|
+
For production builds, the default caching will ignore both the implicit and explicit information about an asset's freshness and _always_ revalidate it before using a locally cached response.
|
|
75
90
|
|
|
76
91
|
@docs getWithOptions
|
|
77
92
|
|
|
@@ -89,7 +104,7 @@ import Base64
|
|
|
89
104
|
import Bytes exposing (Bytes)
|
|
90
105
|
import Bytes.Decode
|
|
91
106
|
import Dict exposing (Dict)
|
|
92
|
-
import
|
|
107
|
+
import FatalError exposing (FatalError, Recoverable)
|
|
93
108
|
import Json.Decode
|
|
94
109
|
import Json.Encode as Encode
|
|
95
110
|
import Pages.Internal.StaticHttpBody as Body
|
|
@@ -138,15 +153,16 @@ type alias Body =
|
|
|
138
153
|
Body.Body
|
|
139
154
|
|
|
140
155
|
|
|
141
|
-
{-| A simplified helper around [`BackendTask.Http.
|
|
156
|
+
{-| A simplified helper around [`BackendTask.Http.get`](#get), which builds up a BackendTask.Http GET request with `expectJson`.
|
|
142
157
|
|
|
143
158
|
import BackendTask
|
|
144
159
|
import BackendTask.Http
|
|
160
|
+
import FatalError exposing (FatalError)
|
|
145
161
|
import Json.Decode as Decode exposing (Decoder)
|
|
146
162
|
|
|
147
|
-
getRequest : BackendTask Int
|
|
163
|
+
getRequest : BackendTask (FatalError Error) Int
|
|
148
164
|
getRequest =
|
|
149
|
-
BackendTask.Http.
|
|
165
|
+
BackendTask.Http.getJson
|
|
150
166
|
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
151
167
|
(Decode.field "stargazers_count" Decode.int)
|
|
152
168
|
|
|
@@ -154,7 +170,7 @@ type alias Body =
|
|
|
154
170
|
getJson :
|
|
155
171
|
String
|
|
156
172
|
-> Json.Decode.Decoder a
|
|
157
|
-
-> BackendTask (
|
|
173
|
+
-> BackendTask (Recoverable Error) a
|
|
158
174
|
getJson url decoder =
|
|
159
175
|
getWithOptions
|
|
160
176
|
{ url = url
|
|
@@ -167,11 +183,25 @@ getJson url decoder =
|
|
|
167
183
|
}
|
|
168
184
|
|
|
169
185
|
|
|
170
|
-
{-|
|
|
186
|
+
{-| A simplified helper around [`BackendTask.Http.getWithOptions`](#getWithOptions), which builds up a GET request with
|
|
187
|
+
the default retries, timeout, and HTTP caching options. If you need to configure those options or include HTTP request headers,
|
|
188
|
+
use the more flexible `getWithOptions`.
|
|
189
|
+
|
|
190
|
+
import BackendTask
|
|
191
|
+
import BackendTask.Http
|
|
192
|
+
import FatalError exposing (FatalError)
|
|
193
|
+
|
|
194
|
+
getRequest : BackendTask (FatalError Error) String
|
|
195
|
+
getRequest =
|
|
196
|
+
BackendTask.Http.get
|
|
197
|
+
"https://api.github.com/repos/dillonkearns/elm-pages"
|
|
198
|
+
BackendTask.Http.expectString
|
|
199
|
+
|
|
200
|
+
-}
|
|
171
201
|
get :
|
|
172
202
|
String
|
|
173
203
|
-> Expect a
|
|
174
|
-
-> BackendTask
|
|
204
|
+
-> BackendTask { fatal : FatalError, recoverable : Error } a
|
|
175
205
|
get url expect =
|
|
176
206
|
getWithOptions
|
|
177
207
|
{ url = url
|
|
@@ -185,6 +215,12 @@ get url expect =
|
|
|
185
215
|
|
|
186
216
|
|
|
187
217
|
{-| Perform a GET request, with some additional options for the HTTP request, including options for caching behavior.
|
|
218
|
+
|
|
219
|
+
- `retries` - Default is 0. Will try performing request again if set to a number greater than 0.
|
|
220
|
+
- `timeoutInMs` - Default is no timeout.
|
|
221
|
+
- `cacheStrategy` - The [caching options are passed to the NPM package `make-fetch-happen`](https://github.com/npm/make-fetch-happen#opts-cache)
|
|
222
|
+
- `cachePath` - override the default directory for the local HTTP cache. This can be helpful if you want more granular control to clear some HTTP caches more or less frequently than others. Or you may want to preserve the local cache for some requests in your build server, but not store the cache for other requests.
|
|
223
|
+
|
|
188
224
|
-}
|
|
189
225
|
getWithOptions :
|
|
190
226
|
{ url : String
|
|
@@ -195,7 +231,7 @@ getWithOptions :
|
|
|
195
231
|
, timeoutInMs : Maybe Int
|
|
196
232
|
, cachePath : Maybe String
|
|
197
233
|
}
|
|
198
|
-
-> BackendTask (
|
|
234
|
+
-> BackendTask (Recoverable Error) a
|
|
199
235
|
getWithOptions request__ =
|
|
200
236
|
let
|
|
201
237
|
request_ : HashRequest.Request
|
|
@@ -222,7 +258,7 @@ post :
|
|
|
222
258
|
String
|
|
223
259
|
-> Body
|
|
224
260
|
-> Expect a
|
|
225
|
-
-> BackendTask (
|
|
261
|
+
-> BackendTask (Recoverable Error) a
|
|
226
262
|
post url body expect =
|
|
227
263
|
request
|
|
228
264
|
{ url = url
|
|
@@ -361,7 +397,7 @@ request :
|
|
|
361
397
|
, timeoutInMs : Maybe Int
|
|
362
398
|
}
|
|
363
399
|
-> Expect a
|
|
364
|
-
-> BackendTask (
|
|
400
|
+
-> BackendTask (Recoverable Error) a
|
|
365
401
|
request request__ expect =
|
|
366
402
|
let
|
|
367
403
|
request_ : HashRequest.Request
|
|
@@ -439,7 +475,7 @@ with this as a low-level detail, or you can use functions like [BackendTask.Http
|
|
|
439
475
|
requestRaw :
|
|
440
476
|
HashRequest.Request
|
|
441
477
|
-> Expect a
|
|
442
|
-
-> BackendTask (
|
|
478
|
+
-> BackendTask (Recoverable Error) a
|
|
443
479
|
requestRaw request__ expect =
|
|
444
480
|
let
|
|
445
481
|
request_ : HashRequest.Request
|
|
@@ -537,7 +573,7 @@ requestRaw request__ expect =
|
|
|
537
573
|
|> BackendTask.fromResult
|
|
538
574
|
|> BackendTask.mapError
|
|
539
575
|
(\error ->
|
|
540
|
-
|
|
576
|
+
FatalError.recoverable (errorToString error) error
|
|
541
577
|
)
|
|
542
578
|
)
|
|
543
579
|
|