Mobile Development 20 min read

How NetEase Cloud Music Overcame RN 0.60→0.70 Upgrade Challenges

This article details the end‑to‑end technical journey of upgrading NetEase Cloud Music's React Native apps from version 0.60 to 0.70, covering research, break‑change analysis, dependency management, dual‑bundle strategies, automation scripts, and the hidden pitfalls encountered along the way.

NetEase Cloud Music Tech Team
NetEase Cloud Music Tech Team
NetEase Cloud Music Tech Team
How NetEase Cloud Music Overcame RN 0.60→0.70 Upgrade Challenges

The upgrade of NetEase Cloud Music's React Native (RN) applications from 0.60 to 0.70 was divided into four stages—research, solution design, implementation, and split‑traffic verification—with the front‑end team deeply involved in the first three.

Research Phase

Using the react-native upgrade tool, the team listed all direct dependencies (babel, react, etc.) and manually inspected third‑party and internal components. They collected changelogs and commit histories to enumerate every break change, prioritising those that impacted the API surface.

Break‑Change Handling Strategies

Apply patch-package to patch npm packages without modifying source. Example steps:

diff --git a/node_modules/react-native/index.js b/node_modules/react-native/index.js
index d59ba34..1bc8c9d 100644
--- a/node_modules/react-native/index.js
+++ b/node_modules/react-native/index.js
@@ -435,32 +435,16 @@ module.exports = {
 },
 // Deprecated Prop Types
 get ViewPropTypes(): $FlowFixMe {
-    invariant(
-      false,
-      'ViewPropTypes has been removed from React Native. Migrate to '
-        + "ViewPropTypes exported from 'deprecated-react-native-prop-types'.",
-    );
+    return require('deprecated-react-native-prop-types').ViewPropTypes;
 },
};
...

Create the patch file with patch-package documentation.

Add deprecated-react-native-prop-types as a project dependency.

Insert an npm hook in package.json: "postinstall": "npx patch-package" For API‑level break changes, the team used conditional checks (compatibility code) such as:

if (this.scrollView.getNode) {
    this.scrollView.getNode().scrollTo(...);
} else {
    this.scrollView.scrollTo(...);
}

When a single component could not be made compatible across versions, they introduced "capability sinking" by wrapping the original component in two versions—one for 0.60 and one for 0.70—while exposing a unified API.

Dependency Upgrade

Dependencies were grouped into three categories:

Official RN packages (react‑native, metro, etc.).

Common community packages used by Cloud Music (react‑navigation, react‑native‑svg, etc.).

Internal packages (e.g., @music/mnb-rn, utils, business modules).

Over 60 packages required updates. The guiding principle was to keep changes at the lowest possible layer, preserving API stability for business code.

Community Dependency Strategy

Large API changes (e.g., react‑navigation 4.x → 7.x) were avoided; the team kept the 4.x version and privatized it for the 0.70 build.

Minor API changes without 0.70 support were upgraded and privatized (e.g., react-native-gesture-handler).

Some packages required no changes (e.g., react-native-screens).

Internal Dependency Strategy

Internal upgrades focused on adapting break changes and aligning version declarations. Peer dependencies were set to * to let the container dictate the RN version, avoiding duplicate bundles.

{
  "dependencies": {
    "react-native": "0.60",
    "react-native-gesture-handler": "^1.3.0"
    ...
  },
  "devDependencies": {
    "react-native": "*",
    "react-native-gesture-handler": "*"
    ...
  }
}

Solution Design

Two main approaches were evaluated:

Branch per RN version (maintain separate 0.70 branch). This conflicted with existing infrastructure (deployment, data platforms).

Single codebase producing two bundles (0.60 and 0.70). This required careful handling of version‑specific dependencies and resulted in a custom packaging workflow.

The final workflow included:

Dependency elevation: install the bundling tool globally on the build machine to ensure clean removal between builds.

Adding a degrade field in package.json to lock versions for the 0.60 build.

{
  "degrade": {
    "devDependencies": {
      "@babel/core": "^7.5.5"
    },
    "dependencies": {
      "react-native": "0.60.5"
    }
  }
}

Using babel-plugin-module-resolver alias to map privateized packages for the 0.70 build and removing the alias for the 0.60 build.

Automation Script

A Node.js script distributed via npm and executed with npx automates most upgrade steps—generating patches, updating package.json, adjusting Babel config, and running resolutions. The script has been iterated over 110 times to stay current with RN changes.

Hidden Pitfalls

Metro's removal of JSON from default asset types broke a pre‑load mechanism that relied on bundled JSON files.

Hermes engine no longer supports Date.parse and named capture groups in regular expressions, requiring custom polyfills.

Bytecode bundles produced large patch files when using bsdiff. Adding the flag --base-bytecode previous.hbc during incremental compilation reduced patch size.

Inconsistent dependency versions across the 100+ RN apps caused lock‑file conflicts, missing modules (e.g., @babel/runtime/helpers/regeneratorruntime), and runtime errors such as duplicate native component registration.

Conclusion

The RN upgrade demonstrated that thorough research and a flexible dual‑bundle strategy are essential when many applications must migrate simultaneously without downtime. Continuous collaboration across business lines and rapid iteration of automation scripts were key to overcoming the numerous break changes and dependency mismatches.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

dependency managementReact Nativepatch-packageBreak Changesdual bundleRN upgrade
NetEase Cloud Music Tech Team
Written by

NetEase Cloud Music Tech Team

Official account of NetEase Cloud Music Tech Team

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.