hyperapp-router
hyperapp-router copied to clipboard
How does this work with ssr and express?
Nothing?
I for one am not sure what the question means. @brielov Can you explain more specifically what you want to do?
I personally haven’t used SSR, so I can’t answer anything about that. But there is @hyperapp/render for that.
As for express, hyperapp’s router uses the history API, so you’ll want to configure your express router to fall back to serving the app-html instead of 404s
@brielov A server-side example Hyperapp using @hyperapp/render and @hyperapp/router? Nope, there isn't one.
The issue for me is that it seems like the router relies on window.location.pathname
so it throws error: ReferenceError: window is not defined
when using ssr.
https://github.com/hyperapp/router/blob/8db6747b3598c5c7832ffe1c0f09311fecb0ceee/src/location.js#L17-L21
I assume the router should somehow be able to parse req.path
through state.location
on the server e.g.
state.location = {
pathname: req.path
};
You are responsible to wire the router state to your state, so instead of
const state = {
location: location.state
}
You are able to use
const state = {
location: {
pathname: req.path,
previous: "/"
}
}
@Swizz I guess the problem in this code: https://github.com/hyperapp/router/blob/8db6747b3598c5c7832ffe1c0f09311fecb0ceee/src/location.js#L17-L21
This file is used internally and when it being executed it throws an error because window
is undefined on the server. I believe getState
function could help in this case.
@frenzzy Correct, there is also uses of history
in the components as well.
The root of the problem IMO is direct usage of these browser-only objects in the components.
Instead, I think it would be much cleaner and reusable if these components dispatched actions. This then leaves the implementation up to the user, as they can use a different set of actions for browser and SSR.
For example:
const clientActions = {
push: pathname => {
history.pushState({}, '', pathname)
return { pathname }
}
}
const serverActions = {
push: pathname => ({ pathname }),
}
See https://codepen.io/anon/pen/vRwdmy
Also:
Having these as actions allows them to be reused elsewhere. For example a page that submits a form then redirects to a 'Thank You' page on completion. This would then become trivial to implement with @hyperapp/fx
.
To redirect to an external page in SSR requires setting appropriate headers. This implementation of this may vary depending on which JS framework they are using.
It's probably also worth mentioning that I had issues when importing components from the index.js file with import { Route } from '@hyperapp/router'
.
Everything is fine with tree shaking enabled, but the window
and history
objects break things in SSR when theres no tree shaking.
I'm not sure on the best way to fix this. I just removed the offending files from the index.js import, then included them directly where needed.
About the browser only
objects used in @hyperapp/router
, there might be a workaround to make it work in node
environments for SSR.
I am facing the same problem. Probably adding an example on how to use @hyperapp/router
with @hyperapp/render
would help the community. For now, seems like the router code needs a bit of tweaks, am I right @dangerousdan ? Something that doesn't rely on browser only
.
Redirects might be also a fair situation in SSR too.
I don't use Hyperapp with Express and I have a tendency to favor pure client-based apps, so I haven't had the motivation to look into this, but PRs are super welcome! 😄
Thanks @jorgebucaran the workaround seems to be pretty simple, I'll create PR soon, combining a simple typeof window === 'undefined'
with @dangerousdan pen suggestion, it should be enough fine.