Initial prototype of ActionData.

This commit is contained in:
Dillon Kearns 2022-05-03 11:30:52 -07:00
parent cc30fc028a
commit 5a664782cd
12 changed files with 604 additions and 119 deletions

View File

@ -0,0 +1,49 @@
module Fetcher.Route.Signup exposing (load, submit)
import Bytes.Decode
import Effect exposing (Effect)
import FormDecoder
import Http
import Route.Signup
load : Effect (Result Http.Error Route.Signup.Data)
load =
Http.request
{ expect = Http.expectBytes identity decodeData
, tracker = Nothing
, body = Http.emptyBody
, headers = []
, url = "/signup"
, method = "GET"
, timeout = Nothing
}
|> Effect.fromCmd
submit : { headers : List ( String, String ), formFields : List ( String, String ) } -> Effect (Result Http.Error Route.Signup.ActionData)
submit options =
let
{ contentType, body } =
FormDecoder.encodeFormData options.formFields
in
Http.request
{ expect = Http.expectBytes identity decodeActionData
, tracker = Nothing
, body = Http.stringBody contentType body
, headers = options.headers |> List.map (\( key, value ) -> Http.header key value)
, url = "/signup/content.dat"
, method = "POST"
, timeout = Nothing
}
|> Effect.fromCmd
decodeData : Bytes.Decode.Decoder Route.Signup.Data
decodeData =
Route.Signup.w3_decode_Data
decodeActionData : Bytes.Decode.Decoder Route.Signup.ActionData
decodeActionData =
Route.Signup.w3_decode_ActionData

View File

@ -0,0 +1,139 @@
module Route.Hello exposing (ActionData, Data, Model, Msg, route)
import DataSource exposing (DataSource)
import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import Fetcher.Route.Signup
import Head
import Head.Seo as Seo
import Html
import Http
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Path exposing (Path)
import Route.Signup
import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload)
import Server.Request as Request
import Server.Response as Response exposing (Response)
import Shared
import View exposing (View)
type alias Model =
{}
type Msg
= NoOp
| GotResponse (Result Http.Error Route.Signup.ActionData)
type alias RouteParams =
{}
route : StatefulRoute RouteParams Data ActionData Model Msg
route =
RouteBuilder.serverRender
{ head = head
, data = data
, action = \_ -> Request.succeed (DataSource.succeed (Response.render {}))
}
|> RouteBuilder.buildWithLocalState
{ view = view
, update = update
, subscriptions = subscriptions
, init = init
}
init :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> ( Model, Effect Msg )
init maybePageUrl sharedModel static =
( {}
, Fetcher.Route.Signup.submit
{ headers = []
, formFields =
[ ( "first", "Jane" )
, ( "email", "jane@example.com" )
]
}
|> Effect.map GotResponse
)
update :
PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> Msg
-> Model
-> ( Model, Effect Msg )
update pageUrl sharedModel static msg model =
case msg of
NoOp ->
( model
, Effect.none
)
GotResponse result ->
let
_ =
Debug.log "GotResponse" result
in
( model
, Effect.none
)
subscriptions : Maybe PageUrl -> RouteParams -> Path -> Shared.Model -> Model -> Sub Msg
subscriptions maybePageUrl routeParams path sharedModel model =
Sub.none
type alias Data =
{}
type alias ActionData =
{}
data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
data routeParams =
Request.succeed (DataSource.succeed (Response.render Data))
head :
StaticPayload Data ActionData RouteParams
-> List Head.Tag
head static =
Seo.summary
{ canonicalUrlOverride = Nothing
, siteName = "elm-pages"
, image =
{ url = Pages.Url.external "TODO"
, alt = "elm-pages logo"
, dimensions = Nothing
, mimeType = Nothing
}
, description = "TODO"
, locale = Nothing
, title = "TODO title" -- metadata.title -- TODO
}
|> Seo.website
view :
Maybe PageUrl
-> Shared.Model
-> Model
-> StaticPayload Data ActionData RouteParams
-> View Msg
view maybeUrl sharedModel model static =
{ title = "Hello!"
, body = [ Html.text "Hello" ]
}

View File

@ -1,4 +1,4 @@
module Route.Index exposing (Data, Model, Msg, route)
module Route.Index exposing (ActionData, Data, Model, Msg, route)
import DataSource exposing (DataSource)
import DataSource.Env as Env
@ -28,7 +28,7 @@ type alias RouteParams =
{}
route : StatelessRoute RouteParams Data
route : StatelessRoute RouteParams Data ActionData
route =
RouteBuilder.single
{ head = head
@ -41,6 +41,10 @@ type alias Data =
{ pokemon : List String, envValue : Maybe String }
type alias ActionData =
{}
data : DataSource Data
data =
DataSource.map2 Data
@ -54,7 +58,7 @@ data =
head :
StaticPayload Data RouteParams
StaticPayload Data RouteParams ActionData
-> List Head.Tag
head static =
Seo.summary
@ -76,7 +80,7 @@ head static =
view :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data RouteParams
-> StaticPayload Data RouteParams ActionData
-> View Msg
view maybeUrl sharedModel static =
{ title = "Pokedex"

View File

@ -0,0 +1,127 @@
module Route.Signup exposing (ActionData, Data, Model, Msg, route)
import DataSource exposing (DataSource)
import Effect exposing (Effect)
import ErrorPage exposing (ErrorPage)
import Head
import Head.Seo as Seo
import Pages.PageUrl exposing (PageUrl)
import Pages.Url
import Path exposing (Path)
import RouteBuilder exposing (StatefulRoute, StatelessRoute, StaticPayload)
import Server.Request as Request
import Server.Response as Response exposing (Response)
import Shared
import View exposing (View)
type alias Model =
{}
type Msg
= NoOp
type alias RouteParams =
{}
route : StatefulRoute RouteParams Data ActionData Model Msg
route =
RouteBuilder.serverRender
{ head = head
, data = data
, action = action
}
|> RouteBuilder.buildWithLocalState
{ view = view
, update = update
, subscriptions = subscriptions
, init = init
}
action : RouteParams -> Request.Parser (DataSource (Response ActionData ErrorPage))
action _ =
Request.expectFormPost
(\{ field } ->
Request.map2 Tuple.pair
(field "first")
(field "email")
|> Request.map
(\( first, email ) ->
Success
{ email = email
, first = first
}
|> Response.render
|> DataSource.succeed
)
)
init :
Maybe PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> ( Model, Effect Msg )
init maybePageUrl sharedModel static =
( {}, Effect.none )
update :
PageUrl
-> Shared.Model
-> StaticPayload Data ActionData RouteParams
-> Msg
-> Model
-> ( Model, Effect Msg )
update pageUrl sharedModel static msg model =
case msg of
NoOp ->
( model, Effect.none )
subscriptions : Maybe PageUrl -> RouteParams -> Path -> Shared.Model -> Model -> Sub Msg
subscriptions maybePageUrl routeParams path sharedModel model =
Sub.none
type alias Data =
{}
type ActionData
= Success { email : String, first : String }
| ValidationErrors
{ errors : List String
, fields : List ( String, String )
}
actionData : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
actionData routeParams =
Debug.todo ""
data : RouteParams -> Request.Parser (DataSource (Response Data ErrorPage))
data routeParams =
Request.succeed (DataSource.succeed (Response.render Data))
head :
StaticPayload Data ActionData RouteParams
-> List Head.Tag
head static =
[]
view :
Maybe PageUrl
-> Shared.Model
-> Model
-> StaticPayload Data ActionData RouteParams
-> View Msg
view maybeUrl sharedModel model static =
View.placeholder "Signup"

View File

@ -27,7 +27,7 @@ data _ =
|> DataSource.map Server.Response.render
head : (routeParams -> String) -> StaticPayload Data routeParams -> List Head.Tag
head : (routeParams -> String) -> StaticPayload Data {} routeParams -> List Head.Tag
head toCssValue static =
Seo.summary
{ canonicalUrlOverride = Nothing
@ -53,7 +53,7 @@ view :
(routeParams -> String)
-> Maybe PageUrl
-> Shared.Model
-> StaticPayload Data routeParams
-> StaticPayload Data {} routeParams
-> View msg
view toCssVal maybeUrl sharedModel static =
let

View File

@ -98,20 +98,21 @@ import View exposing (View)
{-| -}
type alias StatefulRoute routeParams data model msg =
type alias StatefulRoute routeParams data action model msg =
{ data : routeParams -> DataSource (Server.Response.Response data ErrorPage)
, action : routeParams -> DataSource (Server.Response.Response action ErrorPage)
, staticRoutes : DataSource (List routeParams)
, view :
Maybe PageUrl
-> Shared.Model
-> model
-> StaticPayload data routeParams
-> StaticPayload data action routeParams
-> View msg
, head :
StaticPayload data routeParams
StaticPayload data action routeParams
-> List Head.Tag
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data routeParams -> ( model, Effect msg )
, update : PageUrl -> StaticPayload data routeParams -> msg -> model -> Shared.Model -> ( model, Effect msg, Maybe Shared.Msg )
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data action routeParams -> ( model, Effect msg )
, update : PageUrl -> StaticPayload data action routeParams -> msg -> model -> Shared.Model -> ( model, Effect msg, Maybe Shared.Msg )
, subscriptions : Maybe PageUrl -> routeParams -> Path -> model -> Shared.Model -> Sub msg
, handleRoute : { moduleName : List String, routePattern : RoutePattern } -> (routeParams -> List ( String, String )) -> routeParams -> DataSource (Maybe NotFoundReason)
, kind : String
@ -119,26 +120,28 @@ type alias StatefulRoute routeParams data model msg =
{-| -}
type alias StatelessRoute routeParams data =
StatefulRoute routeParams data {} ()
type alias StatelessRoute routeParams data action =
StatefulRoute routeParams data action {} ()
{-| -}
type alias StaticPayload data routeParams =
type alias StaticPayload data action routeParams =
{ data : data
, sharedData : Shared.Data
, routeParams : routeParams
, path : Path
, action : Maybe action
}
{-| -}
type Builder routeParams data
type Builder routeParams data action
= WithData
{ data : routeParams -> DataSource (Server.Response.Response data ErrorPage)
, action : routeParams -> DataSource (Server.Response.Response action ErrorPage)
, staticRoutes : DataSource (List routeParams)
, head :
StaticPayload data routeParams
StaticPayload data action routeParams
-> List Head.Tag
, serverless : Bool
, handleRoute :
@ -155,17 +158,18 @@ buildNoState :
{ view :
Maybe PageUrl
-> Shared.Model
-> StaticPayload data routeParams
-> StaticPayload data action routeParams
-> View ()
}
-> Builder routeParams data
-> StatefulRoute routeParams data {} ()
-> Builder routeParams data action
-> StatefulRoute routeParams data action {} ()
buildNoState { view } builderState =
case builderState of
WithData record ->
{ view = \maybePageUrl sharedModel _ -> view maybePageUrl sharedModel
, head = record.head
, data = record.data
, action = record.action
, staticRoutes = record.staticRoutes
, init = \_ _ _ -> ( {}, Effect.none )
, update = \_ _ _ _ _ -> ( {}, Effect.none, Nothing )
@ -181,14 +185,14 @@ buildWithLocalState :
Maybe PageUrl
-> Shared.Model
-> model
-> StaticPayload data routeParams
-> StaticPayload data action routeParams
-> View msg
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data routeParams -> ( model, Effect msg )
, update : PageUrl -> Shared.Model -> StaticPayload data routeParams -> msg -> model -> ( model, Effect msg )
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data action routeParams -> ( model, Effect msg )
, update : PageUrl -> Shared.Model -> StaticPayload data action routeParams -> msg -> model -> ( model, Effect msg )
, subscriptions : Maybe PageUrl -> routeParams -> Path -> Shared.Model -> model -> Sub msg
}
-> Builder routeParams data
-> StatefulRoute routeParams data model msg
-> Builder routeParams data action
-> StatefulRoute routeParams data action model msg
buildWithLocalState config builderState =
case builderState of
WithData record ->
@ -197,6 +201,7 @@ buildWithLocalState config builderState =
config.view model sharedModel staticPayload
, head = record.head
, data = record.data
, action = record.action
, staticRoutes = record.staticRoutes
, init = config.init
, update =
@ -225,20 +230,21 @@ buildWithSharedState :
Maybe PageUrl
-> Shared.Model
-> model
-> StaticPayload data routeParams
-> StaticPayload data action routeParams
-> View msg
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data routeParams -> ( model, Effect msg )
, update : PageUrl -> Shared.Model -> StaticPayload data routeParams -> msg -> model -> ( model, Effect msg, Maybe Shared.Msg )
, init : Maybe PageUrl -> Shared.Model -> StaticPayload data action routeParams -> ( model, Effect msg )
, update : PageUrl -> Shared.Model -> StaticPayload data action routeParams -> msg -> model -> ( model, Effect msg, Maybe Shared.Msg )
, subscriptions : Maybe PageUrl -> routeParams -> Path -> Shared.Model -> model -> Sub msg
}
-> Builder routeParams data
-> StatefulRoute routeParams data model msg
-> Builder routeParams data action
-> StatefulRoute routeParams data action model msg
buildWithSharedState config builderState =
case builderState of
WithData record ->
{ view = config.view
, head = record.head
, data = record.data
, action = record.action
, staticRoutes = record.staticRoutes
, init = config.init
, update =
@ -259,12 +265,13 @@ buildWithSharedState config builderState =
{-| -}
single :
{ data : DataSource data
, head : StaticPayload data {} -> List Head.Tag
, head : StaticPayload data action {} -> List Head.Tag
}
-> Builder {} data
-> Builder {} data action
single { data, head } =
WithData
{ data = \_ -> data |> DataSource.map Server.Response.render
, action = \_ -> DataSource.fail "Internal Error - actions should never be called for statically generated pages."
, staticRoutes = DataSource.succeed [ {} ]
, head = head
, serverless = False
@ -277,12 +284,13 @@ single { data, head } =
preRender :
{ data : routeParams -> DataSource data
, pages : DataSource (List routeParams)
, head : StaticPayload data routeParams -> List Head.Tag
, head : StaticPayload data action routeParams -> List Head.Tag
}
-> Builder routeParams data
-> Builder routeParams data action
preRender { data, head, pages } =
WithData
{ data = data >> DataSource.map Server.Response.render
, action = \_ -> DataSource.fail "Internal Error - actions should never be called for statically generated pages."
, staticRoutes = pages
, head = head
, serverless = False
@ -314,12 +322,13 @@ preRender { data, head, pages } =
preRenderWithFallback :
{ data : routeParams -> DataSource (Server.Response.Response data ErrorPage)
, pages : DataSource (List routeParams)
, head : StaticPayload data routeParams -> List Head.Tag
, head : StaticPayload data action routeParams -> List Head.Tag
}
-> Builder routeParams data
-> Builder routeParams data action
preRenderWithFallback { data, head, pages } =
WithData
{ data = data
, action = \_ -> DataSource.fail "Internal Error - actions should never be called for statically generated pages."
, staticRoutes = pages
, head = head
, serverless = False
@ -333,10 +342,11 @@ preRenderWithFallback { data, head, pages } =
{-| -}
serverRender :
{ data : routeParams -> Server.Request.Parser (DataSource (Server.Response.Response data ErrorPage))
, head : StaticPayload data routeParams -> List Head.Tag
, action : routeParams -> Server.Request.Parser (DataSource (Server.Response.Response action ErrorPage))
, head : StaticPayload data action routeParams -> List Head.Tag
}
-> Builder routeParams data
serverRender { data, head } =
-> Builder routeParams data action
serverRender { data, action, head } =
WithData
{ data =
\routeParams ->
@ -355,6 +365,23 @@ serverRender { data, head } =
Err error ->
Server.Request.errorsToString error |> DataSource.fail
)
, action =
\routeParams ->
DataSource.Http.get
"$$elm-pages$$headers"
(routeParams
|> action
|> Server.Request.getDecoder
)
|> DataSource.andThen
(\rendered ->
case rendered of
Ok okRendered ->
okRendered
Err error ->
Server.Request.errorsToString error |> DataSource.fail
)
, staticRoutes = DataSource.succeed []
, head = head
, serverless = True

View File

@ -142,6 +142,17 @@ type PageData
.join(" | ")}
type ActionData
=
${templates
.map(
(name) =>
`ActionData${pathNormalizedName(name)} Route.${moduleName(
name
)}.ActionData\n`
)
.join(" | ")}
view :
{ path : Path
@ -201,6 +212,7 @@ view page maybePageUrl globalData pageData =
, routeParams = ${
emptyRouteParams(name) ? "{}" : "s"
}
, action = Nothing
, path = page.path
}
|> View.map Msg${pathNormalizedName(name)}
@ -215,6 +227,7 @@ view page maybePageUrl globalData pageData =
{ data = data
, sharedData = globalData
, routeParams = ${emptyRouteParams(name) ? "{}" : "s"}
, action = Nothing
, path = page.path
}
`
@ -278,6 +291,7 @@ init currentGlobalModel userFlags sharedData pageData navigationKey maybePagePat
sharedModel
{ data = thisPageData
, sharedData = sharedData
, action = Nothing
, routeParams = ${
emptyRouteParams(name) ? "{}" : "routeParams"
}
@ -414,6 +428,7 @@ update sharedData pageData navigationKey msg model =
pageUrl
{ data = thisPageData
, sharedData = sharedData
, action = Nothing
, routeParams = ${routeHelpers.referenceRouteParams(
name,
"routeParams"
@ -476,7 +491,7 @@ templateSubscriptions route path model =
main : ${
phase === "browser"
? "Pages.Internal.Platform.Program Model Msg PageData Shared.Data ErrorPage"
? "Pages.Internal.Platform.Program Model Msg PageData ActionData Shared.Data ErrorPage"
: "Pages.Internal.Platform.Cli.Program (Maybe Route)"
}
main =
@ -515,6 +530,7 @@ config =
phase === "browser" ? "Sub.none" : "gotBatchSub identity"
}
, data = dataForRoute
, action = action
, sharedData = Shared.template.data
, apiRoutes = ${
phase === "browser"
@ -533,6 +549,7 @@ config =
, hotReloadData = hotReloadData identity
, encodeResponse = encodeResponse
, decodeResponse = decodeResponse
, encodeAction = encodeActionData
, cmdToEffect = Effect.fromCmd
, perform = Effect.perform
, errorStatusCode = ErrorPage.statusCode
@ -553,14 +570,14 @@ globalHeadTags =
|> DataSource.map List.concat
encodeResponse : ResponseSketch PageData Shared.Data -> Bytes.Encode.Encoder
encodeResponse : ResponseSketch PageData ActionData Shared.Data -> Bytes.Encode.Encoder
encodeResponse =
Pages.Internal.ResponseSketch.w3_encode_ResponseSketch w3_encode_PageData Shared.w3_encode_Data
Pages.Internal.ResponseSketch.w3_encode_ResponseSketch w3_encode_PageData w3_encode_ActionData Shared.w3_encode_Data
decodeResponse : Bytes.Decode.Decoder (ResponseSketch PageData Shared.Data)
decodeResponse : Bytes.Decode.Decoder (ResponseSketch PageData ActionData Shared.Data)
decodeResponse =
Pages.Internal.ResponseSketch.w3_decode_ResponseSketch w3_decode_PageData Shared.w3_decode_Data
Pages.Internal.ResponseSketch.w3_decode_ResponseSketch w3_decode_PageData w3_decode_ActionData Shared.w3_decode_Data
port hotReloadData : (Bytes -> msg) -> Sub msg
@ -584,6 +601,18 @@ ${templates
)
.join("\n")}
encodeActionData : ActionData -> Bytes.Encode.Encoder
encodeActionData actionData =
case actionData of
${templates
.map(
(name) => ` ActionData${pathNormalizedName(name)} thisActionData ->
Route.${name.join(".")}.w3_encode_ActionData thisActionData
`
)
.join("\n")}
port sendPageData : Pages.Internal.Platform.ToJsPayload.NewThingForPort -> Cmd msg
@ -607,6 +636,9 @@ ${templates
)
.join("\n")}
dataForRoute : Maybe Route -> DataSource (Server.Response.Response PageData ErrorPage)
dataForRoute route =
case route of
@ -633,6 +665,34 @@ dataForRoute route =
)
.join("\n ")}
action : Maybe Route -> DataSource (Server.Response.Response ActionData ErrorPage)
action route =
case route of
Nothing ->
DataSource.succeed ( Server.Response.plainText "TODO" )
${templates
.map(
(name) =>
`Just ${
emptyRouteParams(name)
? `Route.${routeHelpers.routeVariant(name)}`
: `(Route.${routeHelpers.routeVariant(name)} routeParams)`
} ->\n Route.${name.join(
"."
)}.route.action ${routeHelpers.referenceRouteParams(
name,
"routeParams"
)}
|> DataSource.map (Server.Response.map ActionData${routeHelpers.routeVariant(
name
)})
`
)
.join("\n ")}
handleRoute : Maybe Route -> DataSource (Maybe Pages.Internal.NotFoundReason.NotFoundReason)
handleRoute maybeRoute =
case maybeRoute of

View File

@ -46,12 +46,12 @@ type Transition
{-| -}
type alias Program userModel userMsg pageData sharedData errorPage =
Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg pageData sharedData errorPage)
type alias Program userModel userMsg pageData actionData sharedData errorPage =
Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg pageData actionData sharedData errorPage)
mainView :
ProgramConfig userMsg userModel route pageData sharedData effect (Msg userMsg pageData sharedData errorPage) errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Model userModel pageData sharedData
-> { title : String, body : Html userMsg }
mainView config model =
@ -100,9 +100,9 @@ urlsToPagePath urls =
view :
ProgramConfig userMsg userModel route pageData sharedData effect (Msg userMsg pageData sharedData errorPage) errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Model userModel pageData sharedData
-> Browser.Document (Msg userMsg pageData sharedData errorPage)
-> Browser.Document (Msg userMsg pageData actionData sharedData errorPage)
view config model =
let
{ title, body } =
@ -142,11 +142,11 @@ type InitKind shared page errorPage
{-| -}
init :
ProgramConfig userMsg userModel route pageData sharedData userEffect (Msg userMsg pageData sharedData errorPage) errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData userEffect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Flags
-> Url
-> Maybe Browser.Navigation.Key
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
init config flags url key =
let
pageDataResult : Result BuildError (InitKind sharedData pageData errorPage)
@ -163,10 +163,10 @@ init config flags url key =
config.decodeResponse
justBytes
of
Just (ResponseSketch.RenderPage _) ->
Just (ResponseSketch.RenderPage _ _) ->
Nothing
Just (ResponseSketch.HotUpdate pageData shared) ->
Just (ResponseSketch.HotUpdate pageData shared _) ->
OkPage shared pageData
|> Just
@ -223,7 +223,7 @@ init config flags url key =
}
|> config.init userFlags sharedData pageData key
cmd : Effect userMsg pageData sharedData userEffect errorPage
cmd : Effect userMsg pageData actionData sharedData userEffect errorPage
cmd =
UserCmd userCmd
@ -281,14 +281,14 @@ init config flags url key =
{-| -}
type Msg userMsg pageData sharedData errorPage
type Msg userMsg pageData actionData sharedData errorPage
= LinkClicked Browser.UrlRequest
| UrlChanged Url
| UserMsg userMsg
| UpdateCacheAndUrlNew Bool Url (Maybe userMsg) (Result Http.Error ( Url, ResponseSketch pageData sharedData ))
| UpdateCacheAndUrlNew Bool Url (Maybe userMsg) (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ))
| PageScrollComplete
| HotReloadCompleteNew Bytes
| ProcessFetchResponse (Result Http.Error ( Url, ResponseSketch pageData sharedData )) (Result Http.Error ( Url, ResponseSketch pageData sharedData ) -> Msg userMsg pageData sharedData errorPage)
| ProcessFetchResponse (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData )) (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
{-| -}
@ -310,23 +310,23 @@ type alias Model userModel pageData sharedData =
}
type Effect userMsg pageData sharedData userEffect errorPage
type Effect userMsg pageData actionData sharedData userEffect errorPage
= ScrollToTop
| NoEffect
| BrowserLoadUrl String
| BrowserPushUrl String
| FetchPageData Int (Maybe RequestInfo) Url (Result Http.Error ( Url, ResponseSketch pageData sharedData ) -> Msg userMsg pageData sharedData errorPage)
| Batch (List (Effect userMsg pageData sharedData userEffect errorPage))
| FetchPageData Int (Maybe RequestInfo) Url (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
| Batch (List (Effect userMsg pageData actionData sharedData userEffect errorPage))
| UserCmd userEffect
| CancelRequest Int
{-| -}
update :
ProgramConfig userMsg userModel route pageData sharedData userEffect (Msg userMsg pageData sharedData errorPage) errorPage
-> Msg userMsg pageData sharedData errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData userEffect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Msg userMsg pageData actionData sharedData errorPage
-> Model userModel pageData sharedData
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
update config appMsg model =
case appMsg of
LinkClicked urlRequest ->
@ -462,10 +462,10 @@ update config appMsg model =
let
( newPageData, newSharedData ) =
case newData of
ResponseSketch.RenderPage pageData ->
ResponseSketch.RenderPage pageData _ ->
( pageData, previousPageData.sharedData )
ResponseSketch.HotUpdate pageData sharedData ->
ResponseSketch.HotUpdate pageData sharedData _ ->
( pageData, sharedData )
_ ->
@ -563,14 +563,14 @@ update config appMsg model =
|> Result.map
(\pageData ->
let
newThing : Maybe (ResponseSketch pageData sharedData)
newThing : Maybe (ResponseSketch pageData actionData sharedData)
newThing =
-- TODO if ErrorPage, call ErrorPage.init to get appropriate Model?
pageDataBytes
|> Bytes.Decode.decode config.decodeResponse
in
case newThing of
Just (ResponseSketch.RenderPage newPageData) ->
Just (ResponseSketch.RenderPage newPageData _) ->
( { model
| pageData =
Ok
@ -583,7 +583,7 @@ update config appMsg model =
, NoEffect
)
Just (ResponseSketch.HotUpdate newPageData newSharedData) ->
Just (ResponseSketch.HotUpdate newPageData newSharedData _) ->
( { model
| pageData =
Ok
@ -605,7 +605,7 @@ update config appMsg model =
|> Result.withDefault ( model, NoEffect )
perform : ProgramConfig userMsg userModel route pageData sharedData userEffect (Msg userMsg pageData sharedData errorPage) errorPage -> Url -> Maybe Browser.Navigation.Key -> Effect userMsg pageData sharedData userEffect errorPage -> Cmd (Msg userMsg pageData sharedData errorPage)
perform : ProgramConfig userMsg userModel route pageData actionData sharedData userEffect (Msg userMsg pageData actionData sharedData errorPage) errorPage -> Url -> Maybe Browser.Navigation.Key -> Effect userMsg pageData actionData sharedData userEffect errorPage -> Cmd (Msg userMsg pageData actionData sharedData errorPage)
perform config currentUrl maybeKey effect =
-- elm-review: known-unoptimized-recursion
case effect of
@ -640,8 +640,8 @@ perform config currentUrl maybeKey effect =
let
prepare :
(Result Http.Error Url -> userMsg)
-> Result Http.Error ( Url, ResponseSketch pageData sharedData )
-> Msg userMsg pageData sharedData errorPage
-> Result Http.Error ( Url, ResponseSketch pageData actionData sharedData )
-> Msg userMsg pageData actionData sharedData errorPage
prepare toMsg info =
UpdateCacheAndUrlNew True currentUrl (info |> Result.map Tuple.first |> toMsg |> Just) info
in
@ -683,8 +683,8 @@ perform config currentUrl maybeKey effect =
{-| -}
application :
ProgramConfig userMsg userModel route pageData sharedData effect (Msg userMsg pageData sharedData errorPage) errorPage
-> Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg pageData sharedData errorPage)
ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Platform.Program Flags (Model userModel pageData sharedData) (Msg userMsg pageData actionData sharedData errorPage)
application config =
Browser.application
{ init =
@ -728,10 +728,10 @@ type alias RequestInfo =
withUserMsg :
ProgramConfig userMsg userModel route pageData sharedData userEffect (Msg userMsg pageData sharedData errorPage) errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData userEffect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> userMsg
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
withUserMsg config userMsg ( model, effect ) =
case model.pageData of
Ok pageData ->
@ -761,11 +761,11 @@ urlPathToPath urls =
fetchRouteData :
Int
-> (Result Http.Error ( Url, ResponseSketch pageData sharedData ) -> Msg userMsg pageData sharedData errorPage)
-> ProgramConfig userMsg userModel route pageData sharedData effect (Msg userMsg pageData sharedData errorPage) errorPage
-> (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect (Msg userMsg pageData actionData sharedData errorPage) errorPage
-> Url
-> Maybe { contentType : String, body : String }
-> Cmd (Msg userMsg pageData sharedData errorPage)
-> Cmd (Msg userMsg pageData actionData sharedData errorPage)
fetchRouteData transitionKey toMsg config url details =
{-
TODO:
@ -844,16 +844,16 @@ chopEnd needle string =
startNewGetLoad :
String
-> (Result Http.Error ( Url, ResponseSketch pageData sharedData ) -> Msg userMsg pageData sharedData errorPage)
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData sharedData userEffect errorPage )
-> (Result Http.Error ( Url, ResponseSketch pageData actionData sharedData ) -> Msg userMsg pageData actionData sharedData errorPage)
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
-> ( Model userModel pageData sharedData, Effect userMsg pageData actionData sharedData userEffect errorPage )
startNewGetLoad pathToGet toMsg ( model, effect ) =
let
currentUrl : Url
currentUrl =
model.url
cancelIfStale : Effect userMsg pageData sharedData userEffect errorPage
cancelIfStale : Effect userMsg pageData actionData sharedData userEffect errorPage
cancelIfStale =
case model.transition of
Just (Loading transitionKey path) ->

View File

@ -76,7 +76,7 @@ type alias Program route =
{-| -}
cliApplication :
ProgramConfig userMsg userModel (Maybe route) pageData sharedData effect mappedMsg errorPage
ProgramConfig userMsg userModel (Maybe route) pageData actionData sharedData effect mappedMsg errorPage
-> Program (Maybe route)
cliApplication config =
let
@ -84,7 +84,7 @@ cliApplication config =
site =
getSiteConfig config
getSiteConfig : ProgramConfig userMsg userModel (Maybe route) pageData sharedData effect mappedMsg errorPage -> SiteConfig
getSiteConfig : ProgramConfig userMsg userModel (Maybe route) pageData actionData sharedData effect mappedMsg errorPage -> SiteConfig
getSiteConfig fullConfig =
case fullConfig.site of
Just mySite ->
@ -199,12 +199,12 @@ requestDecoder =
|> Codec.decoder
flatten : SiteConfig -> RenderRequest route -> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage -> List Effect -> Cmd Msg
flatten : SiteConfig -> RenderRequest route -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage -> List Effect -> Cmd Msg
flatten site renderRequest config list =
Cmd.batch (flattenHelp [] site renderRequest config list)
flattenHelp : List (Cmd Msg) -> SiteConfig -> RenderRequest route -> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage -> List Effect -> List (Cmd Msg)
flattenHelp : List (Cmd Msg) -> SiteConfig -> RenderRequest route -> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage -> List Effect -> List (Cmd Msg)
flattenHelp soFar site renderRequest config list =
case list of
first :: rest ->
@ -222,7 +222,7 @@ flattenHelp soFar site renderRequest config list =
perform :
SiteConfig
-> RenderRequest route
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Effect
-> Cmd Msg
perform site renderRequest config effect =
@ -361,7 +361,7 @@ flagsDecoder =
init :
SiteConfig
-> RenderRequest route
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Decode.Value
-> ( Model route, Effect )
init site renderRequest config flags =
@ -388,14 +388,40 @@ init site renderRequest config flags =
}
isActionDecoder : Decode.Decoder Bool
isActionDecoder =
Decode.field "method" Decode.string
|> Decode.map
(\method ->
case method |> String.toUpper of
"GET" ->
False
"OPTIONS" ->
False
_ ->
True
)
initLegacy :
SiteConfig
-> RenderRequest route
-> { staticHttpCache : RequestsAndPending, isDevServer : Bool }
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> ( Model route, Effect )
initLegacy site renderRequest { staticHttpCache, isDevServer } config =
let
isAction : Bool
isAction =
renderRequest
|> RenderRequest.maybeRequestPayload
|> Maybe.map (Decode.decodeValue isActionDecoder)
|> Maybe.withDefault (Ok False)
|> Result.withDefault False
|> Debug.log "@@@isAction"
staticResponses : StaticResponses
staticResponses =
case renderRequest of
@ -403,10 +429,16 @@ initLegacy site renderRequest { staticHttpCache, isDevServer } config =
case singleRequest of
RenderRequest.Page serverRequestPayload ->
StaticResponses.renderSingleRoute
(DataSource.map3 (\_ _ _ -> ())
(config.data serverRequestPayload.frontmatter)
config.sharedData
(config.globalHeadTags |> Maybe.withDefault (DataSource.succeed []))
(if isAction then
config.action serverRequestPayload.frontmatter
|> DataSource.map (\_ -> ())
-- TODO do loader or action based on METHOD
else
DataSource.map3 (\_ _ _ -> ())
(config.data serverRequestPayload.frontmatter)
config.sharedData
(config.globalHeadTags |> Maybe.withDefault (DataSource.succeed []))
)
(if isDevServer then
config.handleRoute serverRequestPayload.frontmatter
@ -461,7 +493,7 @@ initLegacy site renderRequest { staticHttpCache, isDevServer } config =
updateAndSendPortIfDone :
SiteConfig
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Model route
-> ( Model route, Effect )
updateAndSendPortIfDone site config model =
@ -474,7 +506,7 @@ updateAndSendPortIfDone site config model =
{-| -}
update :
SiteConfig
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Msg
-> Model route
-> ( Model route, Effect )
@ -520,7 +552,7 @@ update site config msg model =
nextStepToEffect :
SiteConfig
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Model route
-> ( StaticResponses, StaticResponses.NextStep route )
-> ( Model route, Effect )
@ -578,6 +610,7 @@ nextStepToEffect site config model ( updatedStaticResponsesModel, nextStep ) =
config.sharedData
model.allRawResponses
|> Result.mapError (StaticHttpRequest.toBuildError "")
|> Debug.log "@@@sharedData"
apiResponse : Effect
apiResponse =
@ -666,7 +699,7 @@ nextStepToEffect site config model ( updatedStaticResponsesModel, nextStep ) =
sendSinglePageProgress :
SiteConfig
-> RequestsAndPending
-> ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
-> ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Model route
-> { path : Path, frontmatter : route }
-> Effect
@ -674,6 +707,15 @@ sendSinglePageProgress site contentJson config model info =
let
( page, route ) =
( info.path, info.frontmatter )
isAction : Bool
isAction =
model.maybeRequestJson
|> RenderRequest.maybeRequestPayload
|> Maybe.map (Decode.decodeValue isActionDecoder)
|> Maybe.withDefault (Ok False)
|> Result.withDefault False
|> Debug.log "@@@isAction sendSingle"
in
case model.maybeRequestJson of
RenderRequest.SinglePage includeHtml _ _ ->
@ -696,6 +738,7 @@ sendSinglePageProgress site contentJson config model info =
case includeHtml of
RenderRequest.OnlyJson ->
pageDataResult
|> Debug.log "pageDataResult"
|> Result.map
(\okPageData ->
case okPageData of
@ -802,6 +845,7 @@ sendSinglePageProgress site contentJson config model info =
}
)
--Debug.todo ""
currentUrl : Url
currentUrl =
{ protocol = Url.Https
@ -820,6 +864,14 @@ sendSinglePageProgress site contentJson config model info =
contentJson
|> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
actionDataResult : Result BuildError (PageServerResponse actionData errorPage)
actionDataResult =
-- TODO OPTIMIZATION can these three be included in StaticResponses.Finish?
StaticHttpRequest.resolve
(config.action (urlToRoute config currentUrl))
contentJson
|> Result.mapError (StaticHttpRequest.toBuildError currentUrl.path)
sharedDataResult : Result BuildError sharedData
sharedDataResult =
StaticHttpRequest.resolve
@ -848,19 +900,34 @@ sendSinglePageProgress site contentJson config model info =
-- TODO want to encode both shared and page data in dev server and HTML-embedded data
-- but not for writing out the content.dat files - would be good to optimize this redundant data out
--if model.isDevServer then
if True then
sharedDataResult
|> Result.map (ResponseSketch.HotUpdate pageData)
|> Result.withDefault (ResponseSketch.RenderPage pageData)
|> config.encodeResponse
|> Bytes.Encode.encode
if isAction then
case actionDataResult of
Ok (PageServerResponse.RenderPage _ actionData) ->
--actionData
-- |> ResponseSketch.Action
-- -- TODO remove hardcoded actionData
-- |> config.encodeResponse
-- |> Bytes.Encode.encode
actionData
-- TODO remove hardcoded actionData
|> config.encodeAction
|> Bytes.Encode.encode
_ ->
Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0)
else
pageData
|> ResponseSketch.RenderPage
sharedDataResult
|> Result.map (\something -> ResponseSketch.HotUpdate pageData something Nothing)
|> Result.withDefault (ResponseSketch.RenderPage pageData Nothing)
|> config.encodeResponse
|> Bytes.Encode.encode
--else
-- pageData
-- |> ResponseSketch.RenderPage
-- |> config.encodeResponse
-- |> Bytes.Encode.encode
PageServerResponse.ServerResponse serverResponse ->
-- TODO handle error?
PageServerResponse.toRedirect serverResponse
@ -877,7 +944,13 @@ sendSinglePageProgress site contentJson config model info =
PageServerResponse.ErrorPage error record ->
-- TODO this case should never happen
sharedDataResult
|> Result.map (ResponseSketch.HotUpdate (config.errorPageToData error))
|> Result.map
(\sharedData ->
ResponseSketch.HotUpdate (config.errorPageToData error)
sharedData
-- TODO remove hardcoded action data
Nothing
)
|> Result.map config.encodeResponse
|> Result.map Bytes.Encode.encode
|> Result.withDefault (Bytes.Encode.encode (Bytes.Encode.unsignedInt8 0))
@ -962,7 +1035,7 @@ sendSinglePageProgress site contentJson config model info =
render404Page :
ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage
ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage
-> Maybe sharedData
-> Model route
-> Path
@ -974,8 +1047,11 @@ render404Page config sharedData model path notFoundReason =
let
byteEncodedPageData : Bytes
byteEncodedPageData =
justSharedData
|> ResponseSketch.HotUpdate (config.errorPageToData config.notFoundPage)
ResponseSketch.HotUpdate
(config.errorPageToData config.notFoundPage)
justSharedData
-- TODO remove shared action data
Nothing
|> config.encodeResponse
|> Bytes.Encode.encode
@ -1054,7 +1130,7 @@ render404Page config sharedData model path notFoundReason =
|> Effect.SendSinglePageNew byteEncodedPageData
urlToRoute : ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage -> Url -> route
urlToRoute : ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage -> Url -> route
urlToRoute config url =
if url.path |> String.startsWith "/____elm-pages-internal____" then
config.notFoundRoute

View File

@ -1,11 +1,13 @@
module Pages.Internal.ResponseSketch exposing (ResponseSketch(..))
import Bytes exposing (Bytes)
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
import Path exposing (Path)
type ResponseSketch data shared
= RenderPage data
| HotUpdate data shared
type ResponseSketch data action shared
= RenderPage data (Maybe action)
| HotUpdate data shared (Maybe action)
| Redirect String
| NotFound { reason : NotFoundReason, path : Path }
| Action action

View File

@ -20,11 +20,10 @@ import Pages.Internal.RoutePattern exposing (RoutePattern)
import Pages.PageUrl exposing (PageUrl)
import Pages.SiteConfig exposing (SiteConfig)
import Path exposing (Path)
import Task exposing (Task)
import Url exposing (Url)
type alias ProgramConfig userMsg userModel route pageData sharedData effect mappedMsg errorPage =
type alias ProgramConfig userMsg userModel route pageData actionData sharedData effect mappedMsg errorPage =
{ init :
Pages.Flags.Flags
-> sharedData
@ -45,6 +44,7 @@ type alias ProgramConfig userMsg userModel route pageData sharedData effect mapp
, subscriptions : route -> Path -> userModel -> Sub userMsg
, sharedData : DataSource sharedData
, data : route -> DataSource (PageServerResponse pageData errorPage)
, action : route -> DataSource (PageServerResponse actionData errorPage)
, view :
{ path : Path
, route : route
@ -83,8 +83,9 @@ type alias ProgramConfig userMsg userModel route pageData sharedData effect mapp
, sendPageData : Pages.Internal.Platform.ToJsPayload.NewThingForPort -> Cmd Never
, byteEncodePageData : pageData -> Bytes.Encode.Encoder
, byteDecodePageData : route -> Bytes.Decode.Decoder pageData
, encodeResponse : ResponseSketch pageData sharedData -> Bytes.Encode.Encoder
, decodeResponse : Bytes.Decode.Decoder (ResponseSketch pageData sharedData)
, encodeResponse : ResponseSketch pageData actionData sharedData -> Bytes.Encode.Encoder
, encodeAction : actionData -> Bytes.Encode.Encoder
, decodeResponse : Bytes.Decode.Decoder (ResponseSketch pageData actionData sharedData)
, globalHeadTags : Maybe (DataSource (List Head.Tag))
, cmdToEffect : Cmd userMsg -> effect
, perform :

View File

@ -49,7 +49,7 @@ type IncludeHtml
decoder :
ProgramConfig userMsg userModel (Maybe route) pageData sharedData effect mappedMsg errorPage
ProgramConfig userMsg userModel (Maybe route) pageData actionData sharedData effect mappedMsg errorPage
-> Decode.Decoder (RenderRequest (Maybe route))
decoder config =
Decode.field "request"
@ -90,7 +90,7 @@ decoder config =
requestPayloadDecoder :
ProgramConfig userMsg userModel (Maybe route) pageData sharedData effect mappedMsg errorPage
ProgramConfig userMsg userModel (Maybe route) pageData actionData sharedData effect mappedMsg errorPage
-> Decode.Decoder (RequestPayload (Maybe route))
requestPayloadDecoder config =
(Decode.string