Original link: https://blog.mayandev.top/2022/09/03/tech/pwa/
The construction of an operation platform that our team is responsible for, with the continuous iteration of the project, the increase of various requirements and functions, there are currently more than hundreds of sub-modules, the problem of slow site loading is gradually emerging, and the relevant indicators tend to deteriorate. The research found that there are two main reasons:
-
Page initialization relies on many interfaces, including permissions, regions, project configuration and other related interfaces, and due to historical reasons, these interfaces have a slow response speed and high renovation costs.
-
The loading link based on the micro-frontend + SPA application architecture is long. After the main application is loaded, it needs to request the network to load the pages and resources of the sub-application, resulting in a long white screen time for the sub-application. The figure below shows the original loading link of the current site.
In order to speed up page loading and reduce the slow request rate of resources and interfaces, PWA offline caching technology is used to cache relevant pages, resources and requests offline, and improve the loading interaction, which improves the overall use of the site. experience, and help operation students improve work efficiency.
Technical solution selection
First consider the following three questions:
- Why choose to use PWA?
- Why do you need to do offline caching with HTTP caching?
- Are B-end products suitable for access?
In fact, PWA (Progressive web application) technology is not a novel concept. It has been widely used in recent years, so the technology is relatively mature. By operating the Service Worker API provided by the browser, interface data and static resources can be cached offline, which greatly reduces the request processing speed, shortens the loading time of the first screen, and achieves an experience close to that of native applications. Features like push notifications, notification features and add to home screen features are also widely supported. More importantly, we can implement the core features of PWA at a relatively small cost, and the benefits are very considerable.
For applications using PWA technology, as shown in the figure below, the browser will follow the priority order of ServiceWorker Cache > Disk Cache when requesting resources, and the loading speeds of these two caches are Disk Cache > ServiceWorker Cache respectively. In addition, some modern browsers also have Memory Cache, which has better priority and loading speed than Service Cache and Disk Cache.
.png)
Image credit: Web.Dev
So most of the resources of the site have been HTTP cached before, why do you need to do offline caching? (PS: Only children make choices, adults need them all.) In fact, the two are not in conflict. After investigation, it was found that the difference in the cache acquisition time between the two is milliseconds, which is almost negligible. In the case of a large number of concurrent requests In some cases, Service Worker Cache is faster than Disk Cache . We can also get the fastest resources through resource racing. The most important thing is that the most significant benefit that offline caching brings to us is to optimize the problem that the loading link of micro frontend + SPA is too long, and to initialize page requests and main sub-applications through more fine-grained and controllable caching App-shell and resources to speed up page loading and reduce white screen time.
In addition, as a B-end product, our user group is single and fixed, but the page access frequency is relatively high. The caching strategy requested by the Service Worker interface is very suitable for our interface optimization. At the same time, the transformation cost of PWA is relatively small, which brings us considerable benefits. In addition to cache optimization, we can also use the notification push provided by PWA and add the function of the home screen to further improve the user experience. This is why we choose PWA one of the main reasons.
Plugin comparison
The construction tool of our site is the internal tool of byte, which provides a matching pwa plug-in. Here is a comparison with the webpack plug-in provided by Google.
Internal plugin | workbox-webpack-plugin | |
---|---|---|
introduce | Encapsulation of the workbox-webpack-plugin plugin | Tool library that provides a series of APIs for Service Work operations |
deploy | Integrate the ability to deploy, without having to configure the route of deployment separately | Need to add a sw.js route |
configure | The configuration is simple, but there are too few configuration items, which can only cover a small part of the scene, suitable for small applications | The configuration is a bit complicated, and there are many handwritten things, but it can cover most scenes. |
Bale | The service-worker.js file is automatically generated, and the html is automatically injected into the script registered by the Service Worker | The service-worker.js file is automatically generated, and service worker registration requires handwriting, so you can customize the downgrade scheme |
According to the above comparison, it is found that the custom configuration items of workbox-webpack-plugin are richer, which can cover the scenarios required by this transformation, and can customize the downgrade scheme. Therefore, the workbox-webpack-plugin plug-in is selected for the configuration of PWA.
Service Worker Offline Cache
When the page is first loaded, the Service Worker is in an inactive state and cannot intercept page requests for caching. Only in the activated state will the page request be taken over. That is to say, the first time the page is opened, all resources will still be requested. After installing the service worker, the page needs to be refreshed to have the effect of caching.
caching strategy
Cache First | Network First | StaleWhileRevalidate |
---|---|---|
Prioritize the use of the cache, there is no request network in the cache | Prioritize network requests, and use cache for network exceptions | Priority is given to the use of the cache, if the cache does not exist, the network is used; if the cache exists, the cache is used first, and the network resources are requested to update the cache in the background |
.jpg) Image credit: Google Developers | -20220828114924137.(null)) | -20220828114930732.(null)) |
Precache vs Runtime Cache
The cache in Service Worker is divided into Precache and Runtime Cache.
Precache is pre-cache, which generates a pre-cache list called workbox-precaching during the build phase, keeps the build product up-to-date, and uses the cache-first strategy to set up routes to provide pre-cached URLs. As soon as the page is opened, it will request and cache the resources in the list in the background, instead of waiting for the browser to take over the corresponding request before caching.
Runtime Cache is run-time pre-cache, that is, during the use of the page, as long as the set routing rule is hit, a record will be recorded in the Service Worker.
Generally speaking, when the page is opened for the first time, Precache resources are cached in the background, and can be used after the second refresh. If it is the cache of Runtime, it generally needs to wait until the third refresh before it can be used.
Service Worker Update Policy
By default, when a new Service Worker is detected, it will go through two stages:
-
The intall event is triggered again, but if the page is not closed, the page is still hosted by the old service worker, and the new service worker is in the waiting state.
-
When the user completely closes the page (all tabs of the browser do not open the site) and opens the page again, the activate event will be triggered. At this point the new Service Worker takes over the page and the new cache starts to take effect.
Considering that users have the habit of opening multiple tabs, this solution cannot simply refresh the page to see the latest effect, and needs to close all related tabs, which is not very friendly to the user’s mind.
Another way is to refresh directly through the skipWaiting
method, but this may cause cache conflicts. Because registering a Service Worker is an asynchronous process, there may be a risk of problems when the same page passes through two Service Workers before and after. For example, after a new function is launched, the user refreshes the page, and some resources go to the old cache. After the new Service Worker is registered, if there is an asynchronous request in the old cache, the cache and online cannot be hit, resulting in resource request failure.
Default way | skipWaiting |
---|---|
All tabs need to be closed for the new cache to take effect | Refresh the current page, the cache will take effect immediately |
Advantages: Safest, no risk Disadvantages: Not very user friendly | Advantages: Unperceived by users Disadvantages: Potential problems that may cause asynchronous resource requests to fail |
By comparing the plans, it can be seen that both methods are inappropriate. Technology is not omnipotent, and there are shortcomings that need to be combined with product logic to make up. We use the update method of postMessage + skipWaiting, the page listens to the message
event, and refreshes the page in the callback. The specific manifestation is that when the page detects that a new Service Worker is registered, a prompt box will pop up on the page, prompting the user to refresh the page. When the user clicks the Load New button, a notification is sent through the postMessage API, and all pages are refreshed and the latest cache is obtained.
-20220828115029882.(null))
resource cache
Build packaged resources
The compiled product adopts the CacheFirst scheme for pre-storage (preCache), and the cache status is updated according to the file hash or file revision identifier each time it is updated.
The workbox-webpack-plugin will recognize a special variable __WB_MANIFEST
, which will be replaced by the manifest array in the build result. With each package build, the generated files are updated, which in turn triggers service worker updates.
1 |
// self.__WB_MANIFEST refers to the file list of the build |
1 |
// generate sw.js config |
Three-party static resources
-
Fonts, pictures, icons
-
SDK, the site includes monitoring, management, Oncall customer service SDK, etc.
For font files, images, and third-party SDKs with version numbers, the Cache First strategy is adopted, and the cache time is set for 30 days. For other static resources (excluding build products), such as external styles and sdk without version number, use the StaleWhileRevalidate strategy. While hitting the cache, the background requests the latest resources and updates them to ensure the real-time nature of resources.
1 |
const staleWhileRevalidate = ( cacheName, maxEntries ) => new StaleWhileRevalidate() |
ask
Page initialization depends on many interfaces, and these requests can be cached to speed up initialization. For example, xxx/xxxx/appInfo
, this interface returns some project configuration information, such as permissions, Oncall and so on. According to monitoring, the proportion of this request exceeding 1s reaches 15%, and it will block page rendering. At present, the response data of this kind of request will not be updated for a long time, so choose to use StaleWhileRevalidate to cache it.
1 |
const requests = [ |
App-shell
The site uses the micro-frontend architecture, and it takes a certain amount of time to load each sub-application. Therefore, the App-shell that caches the main and sub-applications is selected to reduce the network request time of the main and sub-applications and speed up the entire loading link.
page link | describe |
---|---|
https://xxxx/index | Main application index.html |
https://xxxx/subappA | Sub-app A index.html |
https://xxxx/subappB | Sub-app B index.html |
https://xxxx/subappC | Subapplication C index.html |
1 |
const registerNavigatorCache = () => { |
The final cache structure of Service Worker is as follows:
1 |
- asset- static // image, font |
In addition, we also used the open-screen connection logo to wait for the main application to be loaded to further enhance the sense of use. In order to prevent the strobe caused by the fast loading of the main application, a minimum logo delay display is set, and it is performed concurrently with the main application loading.
1 |
|
Service Worker Registration
sw.js
registered in the load event of the page, and record the registration.
1 |
<script> |
Update detection
We encapsulate a native update detection popup component, which listens to service worker life cycle events (including updatefound, controllerchange, statechange) and message
events, and refreshes the cache based on user interaction.
Service Worker update detection listener
1 |
// sw.js |
Downgrade plan and grayscale release
In order to avoid some problems in the cache, causing the page to fail to load or a white screen, it is necessary to provide a service worker logout solution. Add a key to the dynamic configuration center as a switch, request configuration when the page is loaded, and choose to register and update Service Worker or log out of all Service Workers according to the configuration. In addition, the configuration also includes gray-scale areas. Only when the corresponding gray-scale area is selected will the Service Worker be registered.
1 |
// tcc api |
benefits and feedback
Through the transformation of the PWA, the overall FCP, Load and slow request rate indicators of the site have been significantly improved, reaching the expected values.
FCP | Load | Main Resource Slow Request Rate | |
---|---|---|---|
Before | 2115.38ms | 2.42s | 11.29% |
After | 1388.06ms | 1.16 | 5.37% |
Percent | ?52% | ?240% | ?52.4% |
However, indicators such as LCP and TTI are still relatively high, and further optimization will be made at the code logic level and packaging level in the future to improve the interactive experience.
-
From the level of code logic, optimize page rendering, image loading, reducing long tasks, etc.
-
Packaging level, reasonable unpacking, removal of unnecessary packages, etc.
In addition, after the function was launched, we also received some positive feedback from PM, RD and related users, which is a great encouragement for us. We will also continue to pay attention to performance optimization and continue to improve.
Finally, an advertisement is inserted. The TikTok Creator Growth team is still recruiting front-end and back-end engineers. Both school and social recruitment are available. Interested students can add WeChat to chat ?.
This article is reproduced from: https://blog.mayandev.top/2022/09/03/tech/pwa/
This site is for inclusion only, and the copyright belongs to the original author.