mirror of
https://github.com/dillonkearns/elm-pages-v3-beta.git
synced 2024-11-24 06:54:03 +03:00
Pass through request from NodeJS and update the ServerRequest API.
This commit is contained in:
parent
3960da425c
commit
9769e7a95c
113
examples/pokedex/src/Page/Time.elm
Normal file
113
examples/pokedex/src/Page/Time.elm
Normal file
@ -0,0 +1,113 @@
|
||||
module Page.Time exposing (Data, Model, Msg, page)
|
||||
|
||||
import DataSource exposing (DataSource)
|
||||
import DataSource.ServerRequest as ServerRequest exposing (ServerRequest)
|
||||
import Dict exposing (Dict)
|
||||
import Head
|
||||
import Head.Seo as Seo
|
||||
import Html
|
||||
import Page exposing (Page, PageWithState, StaticPayload)
|
||||
import Pages.PageUrl exposing (PageUrl)
|
||||
import Pages.Url
|
||||
import QueryParams exposing (QueryParams)
|
||||
import Shared
|
||||
import Url
|
||||
import View exposing (View)
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
type alias Msg =
|
||||
Never
|
||||
|
||||
|
||||
type alias RouteParams =
|
||||
{}
|
||||
|
||||
|
||||
page : Page RouteParams Data
|
||||
page =
|
||||
Page.serverless
|
||||
{ head = head
|
||||
, data = data
|
||||
, routeFound = \_ -> DataSource.succeed True
|
||||
}
|
||||
--{ data : (ServerRequest decodedRequest -> DataSource decodedRequest) -> routeParams -> DataSource data
|
||||
--, routeFound : routeParams -> DataSource Bool
|
||||
--, head : StaticPayload data routeParams -> List Head.Tag
|
||||
--}
|
||||
|> Page.buildNoState { view = view }
|
||||
|
||||
|
||||
type alias Request =
|
||||
{ language : Maybe String
|
||||
, method : ServerRequest.Method
|
||||
, queryParams : Dict String (List String)
|
||||
, protocol : Url.Protocol
|
||||
, allHeaders : Dict String String
|
||||
}
|
||||
|
||||
|
||||
data : (ServerRequest a -> DataSource a) -> RouteParams -> DataSource Data
|
||||
data resolveServerRequest routeParams =
|
||||
let
|
||||
serverReq : ServerRequest Request
|
||||
serverReq =
|
||||
ServerRequest.init
|
||||
(\language method queryParams protocol allHeaders ->
|
||||
{ language = language
|
||||
, method = method
|
||||
, queryParams = queryParams |> QueryParams.toDict
|
||||
, protocol = protocol
|
||||
, allHeaders = allHeaders
|
||||
}
|
||||
)
|
||||
|> ServerRequest.optionalHeader "accept-language"
|
||||
|> ServerRequest.withMethod
|
||||
|> ServerRequest.withQueryParams
|
||||
|> ServerRequest.withProtocol
|
||||
|> ServerRequest.withAllHeaders
|
||||
in
|
||||
serverReq
|
||||
|> ServerRequest.toDataSource
|
||||
|> DataSource.map Data
|
||||
|
||||
|
||||
head :
|
||||
StaticPayload Data 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 = "Time"
|
||||
}
|
||||
|> Seo.website
|
||||
|
||||
|
||||
type alias Data =
|
||||
{ request : Request
|
||||
}
|
||||
|
||||
|
||||
view :
|
||||
Maybe PageUrl
|
||||
-> Shared.Model
|
||||
-> StaticPayload Data RouteParams
|
||||
-> View Msg
|
||||
view maybeUrl sharedModel static =
|
||||
{ title = "Time"
|
||||
, body =
|
||||
[ Html.text (static.data.request |> Debug.toString)
|
||||
]
|
||||
}
|
@ -5,7 +5,7 @@ module Page exposing
|
||||
, prerender, single
|
||||
, Builder(..)
|
||||
, PageWithState
|
||||
, serverless, prerenderWithFallback
|
||||
, prerenderWithFallback, serverless
|
||||
)
|
||||
|
||||
{-|
|
||||
@ -77,13 +77,15 @@ When there are Dynamic Route Segments, you need to tell `elm-pages` which pages
|
||||
|
||||
-}
|
||||
|
||||
import DataSource.ServerRequest as ServerRequest exposing (ServerRequest)
|
||||
import Browser.Navigation
|
||||
import DataSource exposing (DataSource)
|
||||
import DataSource.Http
|
||||
import DataSource.ServerRequest exposing (ServerRequest(..))
|
||||
import Head
|
||||
import Pages.Internal.NotFoundReason exposing (NotFoundReason)
|
||||
import Pages.Internal.RoutePattern exposing (RoutePattern)
|
||||
import Pages.PageUrl exposing (PageUrl)
|
||||
import Pages.Secrets as Secrets
|
||||
import Path exposing (Path)
|
||||
import Shared
|
||||
import View exposing (View)
|
||||
@ -304,7 +306,6 @@ prerender { data, head, pages } =
|
||||
}
|
||||
|
||||
|
||||
|
||||
{-| -}
|
||||
prerenderWithFallback :
|
||||
{ data : routeParams -> DataSource data
|
||||
@ -365,7 +366,7 @@ serverless :
|
||||
-> Builder routeParams data
|
||||
serverless { data, head, routeFound } =
|
||||
WithData
|
||||
{ data = data ServerRequest.toStaticHttp
|
||||
{ data = data DataSource.ServerRequest.toDataSource
|
||||
, staticRoutes = DataSource.succeed []
|
||||
, head = head
|
||||
, serverless = True
|
||||
|
@ -2,6 +2,7 @@ const path = require("path");
|
||||
const fs = require("fs");
|
||||
const which = require("which");
|
||||
const chokidar = require("chokidar");
|
||||
const { URL } = require("url");
|
||||
const {
|
||||
spawnElmMake,
|
||||
compileElmForBrowser,
|
||||
@ -252,7 +253,7 @@ async function start(options) {
|
||||
* @param {((value: any) => any) | null | undefined} onOk
|
||||
* @param {((reason: any) => PromiseLike<never>) | null | undefined} onErr
|
||||
*/
|
||||
function runRenderThread(pathname, onOk, onErr) {
|
||||
function runRenderThread(serverRequest, pathname, onOk, onErr) {
|
||||
let cleanUpThread = () => {};
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const readyThread = await waitForThread();
|
||||
@ -265,6 +266,7 @@ async function start(options) {
|
||||
readyThread.worker.postMessage({
|
||||
mode: "dev-server",
|
||||
pathname,
|
||||
serverRequest,
|
||||
});
|
||||
readyThread.worker.on("message", (message) => {
|
||||
if (message.tag === "done") {
|
||||
@ -344,6 +346,7 @@ async function start(options) {
|
||||
}
|
||||
|
||||
await runRenderThread(
|
||||
reqToJson(req),
|
||||
pathname,
|
||||
function (renderResult) {
|
||||
const is404 = renderResult.is404;
|
||||
@ -562,4 +565,19 @@ async function ensureRequiredExecutables() {
|
||||
}
|
||||
}
|
||||
|
||||
function reqToJson(req) {
|
||||
const url = new URL(req.url, "http://localhost:1234");
|
||||
return {
|
||||
method: req.method,
|
||||
hostname: req.hostname,
|
||||
query: url.search ? url.search.substring(1) : "",
|
||||
headers: req.headers,
|
||||
host: url.host,
|
||||
pathname: url.pathname,
|
||||
port: url.port,
|
||||
protocol: url.protocol,
|
||||
rawUrl: req.url,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { start };
|
||||
|
@ -7,16 +7,15 @@ let Elm;
|
||||
|
||||
global.staticHttpCache = {};
|
||||
|
||||
async function run({ mode, pathname }) {
|
||||
async function run({ mode, pathname, serverRequest }) {
|
||||
console.time(`${threadId} ${pathname}`);
|
||||
try {
|
||||
const req = null;
|
||||
const renderResult = await renderer(
|
||||
workerData.basePath,
|
||||
requireElm(mode),
|
||||
mode,
|
||||
pathname,
|
||||
req,
|
||||
serverRequest,
|
||||
function (patterns) {
|
||||
if (mode === "dev-server" && patterns.size > 0) {
|
||||
parentPort.postMessage({ tag: "watch", data: [...patterns] });
|
||||
|
@ -1,15 +1,21 @@
|
||||
module DataSource.ServerRequest exposing (ServerRequest, expectHeader, init, optionalHeader, staticData, toStaticHttp)
|
||||
module DataSource.ServerRequest exposing
|
||||
( ServerRequest, expectHeader, init, optionalHeader, staticData, toDataSource
|
||||
, Method(..), withAllHeaders, withHost, withMethod, withProtocol, withQueryParams
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs ServerRequest, expectHeader, init, optionalHeader, staticData, toStaticHttp
|
||||
@docs ServerRequest, expectHeader, init, optionalHeader, staticData, toDataSource
|
||||
|
||||
-}
|
||||
|
||||
import DataSource
|
||||
import DataSource.Http
|
||||
import Dict exposing (Dict)
|
||||
import OptimizedDecoder
|
||||
import QueryParams exposing (QueryParams)
|
||||
import Secrets
|
||||
import Url
|
||||
|
||||
|
||||
{-| -}
|
||||
@ -33,8 +39,8 @@ staticData =
|
||||
|
||||
|
||||
{-| -}
|
||||
toStaticHttp : ServerRequest decodesTo -> DataSource.DataSource decodesTo
|
||||
toStaticHttp (ServerRequest decoder) =
|
||||
toDataSource : ServerRequest decodesTo -> DataSource.DataSource decodesTo
|
||||
toDataSource (ServerRequest decoder) =
|
||||
DataSource.Http.get (Secrets.succeed "$$elm-pages$$headers") decoder
|
||||
|
||||
|
||||
@ -43,18 +49,164 @@ expectHeader : String -> ServerRequest (String -> value) -> ServerRequest value
|
||||
expectHeader headerName (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.field headerName OptimizedDecoder.string
|
||||
(OptimizedDecoder.field (headerName |> String.toLower) OptimizedDecoder.string
|
||||
|> OptimizedDecoder.field "headers"
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
withAllHeaders : ServerRequest (Dict String String -> value) -> ServerRequest value
|
||||
withAllHeaders (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.dict OptimizedDecoder.string
|
||||
|> OptimizedDecoder.field "headers"
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
withMethod : ServerRequest (Method -> value) -> ServerRequest value
|
||||
withMethod (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.field "method" OptimizedDecoder.string
|
||||
|> OptimizedDecoder.map methodFromString
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
withHost : ServerRequest (String -> value) -> ServerRequest value
|
||||
withHost (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.field "host" OptimizedDecoder.string)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
withProtocol : ServerRequest (Url.Protocol -> value) -> ServerRequest value
|
||||
withProtocol (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.field "protocol" OptimizedDecoder.string
|
||||
|> OptimizedDecoder.andThen
|
||||
(\protocol ->
|
||||
if protocol |> String.startsWith "https" then
|
||||
OptimizedDecoder.succeed Url.Https
|
||||
|
||||
else if protocol |> String.startsWith "http" then
|
||||
OptimizedDecoder.succeed Url.Http
|
||||
|
||||
else
|
||||
OptimizedDecoder.fail <| "Unexpected protocol: " ++ protocol
|
||||
)
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
withQueryParams : ServerRequest (QueryParams -> value) -> ServerRequest value
|
||||
withQueryParams (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.field "query" OptimizedDecoder.string
|
||||
|> OptimizedDecoder.map QueryParams.fromString
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
{-| -}
|
||||
optionalHeader : String -> ServerRequest (Maybe String -> value) -> ServerRequest value
|
||||
optionalHeader headerName (ServerRequest decoder) =
|
||||
decoder
|
||||
|> OptimizedDecoder.andMap
|
||||
(OptimizedDecoder.optionalField headerName OptimizedDecoder.string
|
||||
(OptimizedDecoder.optionalField (headerName |> String.toLower) OptimizedDecoder.string
|
||||
|> OptimizedDecoder.field "headers"
|
||||
)
|
||||
|> ServerRequest
|
||||
|
||||
|
||||
type Method
|
||||
= Connect
|
||||
| Delete
|
||||
| Get
|
||||
| Head
|
||||
| Options
|
||||
| Patch
|
||||
| Post
|
||||
| Put
|
||||
| Trace
|
||||
| NonStandard String
|
||||
|
||||
|
||||
methodFromString : String -> Method
|
||||
methodFromString rawMethod =
|
||||
case rawMethod |> String.toLower of
|
||||
"connect" ->
|
||||
Connect
|
||||
|
||||
"delete" ->
|
||||
Delete
|
||||
|
||||
"get" ->
|
||||
Get
|
||||
|
||||
"head" ->
|
||||
Head
|
||||
|
||||
"options" ->
|
||||
Options
|
||||
|
||||
"patch" ->
|
||||
Patch
|
||||
|
||||
"post" ->
|
||||
Post
|
||||
|
||||
"put" ->
|
||||
Put
|
||||
|
||||
"trace" ->
|
||||
Trace
|
||||
|
||||
_ ->
|
||||
NonStandard rawMethod
|
||||
|
||||
|
||||
{-| Gets the HTTP Method as a String, like 'GET', 'PUT', etc.
|
||||
-}
|
||||
methodToString : Method -> String
|
||||
methodToString method =
|
||||
case method of
|
||||
Connect ->
|
||||
"CONNECT"
|
||||
|
||||
Delete ->
|
||||
"DELETE"
|
||||
|
||||
Get ->
|
||||
"GET"
|
||||
|
||||
Head ->
|
||||
"HEAD"
|
||||
|
||||
Options ->
|
||||
"OPTIONS"
|
||||
|
||||
Patch ->
|
||||
"PATCH"
|
||||
|
||||
Post ->
|
||||
"POST"
|
||||
|
||||
Put ->
|
||||
"PUT"
|
||||
|
||||
Trace ->
|
||||
"TRACE"
|
||||
|
||||
NonStandard nonStandardMethod ->
|
||||
nonStandardMethod
|
||||
|
Loading…
Reference in New Issue
Block a user