reactnative engineering construction

background

After mastering the front-end foundations such as js, css, html, react, etc., you can learn more about what other points need to be considered in the process of using reactNative from demo to production environment.

architecture

Let's take a look at it from the top down. First of all, our project needs to have the ability to be used in both the app and the browser, so that it can truly span the three terminals.

We need to do parallel expansion based on react, so that in the future, whether it is the way of webview embedding h5 or the native way of the applet, there is room for imagination and optimization.

那么问题来了,如何做到h5和app内通用呢?

Here we need to analyze the similarities and differences between the two containers:

native ability

The react native in the app communicates through the nativeModule; while hybrid, h5, and applets are all other implementations, such as jsbridge, back-end interface, applet API, and so on.

For this point, we solve it through the adapter mode.

适配器:使接口不兼容的对象能够相互合作。

Adapter case demo:

// axios能同时用于浏览器和node端的原理
// 区分node和浏览器环境的适配器
// 适配器模式的运用
function getDefaultAdapter() {
    
    
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    
    
    // For browsers use XHR adapter
    adapter = require('./adapters/xhr');
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    
    
    // For node use HTTP adapter
    adapter = require('./adapters/http');
  }
  return adapter;
}

We save references through a simple module:


let bridge = null;

export const setBridge = bge => {
    
    
  bridge = bge;
};

export {
    
    bridge};

Then insert different bridges in different entry files (h5 and app entry files are distinguished):

// react native 入口
const {
    
    YktNativeModule} = NativeModules;
bridge.init({
    
    bridge: YktNativeModule});
setBridge(bridge);

// h5入口
bridge.init({
    
    yktlog: window.YktTracker});
setBridge(bridge);

engine

首先提个问题,reactNative在app内是跑在什么引擎上的?

The most standard answers are javascriptCore, V8, Hermes.
Traditional applications use javascriptCore in the production environment and v8 in the chrome development environment:

The new version uses Hermes:

The performance of Hermes on various models:

Chat Widget

As for what optimizations Hermes has made and how the effect is improved after the production environment is used, you can refer to the headline article ReactNative Practice and Exploration in Game Marketing Scenarios - Hermes Engine - Nuggets

Here we only look at two points, one is that hermes can run bytecode directly; the other is the greatly reduced memory usage and startup time.

It can be seen that after enabling hermes and providing bytecode, TTI (interactive time is reduced by about half):

Pack

As mentioned earlier, rn provides bytecodes to the hermes engine in the app, and js in h5.

Then think about a question:

怎么提供字节码?

The official compiler is provided:

  // 生成jsbundle
  spawn.sync(
    'npx',
    [
      'react-native',
      'bundle',
      '--platform',
      platform,
      '--dev',
      'false',
      '--entry-file',
      'index.js',
      '--bundle-output',
      `dist/${
      
      platform}/${
      
      appName}.${
      
      platform}.bundle`,
      '--assets-dest',
      `dist/${
      
      platform}/`,
      '--config',
      'metro.business.config.js',
    ],
    {
    
    
      stdio: 'inherit',
    },
  );
  //生成hbc字节码
  spawn.sync(
    `./node_modules/hermes-engine/${
      
      
      os.platform() === 'darwin' ? 'osx-bin' : 'win64-bin'
    }/hermesc`,
    [
      '-emit-binary',
      '-out',
      `dist/${
      
      platform}/${
      
      appName}.${
      
      platform}.bundle.hbc`,
      `dist/${
      
      platform}/${
      
      appName}.${
      
      platform}.bundle`,
    ],
    {
    
    
      stdio: 'inherit',
    },
  );

How to check what the js code you wrote looks like into bytecode, you can refer to Hermes | Hermes

Think again:

除了生成字节码,还有没有其他可以优化的空间呢?

The answer is unpacking:

The picture in the upper left corner is the overall idea. You can see the previous status quo on the left, that is, each rn business module relies on some common codes, such as react and react-native. We want to extract these common codes , so that each business package does not contain a lot of repetitive code, which affects the size of the app. At the same time, the client can also preload the logic of the public package, thereby reducing the white screen time.

metro是Facebook出品的react native专用打包工具

The whole process is divided into 3 steps.

The first step is to find which js files the public package depends on. Here we get the path of each js module participating in the package through the API of metro in the stage of createModuleFactory packaged by the public package, and then generate a unique id through the md5 file path.

The second step is to save the dependency list in the file. For details, please see the picture in the upper right corner, mainly the file path and the corresponding module id.

The third step is to exclude these modules from the packaging process based on the files generated in the second step through the API of metro in the processModuleFilter stage when the business package is packaged, so as to obtain the pure business package content.

In this way, even if the content of the public package increases in the future, the dependency list can be automatically calculated and deduplicated through the unique id.

Let's take a look at the reduction of bundle size by unpacking:

After the unpacking is complete, one last question:

如何让reactnative的代码,可以在浏览器中使用呢?

This needs to start with React's architecture.

The React16 architecture can be divided into three layers:

Scheduler (scheduler) - there is only one core responsibility, which is to execute callbacks

Wrap the callback function provided by react-reconciler into a task object. Maintain a task queue internally, and the one with the highest priority is at the top. Consume the task queue in a loop until the queue is emptied.

Reconciler (coordinator) - the component responsible for finding out changes, version 16 is mainly Fiber, and version 15 is stack. The difference is that the priority system is added, and interruptible recursion is realized by traversal. The construction process of the fiber tree is wrapped in a callback function, and this callback function is passed to the scheduler package to wait for scheduling.

Renderer (renderer) - responsible for rendering the changed components to the page, can display the fiber tree constructed by the react-reconciler package, generate dom nodes (in the browser), and generate strings (ssr), such as react -dom, react-native.

So the role of react-native is mainly to render the nodes provided by react to the app page.

The react-native components we write, such as View, Text, etc., need to be transformed into react-dom-recognizable nodes through react-native-web:

Its principle is to implement all exposed APIs of the react-native library, and then cooperate with the alias of webpack to replace the alias when packaging.

  resolve: {
    
    
    alias: {
    
    
      'react-native': 'react-native-web',
    },
  },
webpack是一个js打包工具,一般浏览器端工程会用它。

After understanding the working principle of react, react-native and react-native-web, react-native-windows and react-native-mac can be obtained in the same way:

Basic ecology

A front-end project, including component library, request library, data status management, exception monitoring, etc.

Component library we use nativebase:

The advantage is that it has everything, and the disadvantage is that the library is a bit large, which is a bit of an eyesore in react-native that does not support tree-shaking, but we have the common package, so it is not a problem.

nativebase看起来大是因为基于react-native-svg,如果其他库用了这个也会很大。

requests library we use axios:

A famous titan, but more introduction, the biggest advantage is promisify, adapter (node, browser common), chain of responsibility (interceptor system)

For data state management we use redux-toolkit:

Integrates redux, redux-thunk, and immer to provide an easier-to-use API.

redux是数据状态管理工具,之前介绍过。

redux-thunk是一个redux中间件,可以用来解决action的异步问题。

immer是一个immutable的解决方案。

For exception monitoring we use Sentry:

A well-known exception monitoring platform in the industry, supporting SDKs of various languages ​​and frameworks: (js, react, react-navie, flutter, node, etc.)

Guess you like

Origin blog.csdn.net/mevicky/article/details/122366739