elm-pages 3.0 feedback #264
Replies: 5 comments 8 replies
-
I've read through it and it all makes sense. Sounds very exciting! The only thing throwing me off is the current term "serverless", because I'm deploying on GitHub Pages, therefore I don't have a server which I thought of as serverless. But I know that "serverless" also is the term used for the pay-per-execution model where there actually are servers, just not under your control. (I never liked that term in this context.) For the terminology in elm-pages I think that build-time vs request-time is much clearer, and you already use that terminology, so maybe it's just a case of deciding on one and using it consistently. 😊 |
Beta Was this translation helpful? Give feedback.
-
To give an update on the ServerRequest API, I'm going a new direction with this to have an API that is more declarative, very much like the Here's what it looked like before: data : ServerRequest.IsAvailable -> RouteParams -> DataSource (PageServerResponse Data)
data serverRequestKey routeParams =
let
serverReq : ServerRequest ( Maybe String, Time.Posix )
serverReq =
ServerRequest.init Tuple.pair
|> ServerRequest.optionalHeader "cookie"
|> ServerRequest.withRequestTime
in
serverReq
|> ServerRequest.toDataSource serverRequestKey
|> DataSource.andThen
(\( cookies, requestTime ) ->
case
cookies
|> Maybe.withDefault ""
|> CookieParser.parse
|> Dict.get "username"
of
Just username ->
DataSource.succeed
(PageServerResponse.RenderPage { username = username, requestTime = requestTime })
Nothing ->
DataSource.succeed
(PageServerResponse.ServerResponse (ServerResponse.temporaryRedirect "/login"))
) And with the new, more declarative API: data : RouteParams -> Request.Handler Data
data routeParams =
Request.oneOfHandler
[ Request.map2 Data
(Request.expectCookie "username")
Request.requestTime
|> Request.thenRespond
(\requestData ->
requestData
|> PageServerResponse.RenderPage
|> DataSource.succeed
)
, Request.succeed ()
|> Request.thenRespond
(\() ->
DataSource.succeed
(PageServerResponse.ServerResponse (ServerResponse.temporaryRedirect "/login"))
)
] It's also worth noting that we don't need the |
Beta Was this translation helpful? Give feedback.
-
This is kind of an interesting case. How should OPTIONS requests be handled (pre-flight requests that check which HTTP methods and which origins are allowed for CORS https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS). The options I can think of are:
(2) doesn't seem like a great idea to me because it seems likely to make too many assumptions that could end up leaving users in a dead end for certain use cases. And at the same time, it would probably mean limiting the expressive power of the Supporting some sort of middleware that all requests go through (4) seems like it could be a pretty good idea, but I need to figure how to get the semantics right and if there are any issues with that approach given the current API and mental model. Middleware is also a common way to handle CORS and OPTIONS requests, like in ExpressJS for example: https://expressjs.com/en/resources/middleware/cors.html. |
Beta Was this translation helpful? Give feedback.
-
@dillonkearns a couple of questions:
Sorry if I'm asking dumb questions. I haven't had any exposure to Elm Pages yet, but v3 seems promising because it opens the door for more dynamic use cases. |
Beta Was this translation helpful? Give feedback.
-
Hi @dillonkearns, thanks for the awesome elm-pages!
|
Beta Was this translation helpful? Give feedback.
-
Here's a preview of what's coming in
elm-pages
3.0. I need feedback to get this across the finish line, so please share your thoughts in the comments here or on Slack! Bonus points if you try it out and let me know how it goes.Here's a peek of what's new in elm-pages 3.0.
Serverless Pages
In
elm-pages
2.0, all pages were pre-rendered. That means you got HTML pages for each page in your site. You could also generate files fromApi.elm
. 3.0 gives you the ability to respond to requests in real-time on the server-side.There are 2 ways to handle requests server-side:
serverless
, but maybe there's a better name) - this means that there are no static files generated for this route at build-time, the route is just wired up so that it can respond when a request comes inprerenderWithFallback
, but again name could be improved) - this allows you to pre-render some routes like a regular pre-rendered page in elm-pages 2.0, but for any pages you didn't pre-render they can be handled at request-time. For example, maybe you pre-render the most recent or popular articles for a news paper site, but the archives are built at request-time since they aren't hit frequently and there are a lot of them.Note that pre-rendering can slow down your build, but the tradeoff is that pages that are handled at request-time could now fail when the user requests them, whereas a pre-rendered page would have resulted in a build failure if anything went wrong. And of course pre-rendered assets have less work to do at request-time, so you have to be mindful of performance using these new features.
Request-Time Routes
A few differences are that request-time routes (1) can access the ServerRequest as a
DataSource
. That gives you access to the actual incoming user request, including HTTP method, headers, body, query parameters, etc. You can respond with either by rendering a page, or by giving a custom HTTP response, as the example below illustrates. You cannot, however, pre-render any of these routes, they are always handled at request-time. The code for this example below is live here: https://elm-pages-pokedex.netlify.app/loginThe generated
Page.elm
API for this function looks like this:Hybrid Routes
Unlike Request-Time routes, Hybrid routes do not get access to the
DataSource.ServerRequest
information. That's because conceptually these are just like pre-rendered pages, except that you can defer pre-rendering for some of them. In practice, that means they're responding to a user request, but once that request is cached for the next user's request, you can see that there's actually no meaningful concept of a user's request but instead this is just pre-rendering lazily. So this is really just exactly like a pre-rendered page, except that it can run on the server to lazily pre-render.Here's an example (and the corresponding live page is at https://elm-pages-pokedex.netlify.app/25):
API Routes
The module name
Api.elm
may have seemed strange in elm-pages 2.0 since this is just a place where you can generate files like asitemap.xml
or RSS feed.Hopefully the name is more clear now with these new server-side API routes!
Here's an example (you can try it live at https://elm-pages-pokedex.netlify.app/api/repo/elm-pages):
That same request would look very similar for a Hybrid route, except that you cannot access
DataSource.ServerRequest
(as described above), and you can pre-render a subset of routes:To pre-render these JSON files instead of deferred hybrid rendering, you would just make a few small tweaks. So as you can see, these different rendering modes are easy to change:
DataSource.ServerRequest
I'm working on several high-level APIs to make it easier to work with standard formats like form data, parsed cookies, parsed headers, etc. My goal is to make it safe, easy, and high-level to access these things where possible. I don't want to make assumptions about people's use cases or prohibit any possible use cases, but I want to make assumptions where they are baked into these protocols and web standards and abstract details there.
You can see the preview of the Elm package docs here: https://elm-doc-preview.netlify.app/DataSource-ServerRequest?repo=dillonkearns%2Felm-pages&version=serverless-latest.
ServerResponse
APIThe
ServerResponse
API uses the builder pattern to let you define a custom server response. For example, for serverless (request-time) routes, you could respond with eitherPageServerResponse.RenderPage { ... }
(the value is theData
type for the page, and this will be what you get access to as yourDataSource
when the page is rendered.Or you could render a custom response, like a redirect, with:
PageServerResponse.ServerResponse (ServerResponse.temporaryRedirect "/"
See the preview of the API docs here: https://elm-doc-preview.netlify.app/ServerResponse?repo=dillonkearns%2Felm-pages&version=serverless-latest
Similar to the
DataSource.ServerRequest
API, my goal here is to abstract away as many low-level details of web standards as possible. I would welcome any feedback on possible core building blocks to include in this API.Adapters
In order to setup the code for server-side rendering and routing for different platforms, we need a flexible script.
elm-pages
3.0 uses a similar approach to SvelteKit's adapters here: https://github.com/sveltejs/kit/tree/master/packages/adapter-netlify.Right now, I only have an adapter for Netlify, and I would welcome contributions for other platforms: https://github.com/dillonkearns/elm-pages/blob/42f38cbe39062d10caae5ece5fdda8565eddd087/examples/pokedex/adapter.js
I'm still trying to figure out the best way to configure these adapter scripts and install different ones. As a starting point, it may just be a copy-pasted file, but I would love to hear feedback and ideas on this.
Beta Was this translation helpful? Give feedback.
All reactions