humphd / next

What I'm doing next (name TBD)
MIT License
14 stars 5 forks source link

Decide on a URL routing scheme and how to use React vs. docusaurus vs. ?? #125

Open humphd opened 6 years ago

humphd commented 6 years ago

We need to figure out what we want to do to integrate an app-style URL router in something like React with our Service Worker based URL scheme for getting access to resources in the browser. It's unclear how to cleanly merge these

humphd commented 6 years ago

@Pomax, would you be willing to give me some advice on this issue? Let me explain what I'm hoping to achieve, and maybe you can tell me what is and isn't possible with React routing.

We have a web app that looks a lot like a typical static web site with a regular web server, but everything is done via Service Worker routing. For example, currently:

URL Response
/ give a basic index.html page with links to other parts of the app
/terminal boots our Linux VM, starts an xterm.js based terminal
/www/{path/to/file} loads whatever file path you give in file (e.g., /foo/myfile.txt)
/www/{path/to/dir} loads a directory listing as HTML of whatever file path you give
/edit/{path/to/open} let's you edit files by opening some dir or file as your project
/share let's you export/import files using WebTorrent
... we have lots more

There are more, but the point is, we have 2 kinds of URLS:

  1. Those that return some raw response (a file from the browser filesystem)
  2. Those that return some kind of UI, and likely consume (fetch) files in some way to do things with them.

We are starting to think about moving our UI into React. Doing so (I think) we'd end up with a single app index.html and client-side routing/navigation to different parts of the system. I want to figure out a way to still support our arbitrary URL schemes (i.e, where we let users enter paths into the filesystem) and mix that with React's style of routing.

Consider an example:

The user goes to the main page

screen shot 2018-06-22 at 1 47 11 pm

This would be a React app/component for our site's UI, allowing you to find all the other parts of the app.

The user looks at the files in their server, visiting /www

screen shot 2018-06-22 at 1 47 24 pm

Here we render some UI when you visit /www, which in turn pulls filesystem data as JSON for a given path. For example, if you went to /www/some/other/dir we would show you the contents of /some/other/dir instead of / (the root dir).

The user opens the Editor (/edit) and creates new files

screen shot 2018-06-22 at 1 47 59 pm

The Editor is more UI that could be managed by React. It lets you create new content in the filesystem. We'd also want to support doing things like /edit/path/to/some/file.txt so you can open a portion of your filesystem vs. the entire thing.

The user goes back to their web server view

screen shot 2018-06-22 at 1 48 06 pm

The new file is there, as you'd expect.

The user clicks on the file, and it gets served raw

screen shot 2018-06-22 at 1 48 13 pm

Here we are viewing the file without any UI. This is like GitHub's ?raw=true, where you get served the file with its native mime type. I'm getting this file via the URL I enter: /www/path/to/file. So I need to support that in my app, and not have React render something.

I'm trying to figure out how to marry the idea of React's single-page-app routing style, with my Service Worker multiple-document-URL-api style of accessing the filesystem.

Is there some obvious way you can imagine doing this?

humphd commented 6 years ago

I should add that we've seen the so-called /# hash router, where you move around the app via React changing the URL's hash. I'm hoping there's a way to preserve URLs more closely, so I can map some of them directly to responses direct from the server (Service Worker) instead of having React manage.

Pomax commented 6 years ago

Yeah they solved the # nonsense a while ago, thankfully, by making proper use of the browser history API so it looks like you're changing URLs, when under the hook you stay in the same document and content just gets swapped in and out on the client-side, and using "server-side rendering" on the server (which basically asks the routing library which component belongs to which URL, then builds that, serializes it to HTML, and servers it as content that then basically "hot lodas" the react application back onto it).

So it depends a little on whether there is a server process running here. If there is, something like https://github.com/zeit/next.js/ should work quite well, if there isn't then things get for more tricky.

humphd commented 6 years ago

Interesting. So in our case, there is no server, only gh-pages. So is there some way to instruct React to allow some URL to pass through its usual routing, and let the underlying network request/response stuff take over?

Pomax commented 6 years ago

To do things cleanly, each route would need its own index.html with either a minimal HTML skeleton that loads the react app, which then looks at the URL and goes "aha! I need to load component XYZ", or with fully serialized client html (that still also loads the react app again so it can hook into the UI and take over from the browser).

The thing I did for github pages around "arbitrary routes" is a 404.html file in the root - any "virtual" location will end up hitting that, and some JS in the 404.html then does an immediate redirect to the project root with the original URL as argument, so the app can load itself with full knowledge of what the user "wanted" to see.

Basically the same idea as using # routing, but with real URLs that people can at least link to, with the tradeoff that it looks a bit weird during the initial page load because you'll see the URL bar change from something like "/blog/177263/everything-was-better-40-years-ago" (the URL the user visits) to "/?blog=177263" (the redirect URL) and then back to "/blog/177263/everything-was-better-40-years-ago" (this time effected as a history.replace() so the intermediate redirect disappears from the navigation history)

E.g.: https://pomax.github.io/1517436884711/listening-to-birds-from-inside-the-house, with the 404.html being really simple. https://github.com/Pomax/pomax.github.io/blob/master/404.html

humphd commented 6 years ago

OK, this is all very helpful, thank you. It seems like you need to pick: "server side" or client side rendering, and mixing is going to mean shenanigans. I feel like there must be some solution that takes the Service Worker into account, and combines URL routing with React routing.

Barring that, I think I'm going to go back to "server side" routing so I can maintain my URL API.

Pomax commented 6 years ago

What's currently doing the URL servicing? (if you already had something for that)

humphd commented 6 years ago

We use Workbox Routing in our Service Worker. This let's me respond to URLS with arbitrary paths on them, for example: /www/path/to/some/file/the/user/owns.html

Pomax commented 6 years ago

Hm, intesting... it feels like you should be able to tie that into react-router, so that you can ask it for the component associated with a path (it has a reverse lookup API), and then render that component as appropriate.