See the entire conversation

Learning the hard way that the modern answer to "holy cow, why is the TTFB so bad and the HTML payload so bloated?" is SSR + inline'd Redux. `window.__INITIAL_STATE__` is my nemesis.
99 replies and sub-replies as of Jul 18 2018

Seriously tho; not the first time *this month* I've seen > 300K of inline'd `window.__INITIAL_STATE__` for a page whose contents isn't (and won't ever be) that large. THIS IS WHY WE INVENTED AJAX, YO.
Seriously I find the youngs don't even know what Ajax is.
Yep, seen this emerging, too. How about a @____lighthouse audit for excessive embedded scripts? Same goes for styles (critical CSS sometimes gets out of hand). Also some mistakenly embedded laaarge SVGs.
e.g I’ve seen some pages where >30% of the HTML payload was SVG logos embedded in the footer.
30% of not very much is not very much. I mostly care about this sort of thing as a matter of scale.
Well, it was like 30KB if I remember well. Also for something that most users would never even see.
And you forgot to mention, you are responsible for that page
a) how else would I have noticed? (I’m not auditing pages at random - yet) b) guess who fixed it last time? (and pushing for a fix in the new version, too)
there is not any c option?
c) joel's fault ?
c) tbh @fantayeneh, you noticed it first
and he didn't fix it...
...or whatever that slow BS Twitter was pulling back in '10 or so. *sigh*
"React is the new ASP.NET" <- my tweet when they announced it at JSConf. My opinion has softened a bit. But yeah, lots of mistakes repeated.
The Official Microsoft ASP.NET Site
ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.
asp.net
You forget that "it's easy to reason about"
Ouch, oh dear, people are stillness doing that? Sometimes it feels like I spent half my time at science.ai trying to push back on just that 😑
Overview • science.ai
The new publishing experience.
science.ai
Nobody actually looks at the output of their systems, it seems.
I do! Or I did. I don't really do web development anymore. I wonder how many us were driven away by the giant do-everything-for-you frameworks/toolchains.
Still there, struggling. :) In my case it not Redux+SSR, but Apollo+SSR and JS Styles + SSR. But I think the main problem not with that libs, but React architecture, it requires rendering to discover components. So you aleays have multiple rendering cycles in the request path.
I'm in the middle being driven away right now. That's a slight exaggeration: I'm still at it, but I definitely do a lot more frowning, sighing, and thinking about what else I could do for a career.
Yeah — HTML all wrapped in React instead of the other way around, CSS-in-JS, Redux for trivial stuff… all killed Web dev for me; I’m now doing something else entirely. Wake me up when the Web gets over its “let’s make all the same mistakes Java made!” phase.
that page hardly needs JS at all lol
I'm guilty of this too (Sapper serializes preloaded data — equivalent to getInitialProps in Next.js — and includes it to avoid `preload` running on both server and client). Are you saying that it'd be better to fetch that same 300kb asyncly even if TTI suffers as a result?
Not exactly... This approach can be great in moderation; the problem is over-inclusion in the startup snapshot. Too much data, too little of it used. Delay load what isn't in the critical path.
tricky problem to solve at the tooling level I suppose. If you're streaming the HTML response, and the 300kb is inlined at the bottom of the page, does that sufficiently mitigate the problem?
those 300KB will still have to be parsed & executed on the main thread...
It's significantly better than some of the other approaches (from a raw latency perspective), and we can do *some* parsing off-thread. But from a tools perspective, you know what's going to be needed in initial model bootstrap via component execution on the server...right?
what about loading the data in a worker, then messaging it to the main thread? or is structured cloning 300kb of data not much better than parse/evaling it?
SC won't be better, per sae. Maybe <link rel="preload"> and have worker fetch? Or H/2 PUSH as JSON file?
JSON is no good if your payload includes Map, Set, Date, RegExp etc. Not sure how <link rel="preload"> helps — just that it's getting the data in parallel with the markup?
I'm not seeing those data types in these outputs, generally. They're just string hierarchies. Complex stuff is smushed. Wonder what tools are doing which thing.
i've found JSON to be too crude for real-world situations: // data var things = [a, b, c]; var selected = things[1]; payload = { things, selected } // ui — this doesn't work with JSON <div class={thing === selected ? 'selected' : ''}>... Sapper uses
Rich-Harris/devalue
devalue - Gets the job done when JSON.stringify can't
github.com
Bottom > start. Ideally each component has it’s own trailer of data that you can flush before waiting for more data. Assuming your system even supports incremental flushing of responses. React-ish component systems typically don't allow for this.
One key insight is: You need to emit at the start of the doc *what* data is going to come via streaming, so that the UI can incrementally initialize and know what will eventually stream in to avoid starting network requests.
do you have any examples of implementations of this approach?
Go to plus.google.com/+MalteUbl & view source, and search for AF_initDataKeys // Think of this as the GraphQL queries for which answers will be streamed and AF_initDataCallback for the individual streaming responses.
Malte Ubl - Google+
Curing my asynchronous identity disorder at Google
plus.google.com
Unfortunately there is a problem with the Promise API and SSR. Since you can't ask a promise whether it is done, you don't know when to flush the TCP buffer, so you have to guess.
Right, and I'm mostly seeing this in React apps where the model bootstrap is used to re-generate a bunch of already functional DOM. This gives me many feels.
yeah, it's wasteful. i've found it quite hard to think up general solutions to hydrating server-rendered DOM that don't involve duplicating stuff between markup and data. v interested in any examples you can share
The CS-ish solution would be flyweight components that only really hydrate (or re-create) when processing input events.
A lazier solution would be to only serialize data which was consumed in component generation for SSR and leave stubs for the rest.
The latter is pretty simple with Proxies.
I can definitely imagine scenarios where your UI expects to be able to access certain data synchronously, and your server wasn't aware that it needed to provide it because it happened in a client-only lifecycle hook
Yeah as a dev you need to be aware of it but I implemented it almost a year ago in one of my projects and it rarely creates problems and when it does, it's usually easy to notice and fix it manually. I'd say it's well worth it.
do you have a repo i can take a gander at by any chance?
Unfortunately no but can share a gist tomorrow. I was planning to opensource it later anyway.
Yep, I do this in one project with @RactiveJS and it works pretty well.
...but these apps also seem to be bundling all components, not just those used on the route/page, so IDK. "DX" has apparently liberated minds from the confines of mere physics.
well *that* problem at least is easily solved
...once your acknowledge it's an issue. The Cult of DX preaches that in the fullness of time, the path to (en)lightenment will be baked into your existing tools without any effort or understanding on your part.
DX is... Developer experience?
yes, often viewed as being in conflict with UX, but mostly because of the tools we currently use rather than something inherent
Maybe we should open source Wiz after all 😅
Do you find the DX of wiz in the same BallPark as other options externally today? I find it to feel quite "different". (not that it is bad just that open sourcing it is a small small piece of getting user uptake)
I feel that this bootstrap problem is a solvable thing in both react land and angular land today, the effort involved is more creating and baking the pattern into the ecosystem. Less so creating yet another framework.
Not sure about Angular. I don’t see how it can be done in React without an ugly overlay thing like Bigpipe. I do, however, think you can make a very React-y system that would not have these problems.
One key issue is that “good DX“ largely relies on running JS components in the server. Something that neither Google nor Facebook have been willing to do. And thus their solutions to these problems aren’t widely available.
Heh boq offers this as well in a non-deprecated way 😁
/me scours through Sam's CLs to see if he has any firsthand experience.
Ha, plenty of non-submitted stuff :) but lots on our team
Always boggles my mind that people use the stack for internal apps. @slightlylate often forgets to say this: For Enterprise Back Office Tool Dashboard Manager 2000 the DX/UX tradeoffs of many current generation frameworks are exactly right.
I'd agree and say the "Google" blessed public launch frameworks are the wrong choice for 99.9% of projects. 🤣
At Netflix we shipped some really amazing internal data visualization apps that would absolutely have been horrible had we tried to make it publicly accessible because the size was too big. But for internal use? It was awesome.
Exactly, but like most web apps are not for public use. Most usage is public, not not most apps. Using the same tools for vastly different use cases with different tradeoffs inevitably leads to bad outcomes for some of the use cases.
We are close to launching a Google product using Node.JS for SSR on Angular - Update in Node.JS summit next week. We are also reusing ideas from Wiz including jsaction and progressive bootstrapping. Will be closer to Wiz with Ivy renderer where we can module split better.
Be careful what you wish for. I think the opposite, running fully typed TypedScript on the JVM, would be a good option for Google.
Pretty sure @martin_probst would generally be into this :)
GraalVM could do it I reckon
With async rendering in react, one could now make the state tree be a bunch of lazy-loading properties (getters that create promises on demand).
I'd make some changes that should be done anyway. The DX of Wiz depends on a tightly integrated stack, and open sourcing that would be a large-team year-long effort.
you leave my var __INITIAL_STATE__ = {readyfns: []} </script></head> ... fetch(...)...then(state => readyfns.forEach(fn => fn(state))) </script> </body> alone! (really I just wanted to show an example alternative here for people who don't know of any)
I badly want to see one of these JS frameworks take a "sever-side first" approach". Provide the same conveniences people like from React/Vue/etc but make SSR the default and ship only a thin layer of JS to the client.
I mean, that's what Nuxt does, it's just one command to set up... it has better lighthouse scores out of the gate than even Vue CLI pwa, last time I checked ❤️
Do you mind expanding on this @sarah_edo? I’m super curious of the command you are referring to. 😬
vue init nuxt-community/starter-template <project-name> (You have to have Vue CLI installed globally first, but you should only run that once) This sets up a new Nuxt project.
Aside from SSR, it has code splitting, and you can do routing just by dipping a Vue component in the pages directory. So slick. 🌈
I've used Nuxt.js but am FAR from an expert. My understanding is you have two basic options: static site or server render and then Vue takes over. Is that correct? Is there something in the middle? Mostly static site with minimal JS for interactivity not a complete SPA takeover?
I believe that you're correct, but @Atinux and @_achopin would know more details.
You can also use @vuejs for interactivity only and not as a complete SPA. The router and state management are not required in your project. Static site and server render options depend on your architecture choice.
Yup, that's how we started - a bit of vue sprinkled on top of spring boot + thymeleaf. Mind you, not solution I'd recommend long term/for big project, but it certainly works with no problems.
i think that's what sapper/svelte is trying to do: sapper.svelte.technology/guide/
I hate to jump in with my own thing (or do I? I dunno) but @eleven_ty is exactly this. It ships sites with zero client-side JS and let’s you add what you want on top. 11ty.io/docs/
UGH YOU'RE ONE OF THOSE PEOPLE ;) Have yet to play with it, but it looks (and sounds) pretty slick.
I didn’t used to be, ugh lemme crawl into a hole now
:) In all seriousness: it's a cool thing you built and you should feel zero shame whatsoever for letting folks know about it.
Thanks Dad! 😎
Next / Nuxt are your friends.
ah yes, I know just the thing, they need to put that state into a hidden text area and eval it! /me ducks
Still one of my fav hacks. I haven't had this case personally but I'd totally use that technique if for some reason I needed a huge payload up front. But its way easier to just not need a huge payload up front. (Long term easier that is…)
Soooo server render (not React/Vue/whatever, I mean EJS/handlebars/pug on the server) + PJAX?
Yeah, seems like there is a need for a good howto article that measures the impact and provides a good alternative. Like those blocking scripts in twitter and Facebook widget docs back in a day, we can change the patter.