RN拆包工具

RN拆包工具是为了解决RN产出的bundler包文件过大问题的打包工具;可以按需将模块按照基础&业务生成两个文件。

RN拆包工具_第1张图片
rabbit

思路

基于RN官方的打包工具使用unbundle platform android已经可以拆包,不过是一个模块一个文件,文件数量过多。

#RN unbundle android 的使用 example:
react-native unbundle --platform android --dev true --entry-file index.js --bundle-output dist/metro_android_bundle.js

基础此命令进行修改,将多个单独的模块文件按照“需要”合并到一起;
尝试按照注释或者模块属性,将模块划分到base.js bussiness.js中。

分析

我们先从几个角度了解一下RN的打包工具:

unbundle android 与 unbundle ios 的区别

ios是流文件, android是生成一个基础文件,
模块文件夹js-modules,文件夹中包含以react-native为首的组件,包括业务组件

unbundle android 与 bundle android 的区别

unbundle 文件跟bundle文件开始都一摸一样,
都是定义模块化方法和bable配置,
但是在unbundle在定义模块的时候截止了,将React-native等模块的定义单独拿到了js-modules文件夹中以ID命名,一个模块一个文件,
调用了require(11); 11.js中写的是入口文件index.js _reactNative.AppRegistry.registerComponent

RN模块化

打包之后JSBundle文件的结构,基本分为3部分 头部:全局定义,主要是define,require等全局模块的定义; 中间:模块定义,RN框架和业务的各个模块定义; 尾部:引擎初始化和入口函数执行;

__d是RN自定义的define,符合CommonJS规范,__d后面的数字是模块的id,是在RN打包过程中,解析依赖关系,自增长生成的。

如果所有业务代码,都遵照一个规则:入口JS文件首先require的都是react/react-native, 则打包生成的JSBundle里面react/react-native相关的模块id都是固定的。

打包产物:Bunlde类

RN的bundle在生成文件之前是一个对象,它的定义就在:metro/src/Bundler/index.js中。让我们看下它打印出来的结构:

const bundle = {
  "groups": {},
  "startupModules": [{...},{...}], 
  "lazyModules": [
    {
      "id": 11,
      "code": "__d(function (global, _require, module, exports, _dependencyMap) {\n  var _reactNative = _require(_dependencyMap[0], \"react-native\");\n\n  var _App = _require(_dependencyMap[1], \"./App\");\n\n  var _App2 = babelHelpers.interopRequireDefault(_App);\n\n  _reactNative.AppRegistry.registerComponent('divider', function () {\n    return _App2.default;\n  });\n},11,[12,337],\"index.js\");",
      "map": {
        "version": 3,
        "file": "/Users/pengzou/workspace/exercise/rn/divider/index.js",
        "sources": [
          "/Users/pengzou/workspace/exercise/rn/divider/index.js"
        ],
        "sourcesContent": [
          "import { AppRegistry } from 'react-native';\nimport App from './App';\n\nAppRegistry.registerComponent('divider', () => App);\n"
        ],
        "names": [
          "AppRegistry",
          "registerComponent",
          "App"
        ],
        "mappings": ";AAAA;;AACA;;;;AAEAA,2BAAYC,iBAAZ,CAA8B,SAA9B,EAAyC;AAAA,WAAMC,aAAN;AAAA,GAAzC"
      },
      "name": "index.js",
      "sourcePath": "/Users/pengzou/workspace/exercise/rn/divider/index.js",
      "source": "import { AppRegistry } from 'react-native';\nimport App from './App';\n\nAppRegistry.registerComponent('divider', () => App);\n",
      "type": "module"
    },{...}]
};

其中startupModules, RN基础模块,模块化方法定义等;lazyModules是react,入口,业务等模块;
每个模块对象的重要属性:id:模块ID, code:代码,name:文件名等等;

RN的unbundle命令Android端是将startupModules模块合并到一个文件并在最后一行增加对入口的调用;将lazyModules数组中的模块单独输出到单独文件并以模块id命名保存到js-modules文件夹下。

实践

RN的官方打包工具是metro. 让我们在node_modules/metro 直接修改代码调试:

  1. 使用unbundle 将模块路径包含node_modules字符串的模块视为RN的模块,将这些模块从lazyModules移入startupModules;
  2. 将调用index.js的require(id),即原startupModules中最后一句,提取出来;
  3. 将lazyModules多个模块合并成一个文件;
  4. 将require(id)填入lazy.bundle;
  5. 将require(InitializeCore模块Id)填入lazy.bundle;
  6. 使得platform ios走Android的unbundle

遇到的问题&解决办法

metro代码库中flow文件是什么?

flow是facebook公司的代码规范,需要将flow转移js才可以正常运行。
在Babel中配置使用Flow需要创建一个配置文件.babelrc,并配置插件transform-flow-strip-types,让其它人也可能使用它:

 "presets": ["es2015"],
  "plugins": [
    "transform-flow-strip-types",
  ]
}

然后你可以告诉Babel你的输入文件夹src和输出文件夹lib:

`babel src/ -d lib`

通常,你会将lib目录添加到你的.gitignore中,因为我们不想提交我们编译过后的代码到Git上。

RN打包的核心文件

// metro unbundle
metro/src/shared/output/unbundle/index.js
// metro unbundle android
metro/src/shared/output/unbundle/as-assets.js
// rn local-cli
react-native/local-cli/bundle/unbundle.js

node调试,内容很多的对象如何打印?

//使用格式化输出对象
console.log(JSON.stringify(object,null,2));

//或使用fs写入文件中;
#首先npm上注册账号,别忘了去邮箱验证,而且126邮箱不行,qq可以。

# 不能使用镜像,切换到原始地址:
npm config set registry http://registry.npmjs.org

npm adduser
npm init
npm publish

#更新
npm version <新的版本号>
npm publish

#发布完成之后,如果还想回到之前的cnpm,使用下面的命令
npm config set registry https://registry.npm.taobao.org


此打包工具实践的方案,需要Native对RN做相应的修改,具体内容请参考:

  • RN拆包
  • react-native bundle 解释与拆解

本文的主旨是介绍拆包工具的拆包思想,而是希望将这个思路讲清楚帮助读者优化react-native项目。


2018.9.5更新:由于rabbit工具已经改造并应用于作者公司内部,所以github已经删除,并且在npm上将其废弃,文章内相关信息已经删除,保留拆包的思路。

你可能感兴趣的:(RN拆包工具)