Author: Zhang Weidong (Netease cloud music large front-end team)
0.33 History
In March 2017, in order to solve the problem of mall performance and user experience, the cloud music technical team formed a 4-person ReactNative development team: I am responsible for RN front-end development, and Android and iOS developers are responsible for embedding RN Native in the cloud music app. SDK, and a Java developer is responsible for deploying the platform.
After the mall's RN application was launched, other teams expressed interest in trying, but at that time RN project development did not have scaffolding. The project was created through original copies, lacking forweb support, and RN preloading was only connected to the iOS side.
Various reasons have led to the low efficiency of RN development. The musician business was originally interested in using RN to develop new applications. Half of the development was changed to H5.
From March 2017 to September 19, the RN version was always 0.33, the core development team lost half of the staff, the deployment platform was unmaintained, the project development lacked scaffolding, lacked forweb support, and a total of 2.5 RN applications were launched (Mall, Music People, ternary speakers).
Stir history
Time is rolling forward and new technologies emerge in endlessly. Two and a half years is like a world away for front-end development. If nothing happens, RN technology will lie in the dust of history and no one cares about it. This awkward situation was not broken until the member cash register arrival rate optimization project.
The member cash register page is the following picture, which is the cloud music member purchase page, and its importance is self-evident. This page was originally an H5 page developed by React server-side rendering.
In order to allow users to purchase members more smoothly and improve user experience and arrival rate, the entire technical team adopted web general optimization technology combined with Cloud Music’s own technical facilities, and spent a month optimizing this H5 page, increasing the arrival rate from 72% to 89%, an increase of 17 percentage points. The comparison with competing products is as follows (in seconds).
Arrival rate calculation formula = visible point of cash register / client click point
Although the optimization results are gratifying, there are several problems:
- The arrival rate target has not been completed. At the beginning, the technical team had set at least 90% or more, which was one percentage point behind.
- The ROI is too bad. H5 optimization has invested a lot of manpower in front-end and back-end development, which took nearly a month. If you go to optimize other pages, the current solution has a low degree of automation and still requires a lot of manual operations.
- The 0.33 RN arrival rate was 93%. We counted the arrival rate of the RN version of the mall, without any optimization, easily breaking 90.
There are 3 ways in front of the team at this time:
- Put more resources into optimization on the H5 page, and exceed 90% to complete the task. However, this solution consumes a lot of manpower and material resources and is not very useful for optimizing other pages. It is a one-shot deal.
- Reset the cash register page on RN 0.33 version. Although this can achieve the goal, the RN infrastructure is still stuck 3 years ago.
- Complete the RN infrastructure, upgrade to the latest version 0.6, implement a three-terminal solution, and build a complete RN development system. On this basis, the cash register was reset based on version 0.6, and the entire RN technology stack was updated with this project. Although this scheme has great benefits, it has a long time span, great difficulty, and high complexity.
After intense discussions and painful choices, the team decided to launch an impact on a higher goal. They were not satisfied with only achieving the goal of reaching rate. Instead, they wanted to rebuild the entire RN technology system to pave the way for future development and solve the performance and performance of the entire front-end development once and for all. Experience problems.
Automatic deployment
Old deployment platform
The original RN deployment platform did not implement automatic deployment. To publish an RN application, you need to do the following
Execute compatibility script
In order to support lower versions such as iOS8, you need to manually modify the relevant source code in the local node_modules.
sed -i -e 's/function normalizePrefix(moduleName: string)/const normalizePrefix = function(moduleName: string)/g' ./node_modules/react-native/Libraries/BatchedBridge/BatchedBridgedModules/NativeModules.js
sed -i -e 's/function normalizePrefix(moduleName: string)/const normalizePrefix = function(moduleName: string)/g' ./node_modules/react-native/Libraries/Utilities/UIManager.js
sed -i -e 's/function handleError(e, isFatal)/var handleError = function(e, isFatal)/g' ./node_modules/react-native/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js
Execute packaging script
Local execution release.test.sh
(test) and release.sh
(online). The release script calls the iOS and Android packaging scripts respectively, and then prints the corresponding bundle.
Because both ends of the bundle use the same name, it is easy to be mistransmitted, and every time you upload it, you must be careful.
Upload publishing platform
Here you need to fill in the relevant content, and then click Publish.
It can be seen that the above three steps have local pollution risks, the operation is cumbersome, and it is easy to miss steps and fill in errors.
Automatic deployment process
In response to the above manual deployment defects, we reorganized and designed the entire automatic deployment process
git 克隆 -> 依赖安装 -> 自动脚本执行 -> 压缩 -> 上传文件服务器 -> 保存版本信息 -> 发布
Then replaced Java with Node to develop a new RN deployment platform
The new RN deployment platform will automatically handle compatibility, packaging, uploading, and publishing. It supports multiple environments and completes the entire process with one-click deployment.
Double-ended preload
RN loading process
- The APP starts the RN container first, and the RN container requests JSBundle from the server, and then performs preliminary rendering.
- After the RN page is initialized, send a request to the server for dynamic data, and complete the remaining rendering logic
It can be seen from the figure above that JSBundle requests are the performance bottleneck in the entire process.
If you advance the loading of JSBundle (triggered when the App is initialized), and then open the RN application, the App will load the resource package directly from the local, which greatly improves the user experience and performance.
RN offline package platform
Based on the above reasons, we designed the RN offline package service platform to be responsible for the distribution of JSBundle. Offline package service is closely related to build and deployment. We connect the two platforms and automatically generate offline packages during the build and deployment stage to reduce the deployment work of developers.
The following is the entire flow chart of RN automatic deployment platform and offline package service platform
The main process is as follows:
- The RN automatic deployment platform first constructs a full package, transmits it to the CDN, and then informs the offline package service platform
- The offline package service platform receives the full package information, uses the diff algorithm to calculate the difference package, stores related information, and publishes the difference package.
- When the APP starts, it accesses the offline package service, and reads the local cache or remotely fetches the corresponding full package or differential package according to the returned information.
0.33 upgrade 0.6
The upgrade work is mainly divided into two parts: RN Native SDK upgrade + RN application upgrade.
RN Native SDK refers to the RN related native code (iOS and Android source code) integrated in the Cloud Music App. Since version 0.33 and version 0.6 are not compatible at the same time, we have adopted a strategy of only maintaining and not upgrading the old version.
RN applications refer to business applications such as shopping malls and speakers, and can also be equivalent to JSBundle. The application upgrade must be completed before the SDK upgrade, otherwise the 0.6 SDK will load the 0.3 application, causing the App to crash. Therefore, all applications must be upgraded at the same time
Upgrade facing problems
Dependency problem
RN 0.3 uses React 15.3 version, 0.6 uses 16.8. In addition to rely React, there are other dependencies need to upgrade, we according to the official version were compared created a scaffold, read package.json inside information, one by one than the right, and then modify the corresponding version.
Obsolete components
The RN0.6 version removed 2 components: Listview
and navigator-ios
.
In this case, if we use the new components such as FlatList
rewrite, not only need to understand the original business logic, but also to modify the source code and re-test. Therefore, in response to this situation, the team took measures: do not change the existing code, extract the corresponding components from the old version.
Finally, we released @music/rn-deprecated-navigator-ios
and@music/rn-deprecated-listview
Syntax compatible
The RN grammar is not only written differently between 0.6 and 0.33, but is also not backward compatible. The result is that JSBundle of 0.33 will crash directly when running on RN Native SDK of 0.6. The following is an example of the background image.
In 0.33, in order to realize the background image, it was used to Image
include one View
, but it was changed in 0.6 ImageBackground
, and the attributes are also different.
In addition to the grammar of the background image that needs to be modified, we don't know how much grammar needs to be compatible. In the face of this situation where the scope is not clear and the change time is very tight, if manual methods are used, it is not only inefficient and the progress is also controllable. Therefore, we adopted an automated processing method and launched the industry's first RN codemod framework mrn-codemod
The main process is as follows:
- Use the framework to read the 0.33 source code first
- Convert 0.33 source code to AST tree.
- Perform corresponding operations on the 0.33 AST tree and transform it into a 0.6 AST tree.
- Regenerate the source code of the 0.6 AST tree.
The whole framework handles a total of 12 translation rules
After the completion of this framework, all RN application upgrades were completed within one day, which not only ensured accuracy, reduced labor costs and time, but also provided expansion for future upgrades.
3-terminal solution
After the above upgrades were completed, the team began to invest in the research of the 3-terminal solution. After the investigation, there were three main methods: direct conversion, bridge mode, and bottom construction.
Direct conversion
Because RN and React are only different in grammar at the rendering level, if RN's grammar can be directly translated into React grammar, then RN can be run on the browser.
For example, the RN will View
turn React's div
, RN's click event onPress
into the React onClick
and so on.
The disadvantages of this scheme are:
- over work load. RN inside
View
,Text
,Image
basic components very much. - There is no one-to-one correspondence. For example,
View
there is aonStartShouldSetResponder
method, and no corresponding event can be found in React.
Bridge mode
For RN applications, first find a three-party framework that supports forweb, and then convert the RN DSL to a third-party framework DSL to achieve the final goal.
The representative ones in this regard are Taro and ReactXP .
According to the RN specification, Taro has implemented a set of DSL and customized functions and events.
ReactXP's three-terminal support is very good, but there are very few components, so I had to give up.
Underlying construction
According to the definition of RN elements and components, the whole set of RN API is realized by WEB-related features from the bottom. This is react-native-web . This solution is also the mainstream model in the industry.
We encapsulated and extended this library, added unsupported components, fixed some bugs, and formed it @music/react-native-web-suffix
.
New development process
Based on the three-terminal solution, we developed rn-cli
scaffolding, rn-util
common tool libraries, rn-template
project initialization templates and other supporting tools, forming a complete set of RN development infrastructure. The current new development process is as follows
rn-cli
Called when the scaffolding is initializedrn-template
.rn-template
Built-in android, ios and web development containers and some common engineering configurations, a collection ofrn-util
(processing request, environment judgment, general protocol) and three-terminal component library.
Reconstruction result of cash register RN
After the above efforts, the cashier has been refactored on the RN 0.6 version, and the arrival rate has increased from 89% to 99% in the previous H5 (optimized).
status quo
With the improvement of RN version and perfect infrastructure, more and more big front-end developers adopt RN technology stack in new projects.
More than 10 RN applications have been launched, such as:
future plan
At present, RN technology has become the key development direction of the big front end, and there is a special person to take charge of this matter. The follow-up specific planning is carried out around the three major directions of performance , efficiency , and monitoring , with the goal of becoming the industry's first echelon in this area.
Several special projects are currently in progress
Native RPC
The main purpose of this project is to get through the RN bridge and JS bridge, allowing a set of data communication mechanisms to support both RN and web.
The previous bridge had two main problems:
- Inconsistent usage. Need to write 2 sets of grammar to support RN and web respectively.
- Support is inconsistent. Some protocols do not have RN for web, and vice versa.
Therefore, in response to the above situation, the big front end unified the APIs at both ends and refactored the underlying protocol to support the above functions. Here is an example.
// 查看 net.nefetch 是否支持,
mnb.checkSupport({
module: 'net',
method: 'nefetch'
}).then(res => {
})
/* 手动添加方法 */
mnb.addMethod({
schema: 'page.info',
name: 'getPageInfo'
});
/* 添加之后即可调用 */
mnb.getPageInfo().then((result) => {
// ...
}).catch((e) => {
// ...
});
Both ends of RN and web are written uniformly, so developers no longer have to worry about compatibility issues.
RN unpacking
The RN application performs well on most mainstream models, but there is a stuttering phenomenon on some low-end Android devices. In order to solve this problem, start the unpacking special project, which is mainly divided into two parts.
- Unpacking. Disassemble the current complete JSBundle into a basic package and a business package, and load them separately.
- The container is preloaded. The RN container is preheated when the App starts, which can greatly reduce the container startup time and increase the loading speed.
other
In addition to the above-mentioned special projects, there are many special projects such as RN market monitoring, RN resource package targeted distribution, and document specification are in full swing.
Concluding remarks
At this point, are you curious about the real experience of RN in the Cloud Music App? If you are interested, please upgrade the Cloud Music App version to the latest for experience.
The team of NetEase technology lovers continues to recruit teammates! We have been hiring people, if you happen to be ready to change jobs and you happen to like Cloud Music, then send your resume to [email protected]! Join us!