React-Native学习笔记之第一个RN项目

一、搭建环境及运行第一个项目

1.按照安装教程中使用Homebrew一步一步的安装RN的开发环境及运行环境。
2.按照教程创建第一个RN项目

Snip20170822_1.png

3.使用命令行运行react-native run-ios
4.加载资源.....等了很久,无任何报错。。。一脸懵逼。
5.使用Xcode打开iOS文件夹下的工程文件。
6.报错信息如下:
Snip20170822_7.png

React/RCTbundleURLProvider.h not found未找到文件。
7.检查RN版本 react-native --version 0.47.2
版本过高,boost下载未成功。
8.使用命令:react-native init MyApp --version 0.44.3创建指定版本的App
9.编译程序不报错。
10.使用Xcode查看RN项目结构:
Snip20170822_4.png

11.继续输入命令:react-native run-ios运行成功。
12.运行结果
Snip20170822_3.png

13.找到index.ios.js文件使用sublime打开
Snip20170822_8.png

14.编辑内容后继续使用命令:react-native run-ios运行结果如下:

Snip20170822_6.png

Snip20170822_2.png

第一个项目Hello World了已经。

二、思考第一个问题:react-native init AwesomeProject 这个命令做了什么,是怎样创建 RN 模板项目的?

实际上,在按照教程安装环境后,会在/usr/local/bin/加上react-native脚本,实际是个node.js脚本,也就是github上的react-native-cli/index.js,在命令行全局调用react-native就会调用这个脚本。这个文件的注释也可以看到,这只是一个转接层,所有命令都会转接到local-cli上,但很奇怪react-native init创建工程的逻辑部分在这个转接层react-native-cli/index.js,部分在 local-cli/init/init.js,其他命令则全部转接到 local-cli上。

看看执行 react-native init AwesomeProject 的流程:
  • 安装 react-native 依赖:在AwesomeProject 目录执行npm install react-native,安装react-native 所有依赖的 node 模块。这是 init命令第一个做的事情,代码在 react-native-cli/index.js -> run(),复制项目模板:安装依赖后init 命令随即转接到 local-cli,通过 local-cli/generator 初始化项目,复制项目模板,模板文件在 local-cli/templates里。
  • 链接 native 代码源文件:项目模板复制后需要把刚才安装的node_module/react-native 里的源文件链接到 natvie 工程上,不同平台有不同逻辑,都在local-cli/link 里处理 native 工程的链接。iOS 处理逻辑在 local-cli/link/ios/
    这一步骤处理后, AwesomeProject.xcodeproj 所需要的模块都链接完成,可以直接运行,可以看到工程 Libraries 里所有模块都是从AwesomeProject/node_modules/react-native/ 里链接过来的。
    react-native 模块依赖了 500 多个npm 模块,这在前端界也算是正常,这些模块小部分是 RN 源码依赖的 JS 模块,大部分是用于前端构建,包括 JS 编译/打包/语法检测/http服务中间层等。
    RN 模板项目创建过程大致就是这样。

项目 JS 源码在哪里,如何跑起来的?

在生成的AwesomeProject模板项目里,iOS 端所依赖的所有模块和源码直接可以在工程里看到。但 JS 端的源码在项目里只看到业务实现代码index.ios.js,XCode 项目跑起来后,index.ios.js就执行生效了,RN 核心 JS 代码在哪里,有哪些,怎么跑起来的,都是个黑盒,接下来拆解下,看看 JS 代码是怎样运行起来的。

两种模式

RN 在 iOS 上对 JS 脚本的处理分两种模式:

  • 本地 Server模式。在本地自建一个 Server,客户端通过请求的方式获取 JS 代码。对于在模拟器跑 debug 版,会使用这种方式,用于接入 chrome 调试和脚本实时更新。
  • 本地静态bundle 模式。编译时就把所有相关 JS 文件打包编译到 APP 里,运行时直接本地读取。对于所有 release 版,或无法连接本地 ServeriPhone 真机上的 debug 版,会使用这种方式。

本地 Server 模式在下一节 chrome 调试再描述,这里先看看本地静态 bundle 模式。
本地静态 bundle
在本地静态Bundle模式中,最终所有 JS 代码都会打包成一个文件,客户端最终只需读取一个打包后的 JS 文件执行。这里从依赖分散的 JS 源文件,到最终可执行的单个 JS,有一个编译和打包 JS 的处理过程。这套处理过程的启动是在主工程AwesomeProject.xcodeproj Build Phases里执行了一个脚本node_modules/react-native/packager/react-native-xcode.sh
,最终它在 Release版或真机上执行了这样一条打包命令:

react-native bundle --entry-file index.ios.js --platform ios --dev true --reset-cache --bundle-output main.bundle --assets-dest assets

这个命令最终会输出一个 main.bundle文件,实际是个 JS 文件,包含了 RN 所有核心代码和我们项目的业务代码(这里只有index.ios.js)。
这个打包命令包含非常多处理,流程很长,算是整个 RN 部署工具的核心,主要实现在 react-native/packager里,在这个生成静态 bundle 的流程里,主要做的事情是:

  1. 编译/解析依赖
    现代前端工程中,编译几乎已经是必须的了,这里编译主要做两件事:ES6 -> 通用JSJSX -> JS
    RN 源码以及业务代码都是以 ES6 的语法去写,像 import xxx这种写法在不支持ES6语法的 JS 引擎上是无法运行的,需要编译成 require('xxx')。此外像 JSX这种在 JS 代码里嵌入 XML 标签的语法糖也需要编译成普通 JS 语法才能在 JS引擎上运行,所以需要一个编译的过程。此外需要把 JS 文件的依赖也解析出来,因为这涉及到对 JS 代码的解析,把 require('xxx')语句解析出来,所以这部分也是在编译过程中处理。
    这里统一用 Babel 这个库去做所有编译的工作。它的官网也说得很清楚它做了什么工作,除了编译,后续会提到的 SourceMap 也是用它生成,由 packager/src/JSTransformer去封装编译解析后的数据。
    解析依赖是在 packager/src/JSTransformer/worker/extract-dependencies.js,这里用 babel解析出当前文件中 require的内容后组装返回。编译是在 packager/src/JSTransformer/worker/worker.js
    里。
  2. 管理依赖、打包压缩
    上述解析依赖仅提取了当前 JS 文件依赖的文件名,并没有做依赖文件查找/读取/拼装/更新等工作,这个工作在 packager/src/node-haste里做,把一个个 JS 文件封装成一个个Module,根据上述解析出来的依赖信息,去读取依赖文件,并递归检测依赖,直到所有依赖都加载完毕。
    这里面还有层层处理,最终所有依赖模块会封装成一个 packager/src/Bundler,提供给 cli 命令行调用,打包压缩是小意思,在local-cli/bundle.js里处理了。
  3. 请求执行
    在本地静态 bundle 模式下,RN 最终会统一执行上述生成的 main.bundle,所有 JS 代码都在这里面,由 RCTBundleURLProvider.m处理执行,整个 RN 应用就跑起来了。
    main.bundle 里是合并后的 JS 代码,如果想要看这个 JS 文件合并之前是包括哪些 JS 源文件,可以在上述模块组装的过程中去打出每个模块的信息,例如在 packager/src/Bundler/Bundle.jsaddModule()
    方法里加上 console.log(moduleTransport.sourcePath)就能看到所有依赖的 JS 文件路径。另外通过下述 SourceMap 能更方便地看到。
代码流程

从 cli 命令 – 编译文件 – 解析依赖 – 组装数据 – 写入文件,这个过程在代码中实现流程很长,这里就不列出来了,大致涉及的几个文件的作用列以下:

local-cli/bundle/ - cli命令入口,传参,获取组装好的 Bundle压缩/写入文件
packager/src/Bundler/Bundle.js - 保存 bundle相关的所有模块信息/依赖/源码
packager/src/Bundler/index.js - 组装 Bundle 对象packager/src/JSTransformer - babel 转接,编译 JS,解析依赖
packager/src/node-haste - 管理依赖 cache,把 JS 源文件模块封装成 Module 对象
packager/src/Resolver - JS 模块组装打包成一个文件并不只是直接把 JS 源码拼一起,还需要重新封装模块,处理引用逻辑

第二部分文字引自bang's blog

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

推荐阅读更多精彩内容