Skip to content

Commit e93bfb1

Browse files
committed
Two more scripts
1 parent 3068abd commit e93bfb1

File tree

2 files changed

+513
-0
lines changed

2 files changed

+513
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
I love starting new projects!
2+
3+
It's so much fun to architect an app from scratch.
4+
5+
My latest project is another app starter, this time focusing on server-side rendered React...
6+
7+
...with the regular hooks into Firebase... and a special focus on performance.
8+
9+
It's basically an app shell that scores well on Lighthouse and incorporates everything that I need.
10+
11+
Once this app shell is running smoothly I'll use it to start my next production app...
12+
13+
...so it's super important that I get this done right...
14+
15+
...because my business will succeed or fail based on how well this app appeals to users.
16+
17+
PAUSE FOR INTERSTITIAL
18+
19+
PAUSE FOR INTERSTITIAL
20+
21+
PAUSE FOR INTERSTITIAL
22+
23+
PAUSE FOR INTERSTITIAL
24+
25+
I'm calling this initial project Firebase SSR Starter, where SSR stands for server-side rendered.
26+
27+
And of course I have benchmarks for this project, which is why this is interesting.
28+
29+
First, the app needs to be SEO-friendly and server-side rendered.
30+
31+
Second, I need an architecture that will last for another three-to-five years.
32+
33+
And finally, I need to max out my Lighthouse performance score.
34+
35+
I've been doing a bunch of research and landed on Next.js with React.
36+
37+
Next.js has an excellent server-side rendering system.
38+
39+
Next is a framework, which I kinda hate... but it's flexible enough...
40+
41+
...and it solves so many problems that I'd have to solve myself...
42+
43+
...and I know that I couldn't roll a stronger framework than Next.
44+
45+
Now for my maintainability requirement...
46+
47+
Three-to-five years is a steep requirement in the JavaScript ecosystem...
48+
49+
...so I'm not using any of the fancy, new stuff that I kinda want to use.
50+
51+
I need long-term maintainability, so I'm sticking with React.
52+
53+
I'd love to try lit-html or use Preact... but I can't justify it.
54+
55+
React has the ecosystem momentum these days, and I'm going to need a lot of continuity.
56+
57+
I need the lowest maintenance costs possible in years two through five of this app's lifespan.
58+
59+
My last big, long-term app was written in AngularJS, and we all know how AngularJS went...
60+
61+
...year one was great, two was a little sad, and years three and four have been a failure.
62+
63+
The last time I had to build my old AngularJS app from scratch I spent 12 hours resurrecting it.
64+
65+
I'm not doing that again, so I'm sticking with tried-and-true React.
66+
67+
So now it's time for performance!
68+
69+
Lighthouse is a Chrome extension that will be an integrated part of DevTools in Chrome 69.
70+
71+
Lighthouse runs hundreds of tests on your app and tells you that your performance is horrible.
72+
73+
So then you spend the next few days improving your app's performance with Lighthouse's checklist...
74+
75+
...and you either get to a perfect score of 100 or, like me, give up in the high 90s.
76+
77+
Lighthouse includes a bunch of nice-to-have optimizations.
78+
79+
A truly generic app architecture should be able to score a 100 on Lighthouse pretty easily...
80+
81+
...however, once you start to make app-specific decisions, scoring 100 can be impossible.
82+
83+
For instance, I'm using a React Material Design framework which doesn't support passive scrolling.
84+
85+
And of course Lighthouse requires passive scrolling for a perfect one hundred...
86+
87+
...and I'm not about to hack into the internals of this Material Design framework...
88+
89+
...especially not for very minor passive-scroll improvements.
90+
91+
So I'm not scoring a perfect one hundred... but I got pretty close.
92+
93+
The hardest part of this entire Lighthouse performance audit was getting Firebase to load.
94+
95+
Each part of Firebase is available as its own SDK...
96+
97+
...so once the main `firebase dash app` library is imported, you can import each piece separately.
98+
99+
But even in separate parts, Firebase is a heavy library.
100+
101+
All of those juicy Firebase features don't come for free.
102+
103+
I optimized my Firebase imports by not bundling Firebase with the rest of my app.
104+
105+
I added script tags for each part of the Firebase SDK into the app shell.
106+
107+
But I made sure to put those script tags near the end of my body tag...
108+
109+
...because they have to be loaded in a synchronous, blocking manner.
110+
111+
And I don't want one hundred kilobytes of Firebase SDK to block my app shell's initial paint time.
112+
113+
Putting the Firebase SDK scripts at the bottom of my app shell...
114+
115+
...allows the rest of the shell to render before the SDK scripts block the page.
116+
117+
The tricky part of this process is that my app requires Firebase to boot...
118+
119+
...so my app code needs to load just after the Firebase scripts are done loading.
120+
121+
This method has some benefits and one, big cost.
122+
123+
The cost is that my app will not be interactive until Firebase is fully loaded.
124+
125+
This hurts my time-to-interactive performance on the initial page load.
126+
127+
I really didn't want to sacrifice my initial time-to-interactive... but it had to happen.
128+
129+
See, the benefits outweigh this cost, at least in my case...
130+
131+
...and that's because I don't want to suffer through the misery of making my app asynchronous.
132+
133+
It's possible to only block the parts of the app that rely on Firebase...
134+
135+
...but that requires handling a bunch of asynchronous rending within the app itself.
136+
137+
And since Firebase is so core to app's architecture...
138+
139+
...there wouldn't be much of the app that could load before the Firebase SDK.
140+
141+
So the benefits of going all asynchronous with the Firebase loading aren't huge...
142+
143+
...and building the entire app around asynchronous Firebase loading would be quite challenging.
144+
145+
So I'm using Firebase's CDN links for the SDK...
146+
147+
...which means that the client's browser may already have the CDN files cached.
148+
149+
And I've got full Service Worker caching in place...
150+
151+
...only the very first page load is ever effected.
152+
153+
Once the client browser has the Firebase SDK files, the app will load almost instantly.
154+
155+
So it's not perfect, but shipping code is all about making smart compromises...
156+
157+
...which means accepting that you can't have all of the nice things at once.
158+
159+
You can find my Firebase SSR Starter code on GitHub.
160+
161+
You're welcome to copy it, but I'd recommend using it as a reference instead.
162+
163+
I used to use other people's app starters for every project.
164+
165+
It's a great feeling to jump right into building my app-specific features...
166+
167+
...but building an app starter involves so many small decisions...
168+
169+
...and you need to make those decisions yourself to truly understand how the app works.
170+
171+
So I'll probably reference this starter app a lot going forward...
172+
173+
...but I'll most likely only use it for my next app...
174+
175+
...because I'll have learned so much by the end of that app, that I'll need to start fresh.
176+
177+
So copy/paste and learn from the past, but don't value it too highly...
178+
179+
...because you always know more now than when you started your last app...
180+
181+
...and you need to be deeply familiar with your entire app if you hope to ship anything valuable.

0 commit comments

Comments
 (0)