elm-pages 3.0.0-beta.3 → 3.0.0-beta.30

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.
Files changed (123) hide show
  1. package/README.md +10 -1
  2. package/codegen/{elm-pages-codegen.js → elm-pages-codegen.cjs} +2864 -2589
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  10. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1327 -122
  11. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15295 -13271
  12. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  13. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  14. package/generator/dead-code-review/elm.json +8 -6
  15. package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +59 -10
  16. package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +52 -36
  17. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  18. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
  19. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  20. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  21. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1327 -122
  22. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14621 -12637
  23. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  24. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  25. package/generator/review/elm.json +8 -8
  26. package/generator/src/RouteBuilder.elm +113 -107
  27. package/generator/src/SharedTemplate.elm +3 -2
  28. package/generator/src/SiteConfig.elm +3 -2
  29. package/generator/src/basepath-middleware.js +3 -3
  30. package/generator/src/build.js +123 -87
  31. package/generator/src/cli.js +256 -77
  32. package/generator/src/codegen.js +29 -27
  33. package/generator/src/compatibility-key.js +3 -0
  34. package/generator/src/compile-elm.js +25 -25
  35. package/generator/src/config.js +39 -0
  36. package/generator/src/copy-dir.js +2 -2
  37. package/generator/src/dev-server.js +150 -133
  38. package/generator/src/dir-helpers.js +9 -26
  39. package/generator/src/elm-codegen.js +5 -4
  40. package/generator/src/elm-file-constants.js +2 -3
  41. package/generator/src/error-formatter.js +12 -11
  42. package/generator/src/file-helpers.js +3 -4
  43. package/generator/src/generate-template-module-connector.js +23 -22
  44. package/generator/src/init.js +9 -8
  45. package/generator/src/pre-render-html.js +39 -28
  46. package/generator/src/render-test.js +109 -0
  47. package/generator/src/render-worker.js +25 -28
  48. package/generator/src/render.js +322 -142
  49. package/generator/src/request-cache.js +252 -163
  50. package/generator/src/rewrite-client-elm-json.js +5 -5
  51. package/generator/src/rewrite-elm-json.js +7 -7
  52. package/generator/src/route-codegen-helpers.js +16 -31
  53. package/generator/src/seo-renderer.js +12 -7
  54. package/generator/src/vite-utils.js +77 -0
  55. package/generator/static-code/hmr.js +79 -13
  56. package/generator/template/app/Api.elm +6 -5
  57. package/generator/template/app/Effect.elm +123 -0
  58. package/generator/template/app/ErrorPage.elm +37 -6
  59. package/generator/template/app/Route/Index.elm +17 -10
  60. package/generator/template/app/Shared.elm +24 -47
  61. package/generator/template/app/Site.elm +19 -6
  62. package/generator/template/app/View.elm +1 -8
  63. package/generator/template/elm-tooling.json +0 -3
  64. package/generator/template/elm.json +34 -25
  65. package/generator/template/package.json +10 -4
  66. package/package.json +23 -22
  67. package/src/ApiRoute.elm +199 -61
  68. package/src/BackendTask/Custom.elm +325 -0
  69. package/src/BackendTask/Env.elm +90 -0
  70. package/src/{DataSource → BackendTask}/File.elm +128 -43
  71. package/src/{DataSource → BackendTask}/Glob.elm +136 -125
  72. package/src/BackendTask/Http.elm +673 -0
  73. package/src/{DataSource → BackendTask}/Internal/Glob.elm +1 -1
  74. package/src/BackendTask/Internal/Request.elm +28 -0
  75. package/src/BackendTask/Random.elm +79 -0
  76. package/src/BackendTask/Time.elm +47 -0
  77. package/src/BackendTask.elm +537 -0
  78. package/src/FatalError.elm +89 -0
  79. package/src/Form/Field.elm +21 -9
  80. package/src/Form/FieldView.elm +94 -14
  81. package/src/Form.elm +275 -400
  82. package/src/Head.elm +237 -7
  83. package/src/HtmlPrinter.elm +7 -3
  84. package/src/Internal/ApiRoute.elm +7 -5
  85. package/src/PageServerResponse.elm +6 -1
  86. package/src/Pages/FormState.elm +6 -5
  87. package/src/Pages/GeneratorProgramConfig.elm +15 -0
  88. package/src/Pages/Internal/FatalError.elm +5 -0
  89. package/src/Pages/Internal/Form.elm +21 -1
  90. package/src/Pages/{Msg.elm → Internal/Msg.elm} +26 -16
  91. package/src/Pages/Internal/Platform/Cli.elm +507 -763
  92. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
  93. package/src/Pages/Internal/Platform/Effect.elm +1 -2
  94. package/src/Pages/Internal/Platform/GeneratorApplication.elm +373 -0
  95. package/src/Pages/Internal/Platform/StaticResponses.elm +73 -270
  96. package/src/Pages/Internal/Platform/ToJsPayload.elm +4 -7
  97. package/src/Pages/Internal/Platform.elm +215 -102
  98. package/src/Pages/Internal/Script.elm +17 -0
  99. package/src/Pages/Internal/StaticHttpBody.elm +35 -1
  100. package/src/Pages/Manifest.elm +29 -4
  101. package/src/Pages/PageUrl.elm +23 -9
  102. package/src/Pages/ProgramConfig.elm +14 -10
  103. package/src/Pages/Script.elm +109 -0
  104. package/src/Pages/SiteConfig.elm +3 -2
  105. package/src/Pages/StaticHttp/Request.elm +2 -2
  106. package/src/Pages/StaticHttpRequest.elm +23 -98
  107. package/src/PagesMsg.elm +92 -0
  108. package/src/Path.elm +16 -19
  109. package/src/QueryParams.elm +21 -172
  110. package/src/RequestsAndPending.elm +8 -19
  111. package/src/Result/Extra.elm +26 -0
  112. package/src/Scaffold/Form.elm +484 -0
  113. package/src/Scaffold/Route.elm +1376 -0
  114. package/src/Server/Request.elm +43 -37
  115. package/src/Server/Session.elm +34 -34
  116. package/src/Server/SetCookie.elm +1 -1
  117. package/src/Test/Html/Internal/ElmHtml/ToString.elm +8 -9
  118. package/src/DataSource/Env.elm +0 -38
  119. package/src/DataSource/Http.elm +0 -446
  120. package/src/DataSource/Internal/Request.elm +0 -20
  121. package/src/DataSource/Port.elm +0 -90
  122. package/src/DataSource.elm +0 -538
  123. package/src/Pages/Generate.elm +0 -800
@@ -1,19 +1,19 @@
1
- module Pages.Internal.Platform.Cli exposing (Flags, Model, Msg(..), Program, cliApplication, init, requestDecoder, update)
1
+ module Pages.Internal.Platform.Cli exposing (Flags, Model, Msg(..), Program, cliApplication, init, requestDecoder, update, currentCompatibilityKey)
2
2
 
3
3
  {-| Exposed for internal use only (used in generated code).
4
4
 
5
- @docs Flags, Model, Msg, Program, cliApplication, init, requestDecoder, update
5
+ @docs Flags, Model, Msg, Program, cliApplication, init, requestDecoder, update, currentCompatibilityKey
6
6
 
7
7
  -}
8
8
 
9
- import ApiRoute
9
+ import BackendTask exposing (BackendTask)
10
10
  import BuildError exposing (BuildError)
11
11
  import Bytes exposing (Bytes)
12
12
  import Bytes.Encode
13
13
  import Codec
14
- import DataSource exposing (DataSource)
15
14
  import Dict
16
- import Head
15
+ import FatalError exposing (FatalError)
16
+ import Head exposing (Tag)
17
17
  import Html exposing (Html)
18
18
  import HtmlPrinter
19
19
  import Internal.ApiRoute exposing (ApiRoute(..))
@@ -21,22 +21,19 @@ import Json.Decode as Decode
21
21
  import Json.Encode
22
22
  import PageServerResponse exposing (PageServerResponse)
23
23
  import Pages.Flags
24
- import Pages.Http
25
24
  import Pages.Internal.NotFoundReason as NotFoundReason exposing (NotFoundReason)
25
+ import Pages.Internal.Platform.CompatibilityKey
26
26
  import Pages.Internal.Platform.Effect as Effect exposing (Effect)
27
- import Pages.Internal.Platform.StaticResponses as StaticResponses exposing (StaticResponses)
27
+ import Pages.Internal.Platform.StaticResponses as StaticResponses
28
28
  import Pages.Internal.Platform.ToJsPayload as ToJsPayload
29
29
  import Pages.Internal.ResponseSketch as ResponseSketch
30
- import Pages.Internal.StaticHttpBody as StaticHttpBody
31
- import Pages.Msg
32
30
  import Pages.ProgramConfig exposing (ProgramConfig)
33
31
  import Pages.SiteConfig exposing (SiteConfig)
34
32
  import Pages.StaticHttp.Request
35
- import Pages.StaticHttpRequest as StaticHttpRequest
33
+ import PagesMsg exposing (PagesMsg)
36
34
  import Path exposing (Path)
37
35
  import RenderRequest exposing (RenderRequest)
38
36
  import RequestsAndPending exposing (RequestsAndPending)
39
- import Task
40
37
  import TerminalText as Terminal
41
38
  import Url exposing (Url)
42
39
 
@@ -46,12 +43,16 @@ type alias Flags =
46
43
  Decode.Value
47
44
 
48
45
 
46
+ {-| -}
47
+ currentCompatibilityKey : Int
48
+ currentCompatibilityKey =
49
+ Pages.Internal.Platform.CompatibilityKey.currentCompatibilityKey
50
+
51
+
49
52
  {-| -}
50
53
  type alias Model route =
51
- { staticResponses : StaticResponses
54
+ { staticResponses : BackendTask FatalError Effect
52
55
  , errors : List BuildError
53
- , allRawResponses : RequestsAndPending
54
- , unprocessedPages : List ( Path, route )
55
56
  , maybeRequestJson : RenderRequest route
56
57
  , isDevServer : Bool
57
58
  }
@@ -59,12 +60,7 @@ type alias Model route =
59
60
 
60
61
  {-| -}
61
62
  type Msg
62
- = GotDataBatch
63
- (List
64
- { request : Pages.StaticHttp.Request.Request
65
- , response : RequestsAndPending.Response
66
- }
67
- )
63
+ = GotDataBatch Decode.Value
68
64
  | GotBuildError BuildError
69
65
 
70
66
 
@@ -105,7 +101,7 @@ cliApplication config =
105
101
  |> Tuple.mapSecond (perform site renderRequest config)
106
102
  , update =
107
103
  \msg model ->
108
- update site config msg model
104
+ update msg model
109
105
  |> Tuple.mapSecond (perform site model.maybeRequestJson config)
110
106
  , subscriptions =
111
107
  \_ ->
@@ -152,35 +148,11 @@ cliApplication config =
152
148
  )
153
149
  |> mergeResult
154
150
  )
155
- , config.gotBatchSub
156
- |> Sub.map
157
- (\newBatch ->
158
- Decode.decodeValue batchDecoder newBatch
159
- |> Result.map GotDataBatch
160
- |> Result.mapError
161
- (\error ->
162
- ("From location 2: "
163
- ++ (error
164
- |> Decode.errorToString
165
- )
166
- )
167
- |> BuildError.internal
168
- |> GotBuildError
169
- )
170
- |> mergeResult
171
- )
151
+ , config.gotBatchSub |> Sub.map GotDataBatch
172
152
  ]
173
153
  }
174
154
 
175
155
 
176
- batchDecoder : Decode.Decoder (List { request : Pages.StaticHttp.Request.Request, response : RequestsAndPending.Response })
177
- batchDecoder =
178
- Decode.map2 (\request response -> { request = request, response = response })
179
- (Decode.field "request" requestDecoder)
180
- (Decode.field "response" RequestsAndPending.decoder)
181
- |> Decode.list
182
-
183
-
184
156
  mergeResult : Result a a -> a
185
157
  mergeResult r =
186
158
  case r of
@@ -237,61 +209,16 @@ perform site renderRequest config effect =
237
209
  Effect.Batch list ->
238
210
  flatten site renderRequest config list
239
211
 
240
- Effect.FetchHttp unmasked ->
241
- if unmasked.url == "$$elm-pages$$headers" then
242
- case
243
- renderRequest
244
- |> RenderRequest.maybeRequestPayload
245
- |> Maybe.map (\json -> RequestsAndPending.Response Nothing (RequestsAndPending.JsonBody json))
246
- |> Result.fromMaybe (Pages.Http.BadUrl "$$elm-pages$$headers is only available on server-side request (not on build).")
247
- of
248
- Ok okResponse ->
249
- Task.succeed
250
- [ { request = unmasked
251
- , response = okResponse
252
- }
253
- ]
254
- |> Task.perform GotDataBatch
255
-
256
- Err error ->
257
- { title = "Static HTTP Error"
258
- , message =
259
- [ Terminal.text "I got an error making an HTTP request to this URL: "
260
-
261
- -- TODO include HTTP method, headers, and body
262
- , Terminal.yellow unmasked.url
263
- , Terminal.text <| Json.Encode.encode 2 <| StaticHttpBody.encode unmasked.body
264
- , Terminal.text "\n\n"
265
- , case error of
266
- Pages.Http.BadStatus metadata body ->
267
- Terminal.text <|
268
- String.join "\n"
269
- [ "Bad status: " ++ String.fromInt metadata.statusCode
270
- , "Status message: " ++ metadata.statusText
271
- , "Body: " ++ body
272
- ]
273
-
274
- Pages.Http.BadUrl _ ->
275
- -- TODO include HTTP method, headers, and body
276
- Terminal.text <| "Invalid url: " ++ unmasked.url
277
-
278
- Pages.Http.Timeout ->
279
- Terminal.text "Timeout"
280
-
281
- Pages.Http.NetworkError ->
282
- Terminal.text "Network error"
283
- ]
284
- , fatal = True
285
- , path = "" -- TODO wire in current path here
286
- }
287
- |> Task.succeed
288
- |> Task.perform GotBuildError
289
-
290
- else
291
- ToJsPayload.DoHttp unmasked unmasked.useCache
292
- |> Codec.encoder (ToJsPayload.successCodecNew2 canonicalSiteUrl "")
293
- |> config.toJsPort
294
- |> Cmd.map never
212
+ Effect.FetchHttp requests ->
213
+ requests
214
+ |> List.map
215
+ (\request ->
216
+ ( Pages.StaticHttp.Request.hash request, request )
217
+ )
218
+ |> ToJsPayload.DoHttp
219
+ |> Codec.encoder (ToJsPayload.successCodecNew2 canonicalSiteUrl "")
220
+ |> config.toJsPort
221
+ |> Cmd.map never
295
222
 
296
223
  Effect.SendSinglePage info ->
297
224
  let
@@ -328,32 +255,25 @@ perform site renderRequest config effect =
328
255
  |> config.sendPageData
329
256
  |> Cmd.map never
330
257
 
331
- Effect.Continue ->
332
- Cmd.none
333
-
334
258
 
335
259
  flagsDecoder :
336
260
  Decode.Decoder
337
261
  { staticHttpCache : RequestsAndPending
338
262
  , isDevServer : Bool
263
+ , compatibilityKey : Int
339
264
  }
340
265
  flagsDecoder =
341
- Decode.map2
342
- (\staticHttpCache isDevServer ->
266
+ Decode.map3
267
+ (\staticHttpCache isDevServer compatibilityKey ->
343
268
  { staticHttpCache = staticHttpCache
344
269
  , isDevServer = isDevServer
270
+ , compatibilityKey = compatibilityKey
345
271
  }
346
272
  )
347
- --(Decode.field "staticHttpCache"
348
- -- (Decode.dict
349
- -- (Decode.string
350
- -- |> Decode.map Just
351
- -- )
352
- -- )
353
- --)
354
273
  -- TODO remove hardcoding and decode staticHttpCache here
355
- (Decode.succeed Dict.empty)
274
+ (Decode.succeed (Json.Encode.object []))
356
275
  (Decode.field "mode" Decode.string |> Decode.map (\mode -> mode == "dev-server"))
276
+ (Decode.field "compatibilityKey" Decode.int)
357
277
 
358
278
 
359
279
  {-| -}
@@ -365,14 +285,42 @@ init :
365
285
  -> ( Model route, Effect )
366
286
  init site renderRequest config flags =
367
287
  case Decode.decodeValue flagsDecoder flags of
368
- Ok { staticHttpCache, isDevServer } ->
369
- initLegacy site renderRequest { staticHttpCache = staticHttpCache, isDevServer = isDevServer } config
288
+ Ok { isDevServer, compatibilityKey } ->
289
+ if compatibilityKey == currentCompatibilityKey then
290
+ initLegacy site renderRequest { isDevServer = isDevServer } config
291
+
292
+ else
293
+ let
294
+ elmPackageAheadOfNpmPackage : Bool
295
+ elmPackageAheadOfNpmPackage =
296
+ currentCompatibilityKey > compatibilityKey
297
+
298
+ message : String
299
+ message =
300
+ "The NPM package and Elm package you have installed are incompatible. If you are updating versions, be sure to update both the elm-pages Elm and NPM package.\n\n"
301
+ ++ (if elmPackageAheadOfNpmPackage then
302
+ "The elm-pages Elm package is ahead of the elm-pages NPM package. Try updating the elm-pages NPM package?"
303
+
304
+ else
305
+ "The elm-pages NPM package is ahead of the elm-pages Elm package. Try updating the elm-pages Elm package?"
306
+ )
307
+ in
308
+ updateAndSendPortIfDone
309
+ { staticResponses = StaticResponses.empty Effect.NoEffect
310
+ , errors =
311
+ [ { title = "Incompatible NPM and Elm package versions"
312
+ , message = [ Terminal.text <| message ]
313
+ , fatal = True
314
+ , path = ""
315
+ }
316
+ ]
317
+ , maybeRequestJson = renderRequest
318
+ , isDevServer = False
319
+ }
370
320
 
371
321
  Err error ->
372
322
  updateAndSendPortIfDone
373
- site
374
- config
375
- { staticResponses = StaticResponses.empty
323
+ { staticResponses = StaticResponses.empty Effect.NoEffect
376
324
  , errors =
377
325
  [ { title = "Internal Error"
378
326
  , message = [ Terminal.text <| "Failed to parse flags: " ++ Decode.errorToString error ]
@@ -380,8 +328,6 @@ init site renderRequest config flags =
380
328
  , path = ""
381
329
  }
382
330
  ]
383
- , allRawResponses = Dict.empty
384
- , unprocessedPages = []
385
331
  , maybeRequestJson = renderRequest
386
332
  , isDevServer = False
387
333
  }
@@ -430,140 +376,405 @@ isActionDecoder =
430
376
  initLegacy :
431
377
  SiteConfig
432
378
  -> RenderRequest route
433
- -> { staticHttpCache : RequestsAndPending, isDevServer : Bool }
379
+ -> { isDevServer : Bool }
434
380
  -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
435
381
  -> ( Model route, Effect )
436
- initLegacy site renderRequest { staticHttpCache, isDevServer } config =
382
+ initLegacy site ((RenderRequest.SinglePage includeHtml singleRequest _) as renderRequest) { isDevServer } config =
437
383
  let
438
- staticResponses : StaticResponses
439
- staticResponses =
440
- case renderRequest of
441
- RenderRequest.SinglePage _ singleRequest _ ->
442
- let
443
- globalHeadTags : DataSource (List Head.Tag)
444
- globalHeadTags =
445
- (config.globalHeadTags |> Maybe.withDefault (\_ -> DataSource.succeed [])) HtmlPrinter.htmlToString
446
- in
447
- case singleRequest of
448
- RenderRequest.Page serverRequestPayload ->
449
- let
450
- isAction : Maybe ActionRequest
451
- isAction =
452
- renderRequest
453
- |> RenderRequest.maybeRequestPayload
454
- |> Maybe.andThen (Decode.decodeValue isActionDecoder >> Result.withDefault Nothing)
455
- in
456
- StaticResponses.renderSingleRoute
457
- (case isAction of
458
- Just _ ->
459
- config.action serverRequestPayload.frontmatter
460
- |> DataSource.andThen
461
- (\something ->
462
- case something of
463
- PageServerResponse.ErrorPage _ _ ->
464
- DataSource.succeed something
465
- |> DataSource.map (\_ -> ())
466
-
467
- PageServerResponse.RenderPage _ _ ->
468
- DataSource.map3 (\_ _ _ -> ())
469
- (config.data serverRequestPayload.frontmatter)
470
- config.sharedData
471
- globalHeadTags
472
-
473
- PageServerResponse.ServerResponse _ ->
474
- DataSource.succeed something
475
- |> DataSource.map (\_ -> ())
476
- )
384
+ globalHeadTags : BackendTask FatalError (List Tag)
385
+ globalHeadTags =
386
+ (config.globalHeadTags |> Maybe.withDefault (\_ -> BackendTask.succeed [])) HtmlPrinter.htmlToString
387
+
388
+ staticResponsesNew : BackendTask FatalError Effect
389
+ staticResponsesNew =
390
+ StaticResponses.renderApiRequest
391
+ (case singleRequest of
392
+ RenderRequest.Page serverRequestPayload ->
393
+ let
394
+ isAction : Maybe ActionRequest
395
+ isAction =
396
+ renderRequest
397
+ |> RenderRequest.maybeRequestPayload
398
+ |> Maybe.andThen (Decode.decodeValue isActionDecoder >> Result.withDefault Nothing)
399
+
400
+ currentUrl : Url
401
+ currentUrl =
402
+ { protocol = Url.Https
403
+ , host = site.canonicalUrl
404
+ , port_ = Nothing
405
+ , path = serverRequestPayload.path |> Path.toRelative
406
+ , query = Nothing
407
+ , fragment = Nothing
408
+ }
409
+ in
410
+ --case isAction of
411
+ -- Just actionRequest ->
412
+ (if isDevServer then
413
+ config.handleRoute serverRequestPayload.frontmatter
477
414
 
478
- Nothing ->
479
- DataSource.map3 (\_ _ _ -> ())
480
- (config.data serverRequestPayload.frontmatter)
481
- config.sharedData
482
- globalHeadTags
483
- )
484
- (if isDevServer then
485
- config.handleRoute serverRequestPayload.frontmatter
415
+ else
416
+ BackendTask.succeed Nothing
417
+ )
418
+ |> BackendTask.andThen
419
+ (\pageFound ->
420
+ case pageFound of
421
+ Nothing ->
422
+ --sendSinglePageProgress site model.allRawResponses config model payload
423
+ (case isAction of
424
+ Just _ ->
425
+ config.action (RenderRequest.maybeRequestPayload renderRequest |> Maybe.withDefault Json.Encode.null) serverRequestPayload.frontmatter |> BackendTask.map Just
426
+
427
+ Nothing ->
428
+ BackendTask.succeed Nothing
429
+ )
430
+ |> BackendTask.andThen
431
+ (\something ->
432
+ let
433
+ actionHeaders2 : Maybe { statusCode : Int, headers : List ( String, String ) }
434
+ actionHeaders2 =
435
+ case something of
436
+ Just (PageServerResponse.RenderPage responseThing _) ->
437
+ Just responseThing
438
+
439
+ Just (PageServerResponse.ServerResponse responseThing) ->
440
+ Just
441
+ { headers = responseThing.headers
442
+ , statusCode = responseThing.statusCode
443
+ }
486
444
 
487
- else
488
- DataSource.succeed Nothing
489
- )
445
+ _ ->
446
+ Nothing
490
447
 
491
- RenderRequest.Api ( path, ApiRoute apiRequest ) ->
492
- StaticResponses.renderApiRequest
493
- (DataSource.map2 (\_ _ -> ())
494
- (apiRequest.matchesToResponse path)
495
- globalHeadTags
496
- )
448
+ maybeRedirectResponse : Maybe Effect
449
+ maybeRedirectResponse =
450
+ actionHeaders2
451
+ |> Maybe.andThen
452
+ (\responseMetadata ->
453
+ toRedirectResponse config
454
+ serverRequestPayload
455
+ includeHtml
456
+ responseMetadata
457
+ responseMetadata
458
+ )
459
+ in
460
+ case maybeRedirectResponse of
461
+ Just redirectResponse ->
462
+ redirectResponse
463
+ |> BackendTask.succeed
497
464
 
498
- RenderRequest.NotFound _ ->
499
- StaticResponses.renderApiRequest
500
- (DataSource.map2 (\_ _ -> ())
501
- (DataSource.succeed [])
502
- globalHeadTags
503
- )
465
+ Nothing ->
466
+ BackendTask.map3
467
+ (\pageData sharedData tags ->
468
+ let
469
+ renderedResult : Effect
470
+ renderedResult =
471
+ case pageData of
472
+ PageServerResponse.RenderPage responseInfo pageData_ ->
473
+ let
474
+ currentPage : { path : Path, route : route }
475
+ currentPage =
476
+ { path = serverRequestPayload.path, route = urlToRoute config currentUrl }
477
+
478
+ maybeActionData : Maybe actionData
479
+ maybeActionData =
480
+ case something of
481
+ Just (PageServerResponse.RenderPage _ actionThing) ->
482
+ Just actionThing
483
+
484
+ _ ->
485
+ Nothing
486
+
487
+ pageModel : userModel
488
+ pageModel =
489
+ config.init
490
+ Pages.Flags.PreRenderFlags
491
+ sharedData
492
+ pageData_
493
+ maybeActionData
494
+ (Just
495
+ { path =
496
+ { path = currentPage.path
497
+ , query = Nothing
498
+ , fragment = Nothing
499
+ }
500
+ , metadata = currentPage.route
501
+ , pageUrl = Nothing
502
+ }
503
+ )
504
+ |> Tuple.first
505
+
506
+ viewValue : { title : String, body : List (Html (PagesMsg userMsg)) }
507
+ viewValue =
508
+ (config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData_ maybeActionData |> .view) pageModel
509
+
510
+ responseMetadata : { statusCode : Int, headers : List ( String, String ) }
511
+ responseMetadata =
512
+ actionHeaders2 |> Maybe.withDefault responseInfo
513
+ in
514
+ (case isAction of
515
+ Just actionRequestKind ->
516
+ let
517
+ actionDataResult : Maybe (PageServerResponse actionData errorPage)
518
+ actionDataResult =
519
+ something
520
+ in
521
+ case actionDataResult of
522
+ Just (PageServerResponse.RenderPage ignored2 actionData_) ->
523
+ case actionRequestKind of
524
+ ActionResponseRequest ->
525
+ ( ignored2.headers
526
+ , ResponseSketch.HotUpdate pageData_ sharedData (Just actionData_)
527
+ |> config.encodeResponse
528
+ |> Bytes.Encode.encode
529
+ )
530
+
531
+ ActionOnlyRequest ->
532
+ ---- TODO need to encode action data when only that is requested (not ResponseSketch?)
533
+ ( ignored2.headers
534
+ , actionData_
535
+ |> config.encodeAction
536
+ |> Bytes.Encode.encode
537
+ )
538
+
539
+ _ ->
540
+ ( responseMetadata.headers
541
+ , Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
542
+ )
543
+
544
+ Nothing ->
545
+ ( responseMetadata.headers
546
+ , ResponseSketch.HotUpdate pageData_ sharedData Nothing
547
+ |> config.encodeResponse
548
+ |> Bytes.Encode.encode
549
+ )
550
+ )
551
+ |> (\( actionHeaders, byteEncodedPageData ) ->
552
+ let
553
+ rendered : { view : userModel -> { title : String, body : List (Html (PagesMsg userMsg)) }, head : List Tag }
554
+ rendered =
555
+ config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData_ maybeActionData
556
+ in
557
+ PageServerResponse.toRedirect responseMetadata
558
+ |> Maybe.map
559
+ (\{ location } ->
560
+ location
561
+ |> ResponseSketch.Redirect
562
+ |> config.encodeResponse
563
+ |> Bytes.Encode.encode
564
+ )
565
+ -- TODO handle other cases besides redirects?
566
+ |> Maybe.withDefault byteEncodedPageData
567
+ |> (\encodedData ->
568
+ { route = currentPage.path |> Path.toRelative
569
+ , contentJson = Dict.empty
570
+ , html = viewValue.body |> bodyToString
571
+ , errors = []
572
+ , head = rendered.head ++ tags
573
+ , title = viewValue.title
574
+ , staticHttpCache = Dict.empty
575
+ , is404 = False
576
+ , statusCode =
577
+ case includeHtml of
578
+ RenderRequest.OnlyJson ->
579
+ 200
580
+
581
+ RenderRequest.HtmlAndJson ->
582
+ responseMetadata.statusCode
583
+ , headers =
584
+ -- TODO should `responseInfo.headers` be used? Is there a problem in the case where there is both an action and data response in one? Do we need to make sure it is performed as two separate HTTP requests to ensure that the cookies are set correctly in that case?
585
+ actionHeaders
586
+ }
587
+ |> ToJsPayload.PageProgress
588
+ |> Effect.SendSinglePageNew encodedData
589
+ )
590
+ )
591
+
592
+ PageServerResponse.ServerResponse serverResponse ->
593
+ --PageServerResponse.ServerResponse serverResponse
594
+ -- TODO handle error?
595
+ let
596
+ responseMetadata : PageServerResponse.Response
597
+ responseMetadata =
598
+ case something of
599
+ Just (PageServerResponse.ServerResponse responseThing) ->
600
+ responseThing
601
+
602
+ _ ->
603
+ serverResponse
604
+ in
605
+ toRedirectResponse config serverRequestPayload includeHtml serverResponse responseMetadata
606
+ |> Maybe.withDefault
607
+ ({ body = serverResponse |> PageServerResponse.toJson
608
+ , staticHttpCache = Dict.empty
609
+ , statusCode = serverResponse.statusCode
610
+ }
611
+ |> ToJsPayload.SendApiResponse
612
+ |> Effect.SendSinglePage
613
+ )
614
+
615
+ PageServerResponse.ErrorPage error record ->
616
+ let
617
+ currentPage : { path : Path, route : route }
618
+ currentPage =
619
+ { path = serverRequestPayload.path, route = urlToRoute config currentUrl }
620
+
621
+ pageModel : userModel
622
+ pageModel =
623
+ config.init
624
+ Pages.Flags.PreRenderFlags
625
+ sharedData
626
+ pageData2
627
+ Nothing
628
+ (Just
629
+ { path =
630
+ { path = currentPage.path
631
+ , query = Nothing
632
+ , fragment = Nothing
633
+ }
634
+ , metadata = currentPage.route
635
+ , pageUrl = Nothing
636
+ }
637
+ )
638
+ |> Tuple.first
639
+
640
+ pageData2 : pageData
641
+ pageData2 =
642
+ config.errorPageToData error
643
+
644
+ viewValue : { title : String, body : List (Html (PagesMsg userMsg)) }
645
+ viewValue =
646
+ (config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData2 Nothing |> .view) pageModel
647
+ in
648
+ (ResponseSketch.HotUpdate pageData2 sharedData Nothing
649
+ |> config.encodeResponse
650
+ |> Bytes.Encode.encode
651
+ )
652
+ |> (\encodedData ->
653
+ { route = currentPage.path |> Path.toRelative
654
+ , contentJson = Dict.empty
655
+ , html = viewValue.body |> bodyToString
656
+ , errors = []
657
+ , head = tags
658
+ , title = viewValue.title
659
+ , staticHttpCache = Dict.empty
660
+ , is404 = False
661
+ , statusCode =
662
+ case includeHtml of
663
+ RenderRequest.OnlyJson ->
664
+ 200
665
+
666
+ RenderRequest.HtmlAndJson ->
667
+ config.errorStatusCode error
668
+ , headers = record.headers
669
+ }
670
+ |> ToJsPayload.PageProgress
671
+ |> Effect.SendSinglePageNew encodedData
672
+ )
673
+ in
674
+ renderedResult
675
+ )
676
+ (config.data (RenderRequest.maybeRequestPayload renderRequest |> Maybe.withDefault Json.Encode.null) serverRequestPayload.frontmatter)
677
+ config.sharedData
678
+ globalHeadTags
679
+ )
504
680
 
505
- unprocessedPages : List ( Path, route )
506
- unprocessedPages =
507
- case renderRequest of
508
- RenderRequest.SinglePage _ serverRequestPayload _ ->
509
- case serverRequestPayload of
510
- RenderRequest.Page pageData ->
511
- [ ( pageData.path, pageData.frontmatter ) ]
681
+ Just notFoundReason ->
682
+ render404Page config
683
+ Nothing
684
+ -- TODO do I need sharedDataResult?
685
+ --(Result.toMaybe sharedDataResult)
686
+ isDevServer
687
+ serverRequestPayload.path
688
+ notFoundReason
689
+ |> BackendTask.succeed
690
+ )
512
691
 
513
- RenderRequest.Api _ ->
514
- []
692
+ RenderRequest.Api ( path, ApiRoute apiHandler ) ->
693
+ BackendTask.map2
694
+ (\response _ ->
695
+ case response of
696
+ Just okResponse ->
697
+ { body = okResponse
698
+ , staticHttpCache = Dict.empty -- TODO do I need to serialize the full cache here, or can I handle that from the JS side?
699
+ , statusCode = 200
700
+ }
701
+ |> ToJsPayload.SendApiResponse
702
+ |> Effect.SendSinglePage
515
703
 
516
- RenderRequest.NotFound _ ->
517
- []
704
+ Nothing ->
705
+ render404Page config
706
+ -- TODO do I need sharedDataResult here?
707
+ Nothing
708
+ isDevServer
709
+ (Path.fromString path)
710
+ NotFoundReason.NoMatchingRoute
711
+ --Err error ->
712
+ -- [ error ]
713
+ -- |> ToJsPayload.Errors
714
+ -- |> Effect.SendSinglePage
715
+ )
716
+ (apiHandler.matchesToResponse
717
+ (renderRequest
718
+ |> RenderRequest.maybeRequestPayload
719
+ |> Maybe.withDefault Json.Encode.null
720
+ )
721
+ path
722
+ )
723
+ globalHeadTags
724
+
725
+ RenderRequest.NotFound notFoundPath ->
726
+ (BackendTask.map2
727
+ (\_ _ ->
728
+ render404Page config
729
+ Nothing
730
+ --(Result.toMaybe sharedDataResult)
731
+ --model
732
+ isDevServer
733
+ notFoundPath
734
+ NotFoundReason.NoMatchingRoute
735
+ )
736
+ (BackendTask.succeed [])
737
+ globalHeadTags
738
+ -- TODO is there a way to resolve sharedData but get it as a Result if it fails?
739
+ --config.sharedData
740
+ )
741
+ )
518
742
 
519
743
  initialModel : Model route
520
744
  initialModel =
521
- { staticResponses = staticResponses
745
+ { staticResponses = staticResponsesNew
522
746
  , errors = []
523
- , allRawResponses = staticHttpCache
524
- , unprocessedPages = unprocessedPages
525
747
  , maybeRequestJson = renderRequest
526
748
  , isDevServer = isDevServer
527
749
  }
528
750
  in
529
- StaticResponses.nextStep initialModel Nothing
530
- |> nextStepToEffect site
531
- config
751
+ StaticResponses.nextStep (Json.Encode.object []) initialModel.staticResponses initialModel
752
+ |> nextStepToEffect
532
753
  initialModel
533
754
 
534
755
 
535
756
  updateAndSendPortIfDone :
536
- SiteConfig
537
- -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
538
- -> Model route
757
+ Model route
539
758
  -> ( Model route, Effect )
540
- updateAndSendPortIfDone site config model =
541
- StaticResponses.nextStep
759
+ updateAndSendPortIfDone model =
760
+ StaticResponses.nextStep (Json.Encode.object [])
761
+ model.staticResponses
542
762
  model
543
- Nothing
544
- |> nextStepToEffect site config model
763
+ |> nextStepToEffect model
545
764
 
546
765
 
547
766
  {-| -}
548
767
  update :
549
- SiteConfig
550
- -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
551
- -> Msg
768
+ Msg
552
769
  -> Model route
553
770
  -> ( Model route, Effect )
554
- update site config msg model =
771
+ update msg model =
555
772
  case msg of
556
773
  GotDataBatch batch ->
557
- let
558
- updatedModel : Model route
559
- updatedModel =
560
- model
561
- |> StaticResponses.batchUpdate batch
562
- in
563
- StaticResponses.nextStep
564
- updatedModel
565
- Nothing
566
- |> nextStepToEffect site config updatedModel
774
+ StaticResponses.nextStep batch
775
+ model.staticResponses
776
+ model
777
+ |> nextStepToEffect model
567
778
 
568
779
  GotBuildError buildError ->
569
780
  let
@@ -574,560 +785,45 @@ update site config msg model =
574
785
  buildError :: model.errors
575
786
  }
576
787
  in
577
- StaticResponses.nextStep
788
+ StaticResponses.nextStep (Json.Encode.object [])
789
+ updatedModel.staticResponses
578
790
  updatedModel
579
- Nothing
580
- |> nextStepToEffect site config updatedModel
791
+ |> nextStepToEffect updatedModel
581
792
 
582
793
 
583
794
  nextStepToEffect :
584
- SiteConfig
585
- -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
586
- -> Model route
587
- -> ( StaticResponses, StaticResponses.NextStep route )
795
+ Model route
796
+ -> StaticResponses.NextStep route Effect
588
797
  -> ( Model route, Effect )
589
- nextStepToEffect site config model ( updatedStaticResponsesModel, nextStep ) =
798
+ nextStepToEffect model nextStep =
590
799
  case nextStep of
591
- StaticResponses.Continue updatedAllRawResponses httpRequests maybeRoutes ->
592
- let
593
- updatedUnprocessedPages : List ( Path, route )
594
- updatedUnprocessedPages =
595
- case maybeRoutes of
596
- Just newRoutes ->
597
- newRoutes
598
- |> List.map
599
- (\route ->
600
- ( Path.join (config.routeToPath route)
601
- , route
602
- )
603
- )
604
-
605
- Nothing ->
606
- model.unprocessedPages
607
-
608
- updatedModel : Model route
609
- updatedModel =
610
- { model
611
- | allRawResponses = updatedAllRawResponses
612
- , staticResponses = updatedStaticResponsesModel
613
- , unprocessedPages = updatedUnprocessedPages
614
- }
615
- in
616
- if List.isEmpty httpRequests then
617
- nextStepToEffect site
618
- config
619
- updatedModel
620
- (StaticResponses.nextStep
621
- updatedModel
622
- Nothing
623
- )
624
-
625
- else
626
- ( updatedModel
627
- , (httpRequests
628
- |> List.map Effect.FetchHttp
629
- )
630
- |> Effect.Batch
631
- )
632
-
633
- StaticResponses.Finish toJsPayload ->
634
- case toJsPayload of
635
- StaticResponses.ApiResponse ->
636
- let
637
- apiResponse : Effect
638
- apiResponse =
639
- case model.maybeRequestJson of
640
- RenderRequest.SinglePage _ requestPayload _ ->
641
- let
642
- sharedDataResult : Result BuildError sharedData
643
- sharedDataResult =
644
- StaticHttpRequest.resolve
645
- config.sharedData
646
- model.allRawResponses
647
- |> Result.mapError (StaticHttpRequest.toBuildError "")
648
- in
649
- case requestPayload of
650
- RenderRequest.Api ( path, ApiRoute apiHandler ) ->
651
- let
652
- thing : DataSource (Maybe ApiRoute.Response)
653
- thing =
654
- apiHandler.matchesToResponse path
655
- in
656
- StaticHttpRequest.resolve
657
- thing
658
- model.allRawResponses
659
- |> Result.mapError (StaticHttpRequest.toBuildError "TODO - path from request")
660
- |> (\response ->
661
- case response of
662
- Ok (Just okResponse) ->
663
- { body = okResponse
664
- , staticHttpCache = Dict.empty -- TODO do I need to serialize the full cache here, or can I handle that from the JS side?
665
-
666
- -- model.allRawResponses |> Dict.Extra.filterMap (\_ v -> v)
667
- , statusCode = 200
668
- }
669
- |> ToJsPayload.SendApiResponse
670
- |> Effect.SendSinglePage
671
-
672
- Ok Nothing ->
673
- render404Page config (Result.toMaybe sharedDataResult) model (Path.fromString path) NotFoundReason.NoMatchingRoute
674
-
675
- Err error ->
676
- [ error ]
677
- |> ToJsPayload.Errors
678
- |> Effect.SendSinglePage
679
- )
680
-
681
- RenderRequest.Page payload ->
682
- let
683
- pageFoundResult : Result BuildError (Maybe NotFoundReason)
684
- pageFoundResult =
685
- StaticHttpRequest.resolve
686
- (if model.isDevServer then
687
- -- TODO OPTIMIZATION this is redundant
688
- config.handleRoute payload.frontmatter
689
-
690
- else
691
- DataSource.succeed Nothing
692
- )
693
- model.allRawResponses
694
- |> Result.mapError (StaticHttpRequest.toBuildError (payload.path |> Path.toAbsolute))
695
- in
696
- case pageFoundResult of
697
- Ok Nothing ->
698
- sendSinglePageProgress site model.allRawResponses config model payload
699
-
700
- Ok (Just notFoundReason) ->
701
- render404Page config
702
- --Nothing
703
- (Result.toMaybe sharedDataResult)
704
- model
705
- payload.path
706
- notFoundReason
707
-
708
- Err error ->
709
- [ error ] |> ToJsPayload.Errors |> Effect.SendSinglePage
710
-
711
- RenderRequest.NotFound path ->
712
- render404Page config
713
- --Nothing
714
- (Result.toMaybe sharedDataResult)
715
- model
716
- path
717
- NotFoundReason.NoMatchingRoute
718
- in
719
- ( model
720
- , apiResponse
721
- )
722
-
723
- StaticResponses.Errors errors ->
724
- ( model
725
- , errors |> ToJsPayload.Errors |> Effect.SendSinglePage
726
- )
727
-
728
-
729
- sendSinglePageProgress :
730
- SiteConfig
731
- -> RequestsAndPending
732
- -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
733
- -> Model route
734
- -> { path : Path, frontmatter : route }
735
- -> Effect
736
- sendSinglePageProgress site contentJson config model info =
737
- let
738
- ( page, route ) =
739
- ( info.path, info.frontmatter )
740
- in
741
- case model.maybeRequestJson of
742
- RenderRequest.SinglePage includeHtml _ _ ->
743
- let
744
- isAction : Maybe ActionRequest
745
- isAction =
746
- model.maybeRequestJson
747
- |> RenderRequest.maybeRequestPayload
748
- |> Maybe.andThen (Decode.decodeValue isActionDecoder >> Result.withDefault Nothing)
749
-
750
- pageFoundResult : Result BuildError (Maybe NotFoundReason)
751
- pageFoundResult =
752
- -- TODO OPTIMIZATION this is redundant
753
- StaticHttpRequest.resolve
754
- (if model.isDevServer then
755
- config.handleRoute route
756
-
757
- else
758
- DataSource.succeed Nothing
759
- )
760
- model.allRawResponses
761
- |> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
762
-
763
- renderedResult : Result BuildError (PageServerResponse { head : List Head.Tag, view : String, title : String } errorPage)
764
- renderedResult =
765
- case includeHtml of
766
- RenderRequest.OnlyJson ->
767
- pageDataResult
768
- |> Result.map
769
- (\okPageData ->
770
- case okPageData of
771
- PageServerResponse.RenderPage responseInfo _ ->
772
- PageServerResponse.RenderPage
773
- { statusCode = responseInfo.statusCode
774
- , headers = responseInfo.headers
775
- }
776
- { head = []
777
- , view = "This page was not rendered because it is a JSON-only request."
778
- , title = "This page was not rendered because it is a JSON-only request."
779
- }
780
-
781
- PageServerResponse.ServerResponse serverResponse ->
782
- PageServerResponse.ServerResponse serverResponse
783
-
784
- PageServerResponse.ErrorPage error record ->
785
- PageServerResponse.ErrorPage error record
786
- )
787
-
788
- RenderRequest.HtmlAndJson ->
789
- Result.map2 Tuple.pair pageDataResult sharedDataResult
790
- |> Result.map
791
- (\( pageData_, sharedData ) ->
792
- case pageData_ of
793
- PageServerResponse.RenderPage responseInfo pageData ->
794
- let
795
- currentPage : { path : Path, route : route }
796
- currentPage =
797
- { path = page, route = urlToRoute config currentUrl }
798
-
799
- maybeActionData : Maybe actionData
800
- maybeActionData =
801
- case isAction of
802
- Just _ ->
803
- case actionDataResult of
804
- Ok (PageServerResponse.RenderPage _ actionData) ->
805
- Just actionData
806
-
807
- _ ->
808
- Nothing
809
-
810
- Nothing ->
811
- Nothing
812
-
813
- pageModel : userModel
814
- pageModel =
815
- config.init
816
- Pages.Flags.PreRenderFlags
817
- sharedData
818
- pageData
819
- maybeActionData
820
- (Just
821
- { path =
822
- { path = currentPage.path
823
- , query = Nothing
824
- , fragment = Nothing
825
- }
826
- , metadata = currentPage.route
827
- , pageUrl = Nothing
828
- }
829
- )
830
- |> Tuple.first
831
-
832
- viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
833
- viewValue =
834
- (config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData maybeActionData |> .view) pageModel
835
- in
836
- PageServerResponse.RenderPage responseInfo
837
- { head = config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData maybeActionData |> .head
838
- , view = viewValue.body |> bodyToString
839
- , title = viewValue.title
840
- }
841
-
842
- PageServerResponse.ServerResponse serverResponse ->
843
- PageServerResponse.ServerResponse serverResponse
844
-
845
- PageServerResponse.ErrorPage error record ->
846
- let
847
- currentPage : { path : Path, route : route }
848
- currentPage =
849
- { path = page, route = urlToRoute config currentUrl }
850
-
851
- pageModel : userModel
852
- pageModel =
853
- config.init
854
- Pages.Flags.PreRenderFlags
855
- sharedData
856
- pageData
857
- Nothing
858
- (Just
859
- { path =
860
- { path = currentPage.path
861
- , query = Nothing
862
- , fragment = Nothing
863
- }
864
- , metadata = currentPage.route
865
- , pageUrl = Nothing
866
- }
867
- )
868
- |> Tuple.first
869
-
870
- pageData : pageData
871
- pageData =
872
- config.errorPageToData error
873
-
874
- viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
875
- viewValue =
876
- (config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData Nothing |> .view) pageModel
877
- in
878
- PageServerResponse.RenderPage
879
- { statusCode = config.errorStatusCode error
880
- , headers = record.headers
881
- }
882
- { head = config.view Dict.empty Dict.empty Nothing currentPage Nothing sharedData pageData Nothing |> .head
883
- , view = viewValue.body |> List.map HtmlPrinter.htmlToString |> String.join "\n"
884
- , title = viewValue.title
885
- }
886
- )
887
-
888
- currentUrl : Url
889
- currentUrl =
890
- { protocol = Url.Https
891
- , host = site.canonicalUrl
892
- , port_ = Nothing
893
- , path = page |> Path.toRelative
894
- , query = Nothing
895
- , fragment = Nothing
896
- }
897
-
898
- pageDataResult : Result BuildError (PageServerResponse pageData errorPage)
899
- pageDataResult =
900
- -- TODO OPTIMIZATION can these three be included in StaticResponses.Finish?
901
- StaticHttpRequest.resolve
902
- (case isAction of
903
- Just _ ->
904
- config.action (urlToRoute config currentUrl)
905
- |> DataSource.andThen
906
- (\something ->
907
- case something of
908
- PageServerResponse.ErrorPage a b ->
909
- PageServerResponse.ErrorPage a b
910
- |> DataSource.succeed
911
-
912
- PageServerResponse.RenderPage _ _ ->
913
- -- TODO the headers/response codes are ignored from the action here
914
- -- is that okay? Should you always do a redirect or another kind of
915
- -- server response if you want to control the headers/response code for an action (like logout & redirect, for example)?
916
- config.data (urlToRoute config currentUrl)
917
-
918
- PageServerResponse.ServerResponse a ->
919
- PageServerResponse.ServerResponse a
920
- |> DataSource.succeed
921
- )
922
-
923
- Nothing ->
924
- config.data (urlToRoute config currentUrl)
925
- )
926
- contentJson
927
- |> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
928
-
929
- actionDataResult : Result BuildError (PageServerResponse actionData errorPage)
930
- actionDataResult =
931
- -- TODO OPTIMIZATION can these three be included in StaticResponses.Finish?
932
- StaticHttpRequest.resolve
933
- (config.action (urlToRoute config currentUrl))
934
- contentJson
935
- |> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
936
-
937
- sharedDataResult : Result BuildError sharedData
938
- sharedDataResult =
939
- StaticHttpRequest.resolve
940
- config.sharedData
941
- contentJson
942
- |> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
943
-
944
- globalHeadTags : DataSource (List Head.Tag)
945
- globalHeadTags =
946
- (config.globalHeadTags |> Maybe.withDefault (\_ -> DataSource.succeed [])) HtmlPrinter.htmlToString
947
-
948
- siteDataResult : Result BuildError (List Head.Tag)
949
- siteDataResult =
950
- StaticHttpRequest.resolve
951
- globalHeadTags
952
- model.allRawResponses
953
- |> Result.mapError (StaticHttpRequest.toBuildError "Site.elm")
954
- in
955
- case Result.map3 (\a b c -> ( a, b, c )) pageFoundResult renderedResult siteDataResult of
956
- Ok ( maybeNotFoundReason, renderedOrApiResponse, siteData ) ->
957
- case maybeNotFoundReason of
958
- Nothing ->
959
- let
960
- ( actionHeaders, byteEncodedPageData ) =
961
- case pageDataResult of
962
- Ok pageServerResponse ->
963
- case pageServerResponse of
964
- PageServerResponse.RenderPage ignored1 pageData ->
965
- -- TODO want to encode both shared and page data in dev server and HTML-embedded data
966
- -- but not for writing out the content.dat files - would be good to optimize this redundant data out
967
- --if model.isDevServer then
968
- case isAction of
969
- Just actionRequestKind ->
970
- case actionDataResult of
971
- Ok (PageServerResponse.RenderPage ignored2 actionData) ->
972
- case actionRequestKind of
973
- ActionResponseRequest ->
974
- ( ignored2.headers
975
- , sharedDataResult
976
- |> Result.map (\sharedData -> ResponseSketch.HotUpdate pageData sharedData (Just actionData))
977
- |> Result.withDefault (ResponseSketch.RenderPage pageData (Just actionData))
978
- |> config.encodeResponse
979
- |> Bytes.Encode.encode
980
- )
981
-
982
- ActionOnlyRequest ->
983
- ---- TODO need to encode action data when only that is requested (not ResponseSketch?)
984
- ( ignored2.headers
985
- , actionData
986
- |> config.encodeAction
987
- |> Bytes.Encode.encode
988
- )
989
-
990
- _ ->
991
- ( ignored1.headers
992
- , Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
993
- )
994
-
995
- Nothing ->
996
- ( ignored1.headers
997
- , sharedDataResult
998
- |> Result.map (\something -> ResponseSketch.HotUpdate pageData something Nothing)
999
- |> Result.withDefault (ResponseSketch.RenderPage pageData Nothing)
1000
- |> config.encodeResponse
1001
- |> Bytes.Encode.encode
1002
- )
1003
-
1004
- --else
1005
- -- pageData
1006
- -- |> ResponseSketch.RenderPage
1007
- -- |> config.encodeResponse
1008
- -- |> Bytes.Encode.encode
1009
- PageServerResponse.ServerResponse serverResponse ->
1010
- -- TODO handle error?
1011
- ( serverResponse.headers
1012
- , PageServerResponse.toRedirect serverResponse
1013
- |> Maybe.map
1014
- (\{ location } ->
1015
- location
1016
- |> ResponseSketch.Redirect
1017
- |> config.encodeResponse
1018
- )
1019
- -- TODO handle other cases besides redirects?
1020
- |> Maybe.withDefault (Bytes.Encode.unsignedInt8 0)
1021
- |> Bytes.Encode.encode
1022
- )
1023
-
1024
- PageServerResponse.ErrorPage error { headers } ->
1025
- -- TODO this case should never happen
1026
- ( headers
1027
- , sharedDataResult
1028
- |> Result.map
1029
- (\sharedData ->
1030
- ResponseSketch.HotUpdate (config.errorPageToData error)
1031
- sharedData
1032
- Nothing
1033
- )
1034
- |> Result.map config.encodeResponse
1035
- |> Result.map Bytes.Encode.encode
1036
- |> Result.withDefault (Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0))
1037
- )
800
+ StaticResponses.Continue httpRequests updatedStaticResponsesModel ->
801
+ ( { model
802
+ | staticResponses = updatedStaticResponsesModel
803
+ }
804
+ , Effect.FetchHttp httpRequests
805
+ )
1038
806
 
1039
- _ ->
1040
- -- TODO handle error?
1041
- ( []
1042
- , Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
1043
- )
1044
- in
1045
- case renderedOrApiResponse of
1046
- PageServerResponse.RenderPage responseInfo rendered ->
1047
- { route = page |> Path.toRelative
1048
- , contentJson = Dict.empty
1049
- , html = rendered.view
1050
- , errors = []
1051
- , head = rendered.head ++ siteData
1052
- , title = rendered.title
1053
- , staticHttpCache = Dict.empty
1054
- , is404 = False
1055
- , statusCode = responseInfo.statusCode
1056
- , headers =
1057
- -- TODO should `responseInfo.headers` be used? Is there a problem in the case where there is both an action and data response in one? Do we need to make sure it is performed as two separate HTTP requests to ensure that the cookies are set correctly in that case?
1058
- actionHeaders
1059
- }
1060
- |> ToJsPayload.PageProgress
1061
- |> Effect.SendSinglePageNew byteEncodedPageData
1062
-
1063
- PageServerResponse.ServerResponse serverResponse ->
1064
- PageServerResponse.toRedirect serverResponse
1065
- |> Maybe.map
1066
- (\_ ->
1067
- { route = page |> Path.toRelative
1068
- , contentJson = Dict.empty
1069
- , html = "This is intentionally blank HTML"
1070
- , errors = []
1071
- , head = []
1072
- , title = "This is an intentionally blank title"
1073
- , staticHttpCache = Dict.empty
1074
- , is404 = False
1075
- , statusCode =
1076
- case includeHtml of
1077
- RenderRequest.OnlyJson ->
1078
- -- if this is a redirect for a `content.dat`, we don't want to send an *actual* redirect status code because the redirect needs to be handled in Elm (not by the Browser)
1079
- 200
1080
-
1081
- RenderRequest.HtmlAndJson ->
1082
- serverResponse.statusCode
1083
- , headers = serverResponse.headers
1084
- }
1085
- |> ToJsPayload.PageProgress
1086
- |> Effect.SendSinglePageNew byteEncodedPageData
1087
- )
1088
- |> Maybe.withDefault
1089
- ({ body = serverResponse |> PageServerResponse.toJson
1090
- , staticHttpCache = Dict.empty
1091
- , statusCode = serverResponse.statusCode
1092
- }
1093
- |> ToJsPayload.SendApiResponse
1094
- |> Effect.SendSinglePage
1095
- )
807
+ StaticResponses.FinishedWithErrors errors ->
808
+ ( model
809
+ , errors |> ToJsPayload.Errors |> Effect.SendSinglePage
810
+ )
1096
811
 
1097
- PageServerResponse.ErrorPage error responseInfo ->
1098
- -- TODO this case should never happen
1099
- { route = page |> Path.toRelative
1100
- , contentJson = Dict.empty
1101
- , html = "UNEXPECTED!" --HtmlPrinter.htmlToString rendered.body
1102
- , errors = []
1103
- , head = [] -- rendered.head ++ siteData -- TODO this should call ErrorPage.head maybe?
1104
- , title = "UNEXPECTED CASE" --rendered.title
1105
- , staticHttpCache = Dict.empty
1106
- , is404 = False
1107
- , statusCode = config.errorStatusCode error
1108
- , headers = responseInfo.headers
1109
- }
1110
- |> ToJsPayload.PageProgress
1111
- |> Effect.SendSinglePageNew byteEncodedPageData
1112
-
1113
- Just notFoundReason ->
1114
- render404Page config (Result.toMaybe sharedDataResult) model page notFoundReason
1115
-
1116
- Err error ->
1117
- [ error ]
1118
- |> ToJsPayload.Errors
1119
- |> Effect.SendSinglePage
812
+ StaticResponses.Finish finalValue ->
813
+ ( model
814
+ , finalValue
815
+ )
1120
816
 
1121
817
 
1122
818
  render404Page :
1123
819
  ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
1124
820
  -> Maybe sharedData
1125
- -> Model route
821
+ -> Bool
1126
822
  -> Path
1127
823
  -> NotFoundReason
1128
824
  -> Effect
1129
- render404Page config sharedData model path notFoundReason =
1130
- case ( model.isDevServer, sharedData ) of
825
+ render404Page config sharedData isDevServer path notFoundReason =
826
+ case ( isDevServer, sharedData ) of
1131
827
  ( False, Just justSharedData ) ->
1132
828
  let
1133
829
  byteEncodedPageData : Bytes
@@ -1158,7 +854,7 @@ render404Page config sharedData model path notFoundReason =
1158
854
  pathAndRoute =
1159
855
  { path = path, route = config.notFoundRoute }
1160
856
 
1161
- viewValue : { title : String, body : List (Html (Pages.Msg.Msg userMsg)) }
857
+ viewValue : { title : String, body : List (Html (PagesMsg userMsg)) }
1162
858
  viewValue =
1163
859
  (config.view Dict.empty
1164
860
  Dict.empty
@@ -1221,7 +917,7 @@ render404Page config sharedData model path notFoundReason =
1221
917
 
1222
918
  bodyToString : List (Html msg) -> String
1223
919
  bodyToString body =
1224
- body |> List.map HtmlPrinter.htmlToString |> String.join "\n"
920
+ body |> List.map (HtmlPrinter.htmlToString Nothing) |> String.join "\n"
1225
921
 
1226
922
 
1227
923
  urlToRoute : ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage -> Url -> route
@@ -1231,3 +927,51 @@ urlToRoute config url =
1231
927
 
1232
928
  else
1233
929
  config.urlToRoute url
930
+
931
+
932
+ toRedirectResponse :
933
+ ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
934
+ -> { b | path : Path }
935
+ -> RenderRequest.IncludeHtml
936
+ -> { c | headers : List ( String, String ), statusCode : Int }
937
+ -> { response | statusCode : Int, headers : List ( String, String ) }
938
+ -> Maybe Effect
939
+ toRedirectResponse config serverRequestPayload includeHtml serverResponse responseMetadata =
940
+ PageServerResponse.toRedirect responseMetadata
941
+ |> Maybe.map
942
+ (\_ ->
943
+ let
944
+ ( _, byteEncodedPageData ) =
945
+ ( serverResponse.headers
946
+ , PageServerResponse.toRedirect serverResponse
947
+ |> Maybe.map
948
+ (\{ location } ->
949
+ location
950
+ |> ResponseSketch.Redirect
951
+ |> config.encodeResponse
952
+ )
953
+ |> Maybe.withDefault (Bytes.Encode.unsignedInt8 0)
954
+ |> Bytes.Encode.encode
955
+ )
956
+ in
957
+ { route = serverRequestPayload.path |> Path.toRelative
958
+ , contentJson = Dict.empty
959
+ , html = "This is intentionally blank HTML"
960
+ , errors = []
961
+ , head = []
962
+ , title = "This is an intentionally blank title"
963
+ , staticHttpCache = Dict.empty
964
+ , is404 = False
965
+ , statusCode =
966
+ case includeHtml of
967
+ RenderRequest.OnlyJson ->
968
+ -- if this is a redirect for a `content.dat`, we don't want to send an *actual* redirect status code because the redirect needs to be handled in Elm (not by the Browser)
969
+ 200
970
+
971
+ RenderRequest.HtmlAndJson ->
972
+ responseMetadata.statusCode
973
+ , headers = responseMetadata.headers --serverResponse.headers
974
+ }
975
+ |> ToJsPayload.PageProgress
976
+ |> Effect.SendSinglePageNew byteEncodedPageData
977
+ )