RN拆包工具

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

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做相应的修改,具体内容请参考:

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


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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容