hyperapp-router icon indicating copy to clipboard operation
hyperapp-router copied to clipboard

How does this work with ssr and express?

Open ghost opened this issue 6 years ago • 11 comments

ghost avatar Mar 12 '18 14:03 ghost

Nothing?

ghost avatar Apr 06 '18 13:04 ghost

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

zaceno avatar Apr 06 '18 14:04 zaceno

@brielov A server-side example Hyperapp using @hyperapp/render and @hyperapp/router? Nope, there isn't one.

jorgebucaran avatar Apr 06 '18 14:04 jorgebucaran

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
    };

drejohnson avatar Apr 09 '18 18:04 drejohnson

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 avatar Apr 09 '18 20:04 Swizz

@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 avatar Apr 10 '18 07:04 frenzzy

@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.

dangerousdan avatar Apr 13 '18 11:04 dangerousdan

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.

dangerousdan avatar Apr 13 '18 11:04 dangerousdan

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.

jcperez-ch avatar Apr 16 '18 02:04 jcperez-ch

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! 😄

jorgebucaran avatar Apr 16 '18 03:04 jorgebucaran

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.

jcperez-ch avatar Apr 16 '18 03:04 jcperez-ch