-
Notifications
You must be signed in to change notification settings - Fork 52
The learnings from the app-shell and page-shell structure #1
Description
Hi,
We have experimented with app-shell and are using page-shell currently (with a slight modification - loading the whole view in advance).
App Shell
It gave us better time to first paint but the time to first meaningful paint was delayed. Here's what we found in our experiment.
As a user you get a faster first paint but the time to first meaningful content is what we are looking to optimize so we tried to fix that.
Solution
We got rid of app shell and implemented SSR with HTML streaming in combination with preload
. And the result was :
This way we were able to improve the time to first meaningful paint which made more sense than just improving the time to first paint.
Page Shell
Since we had implemented SSR and the idea of page-shell is same as that of app-shell, we used the idea rather than the implementation.
Case 1: Implement page-shell -> First meaningful paint still suffers. 2 JS files to load and when you navigate from another URL, loading multiple files (we also have separate CSS to prevent FOUC) didn't seem to be a good idea.
Case 2: Implement SSR -> Let the view have 2 files (JS and CSS). When the user lands directly on the page you don't need any shell due to SSR. When you are on a different page and the next intent of the user is to come on that page, load the view of current page in the idle time of previous page.
Implementing these we were able to solve for :
- too many files
- better time to first meaningful paint
- faster route navigation
All of these were more about the implementation rather than webpack bundling.
webpack was mainly optimized to implement long term caching, manifest and chunking.
Intent based chunks
We implement route based chunks but we often ignore this. This is one important implementation that can reduce the size of a view bundle. There are certain parts of a view that are not always needed like a modal or anything that doesn't show up everytime. That can be made into a different chunk and loaded on demand. For example:
The size in the above image is non-gzipped (around 9KB gzipped).
We are using 2 types of intent based chunks which are loaded in idle time or as per need.
Type 1 :
Those which have a chance of being visible but not immediately. They are loaded in idle time like some frequently visited modals. (driven by analytics)
Type 2:
Those which have less chance of being visible or once in many sessions. Load when actually required. Most of the times its not needed. (as per our analytics data)
We have to take care of bandwidth consumption of the user. Loading lot of chunks in idle time also may not be a good idea for people with slow internet connection.
I hope these are useful for developers who are trying to make a PWA.
So in both cases out time to first paint was around 2.2-2.3s so it was better that we implement the 2nd solution.
Its not always necessary that these will work for you so experiment and then implement.
Edit : Added clarity about intent based chunks.