4 ms·
Are there any JS frameworks that make it easy to build SPAs that degrade gracefully when JS isn't available? I know there's a lot of work done on making server
by andrewfong 9y ago
Are there any JS frameworks that make it easy to build SPAs that degrade gracefully when JS isn't available?
I know there's a lot of work done on making server-side rendering work with React / Vue / whatever, but I'm wondering if there's a framework available that asks for some tradeoffs in how your SPA is structured in order to maximize the amount of functionality available when scripting is off (similar to how Redux asks you to make state-management tradeoffs in order to get hot-reloading, dev tools, etc.).
For example, you'd probably want, at a minimum:
* By default, all code related to fetching or subscribing to data from a server is tied to URL routing.
* By default, all code related to sending data to a server works with standard webforms.
The closest analogue to what I'm thinking about is Turbolinks and Ruby on Rails, but I'm curious if there's some equivalent in JS-land because you'd get less context-switching when adding extra JS-only SPA interactions on top of the core JS-optional form-based interaction.
- brut 9y agoI don't have a specific answer to your question. What I think would be much more sensible is to design your website without JS, and then sprinkle it here and there. Ex: Make a request to an API upon page load. Populate tables or whatever you want. Then if JS is enabled, load a script that makes AJAX calls to the API to update the data every x seconds. That way your site gets "enhanced" by JS and is completely usable without it.
- andrewfong 9y agoYes, the issue is then that you have to write two pieces of DOM rendering code (some view code in erb/jinja/whatever to populate a template on the server, and a piece of JS to update the table afterwards). And if you want to allow JS-enabled browsers to transition between views (and different data subscriptions) without having to reload the entire page, then you'll have to write two pieces of routing code (one route in Rails/Django/whatever and another in JS). And if you want to allow JS-enabled browsers to post form data back to your server and make minor changes to the page (e.g. edit one field in a table) without reloading the entire DOM, then you'll have to write two different routes on your server -- one that processes the form data and returns the HTML for a newly rendered page, and one that processes the same form data and returns only what's changed. You could, of course, use server-side-rendering JS to DRY things up for issue one. I'm more curious if anything reduces the boilerplate for issues two and three.
- jkeat 9y agoOn the topic of server-side rendering, Ember's Fastboot is worth checking out. https://ember-fastboot.com/ https://ember-fastboot.com/
- andrewfong 9y agoFastboot (and SSR in general) is nice, but this only ensures that no JS is required for the initial page load. For a true no-JS experience, you'd also need to handle (among other things) posting data back to the server without JS.
- madjam002 9y agoIf you use Redux and React server side rendering, you can quite easily wrap forms/interactions on your page with a <form /> tag and a hidden input with the Redux action name, and then handle the actions/reducers on the server. I've played around with it in the past and managed to convert a SPA which was using redux-form heavily to work fully without Javascript enabled, and it was only like ~200sloc.
- RussianCow 9y agoI wouldn't say it's "quite easily" done. The most obvious challenge is components that depend on data loaded asynchronously: If the only thing the component renders is a "loading" message while it fetches something from an API, that's all that the server is going to render as well. So you have to figure out a way to render asynchronously on the server-side, and then you also have to come up with a generic way to handle cookies, redirects, fallbacks for interactive features, etc. So it might be easy for really simple apps, but it gets incredibly involved as your app becomes more complex. The nice thing about this, though, is that most of the work happens up front, and as long as you develop the app within the proper constraints, server-side rendering is more or less "free" after that.
- madjam002 9y agoAgreed, but the overhead of coming up with "generic" ways to handle all of these interactive features like data fetching, redirects, etc, isn't that big (at least from what I've experienced). It's good to have a standardised way of doing all of those things anyway, and when you do, you can make sure they all work on the server.
- RussianCow 9y agoI don't agree. Dealing with asynchronous API calls in a generic manner is, in my experience, non-trivial. It's been a little while since I've tried it, so maybe things have changed, but when I tried this, the React server rendering API converted the immediate rendering of the component to a string, which means you effectively have to pre-load all the relevant data outside the React app, which may be really difficult depending on how you've architected your app. All the other stuff is pretty easy, though. :)
- insin 9y agoYou can achieve that with any view library which can rehydrate from a server-rendered version and can support your minimum list of requirements. The specifics depends on the libraries you're using. I was experimenting with this [1] a couple of years ago with React, react-router and a form library based on django.forms. The key was to handle form submission in components which behaved like they were servicing a request on both sides, passing in the POST body on the server or form data extracted in the same format on the client. There's some not-so-fun plumbing to make sure everybody has the data they need to re-render with user input and validation errors when they happen, and to handle redirect-after-submit properly on both sides, but I initially had to hack some of the necessary plumbing into a pre v1.0.0 react-router so the specifics are probably no longer relevant. [1] https://isomorphic-lab.herokuapp.com https://isomorphic-lab.herokuapp.com