8 ms·
One downside I've observed from focusing on DX: We have too many single page apps / Jamstack sites, where the default is to send the entire application in Javas
by stevebmark 5y ago
One downside I've observed from focusing on DX: We have too many single page apps / Jamstack sites, where the default is to send the entire application in Javascript bundles, and do little to no HTML over the wire. This is inherently bad for performance and especially bad for mobile. It's why the Jamstack mascot is the loading spinner.
The much better solution, SSR first with optional client hydration, takes more developer work and more cognitive overhead. It's much easier to write a React application and not worry about server side specific data fetching to do universal rendering, even though that's the strongest option for performance. Next.js is bringing us closer to the DX of enabling SSR first by default, but it's not there yet and many people use Next.js only for SPAs or static rendering, and miss the point that its main power is universal/SSR.
My main takeaway is that DX is important when it introduces the right abstractions that are also end user focused.
- Zababa 5y ago> The much better solution, SSR first with optional client hydration, takes more developer work and more cognitive overhead. I would argue it takes less developer work and cognitive overhead if you're doing traditional SSR.
- H12 5y agoAnd the newer HTML-over-WebSockets pattern takes this even further, IMO. In my (admittedly limited) experience, it's hard to beat the DX provided by Phoenix LiveView.
- aabbcc1241 5y agoThat DX can be futher improved with static type check (e.g. with typescript)
- Zababa 5y agoI agree with static typing, but disagree with TypeScript itself. It's a great tool to type existing JS code, but for greenfield projets I find it lacking. Structural typing means that you can't make the difference between an address and a name without resorting to branding, which sucks. Strict null checks are opt in. ADTs are a pain to use.
- RussianCow 5y agoWhat is the alternative that doesn’t force you to use a completely different platform/ecosystem (a la Elm)?
- Zababa 5y agoThere isn't any as easy to integrate as TypeScript. TypeScript isn't flawed because of bad decisions, I think the people behind did an impressive job with it. TypeScript's flaws stems from JS and its ecosystem. And I really can't blame people from trying to keep their legacy systems. JS isn't going anywhere, and of of TS's selling point is that you can easily go back from TS to JS (I'm not sure how true that is, we'll see in a few years). ReScript (https://rescript-lang.org/ https://rescript-lang.org/) is trying to take another approach, which is being a different language, way simple and easier to use and in my opinion better than TS, but the price is that integration with JS is harder. The community is also small compared to TS. But you can leverage some work already done, as it can consume TS types. This may be what you asked for, as you can still use the ecosystem.
- candiddevmike 5y agoI don't think SSR is that big of a deal these days with faster phones and data plans. You get more returns focusing on bundle size, code splitting, and time to first paint.
- jelling 5y agoBlitz.js is worth a look as it supports both out of the box
- vosper 5y agoI like Blitz, but it’s built on Next JS - isn’t that where it gets it’s SSR and static capabilities?
- satvikpendem 5y agoThat seems to be correct, NextJS already has SSR and static capabilities like you say.
- Chyzwar 5y agoWith webpack you can use module federation to share code and reduce bundle size for micro-frontend applications. There are other ways to make your application bundle smaller. I spend a lot of time optimizing performance at work, both for UX and DX. It is common on HN to bash on large bundle sizes of SPAs, but in reality this not a problem unless users are on IE. At work, I often work tirelessly to reduce the amount of dependencies and bundle size, but I know that this would not make things faster, just more maintainable. For UX perf killers are IMO: - rendering large number of deeply nested dom nodes and doing repaints and reflows. - large data fetches and storing huge number of objects in memory. - slow/flaky APIs, in many cases slow backend is main bottleneck, JS is plenty fast - silly animations, bad design that force clicking and multi stage workflows. For DX perf killers - micro-something. Micro services/frontend in organistions without deep pockets. - special snowflakes internal abandoned framework that only two people in company know - lack of dedicated people for tooling and dev infrastructure - lava layer design pattern, multiple competing technologies used within same codebase/product.
- dfabulich 5y ago> It is common on HN to bash on large bundle sizes of SPAs, but in reality this not a problem unless users are on IE. This is dangerously wrong. Large bundle sizes are a huge problem on slow Android phones (and almost all Android phones in real-world use are slow). Even in the US, if you walk into a cellular store and ask for an affordable phone, they're going to give you a device that will take 7-10s to download, parse, and execute a 3MB JS bundle, even over wifi. (The parsing alone will kill you!) (And if you're in a developing economy? That "affordable" phone is the best phone you can reasonably buy with a month's wages. The median phone is even slower!)
- Chyzwar 5y agoIn US 55% of people carry iphone. Depending on app, people with affordable phones are not your users (b2b). Browsers would cache parsed javascript. More likly loading images will be slower. There are use cases that general perfomance matter a lot but people are obsesing on js bundle size too much.
- FractalHQ 5y agoWith Svelte my static sites are automatically pre-rendered and shipped as pre-compiled HTML. Loads instantly and optionally hydrates with JS in place. No extra effort needed.
- Noumenon72 5y agoI don't really understand hydration. I want to render an HTML report on the server with Jinja but be able to use React code in it, like Bootstrap tooltips. Is that possible? I can make the HTML the child of a React component with `dangerouslySetInnerHTML`, but not sure how to make it a first-class citizen of the page.
- satvikpendem 5y agoYou could use MDX [0], it integrates Markdown with React. Lots of MDX to HTML converters out there, I use it with NextJS which has a good MDX plugin. [0] https://mdxjs.com/ https://mdxjs.com/
- stevebmark 5y agoServer Side Rendering means that your Javascript produces an HTML string that's sent over the wire, like "<div><button></div>". The browser can render this HTML very, very fast, which is why it's desirable for performance. However, the <button> that's sent to the client won't have any Javascript onClick interactivity. That's where "hydration" comes in, React (or whatever) re-runs over the HTML already in the browser, and wires up click handlers, etc. The HTML on the page won't change, but now it will be interactive. The benefit is the user gets to see the HTML much faster. For some libraries that are very large, like Threejs or a charting library, or any tech that draws to a Canvas which probably can't be SSR'd, it's probably best to detect if you're on the server or the client in your React code (which is usually done by injecting some env variable into your bundle), and render an empty <div> on the server, and when the client hydrates, it will download the large library and create the chart. For other data, the trick is to create an API that works on both the server and the client. So `getPosts()` on the server will call to your internal API, and when that same function is executed on the client, it calls out to GraphQL. Then you switch out your API client on the server vs client bundle. In this way, your app is "universal," you can do a blocking fetch of posts on the server and render server side HTML, and on the client you can still call `getPosts()` on button clicks or whatever to fetch new posts. And API calls are much faster on your server side because you're in the same VPC, they don't go out over the public internet, and you might not even need TLS for them. For most SSR apps with hydration, the entire app is downloaded again on the front-end. What I want to see is selective hydration first. For example, you define your entire app in React, and things that don't change, like the header and the footer, are only rendered on the server, and the JS React code is never sent to the client. For things that need interactivity, like dropdowns, the React code is sent to the client only needed for the dropdown to make it interactive. I think selective/partial hydration should be the default behavior for webapps, only deviating if you have things like large JS libraries as mentioned above, or maybe applications that you always keep open in a single tab, like an email client. These same principles apply to CSS rendering too. CSS should always be extracted to a static stylesheet and sent as a <style> tag. If you have to download JS, parse JS, run JS, and then get a stylesheet injected into the DOM, it's also a bad performance hit. Browsers will always be faster than us at showing vanilla CSS and HTML to users as fast as possible, which is what we want. The most important consideration of CSS libraries is whether or not they can produce static stylesheets. It's mystifying to me that none of the CSS-in-JS libraries mention if they can/can't do this as part of their landing pages. If users have to execute JS before CSS starts styling the page, you've lost the performance game.
- jorams 5y ago> We have too many single page apps / Jamstack sites, where the default is to send the entire application in Javascript bundles, and do little to no HTML over the wire. This is a confusing statement. Pre-rendering is a core principle of "Jamstack". To quote the site[1]: > With Jamstack, the entire front end is prebuilt into highly optimized static pages and assets during a build process. That seems the complete opposite of what you're saying the default is. [1]: https://jamstack.org/what-is-jamstack/ https://jamstack.org/what-is-jamstack/
- canyonero 5y ago> It's why the Jamstack mascot is the loading spinner. I know much of the HN crowd loves to hate on bloated SPA applications (and not for good reason, we all deserve better perf), but this comment makes no sense. You can have a fast website with no loading spinners, pre-rendering, static HTML and optional/client hydration running on Jamstack infra. It's misleading to suggest Jamstack = complicated/slow/bloated and SSR = fast/simple/good ux. Please take time to understand your tools. You can build a brittle/slow/poor ux website with SSR if you don't know what you're doing and/or don't care. I'd advise others to not worship one technique over another. Choose a stack that solves a problem for your users, demonstrate empathy, evaluate tradeoffs and things will be fine.