React Native开发经验集iOS Developer

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

2017-08-23  本文已影响1164人  迷路的安然和无恙

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

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 的流程:

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

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

两种模式

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

本地 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

上一篇 下一篇

猜你喜欢

热点阅读