react-native的打包流程是通过执行react-native bundle指令进行的。
添加构建指令
修改RN项目中的package.json文件,先其中添加构建命令build-release-ios和build-debug-ios
"scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "lint": "eslint .", "start": "react-native start", "test": "jest", "build-release-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev false ", "build-debug-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev true " },
说明如下;
react-native的打包是使用的命令react-native bundle, 然后再根据需要添加对应的参数。
--entry-file ,ios或者android打包入口的js文件名称,比如index.js(如果要根据不同的平台添加不同的功能,则需要将安卓和iOS的打包入口分开创建index.ios.js, index.android.js)
--platform ,平台名称(ios或者android)
--dev ,设置为false的时候表示为发布包,true为测试包,发布包会对JavaScript代码进行优化处理。
--bundle-output, 生成的jsbundle文件的名称,比如 ./dest/bundle/index.jsbundle
--assets-dest 图片以及其他资源存放的目录,比如./dest/bundle, 注意这里导出的资源是在jsbundle中通过引用使用的资源。
开始打包
打开RN项目,执行下面的打包指令进行打包
npm run build-release-ios 或者 yarn build-release-ios
指令执行完成后,打包的产物是放置在了./dest/bundle/目录之下
内置打包产物
将jsbundel包和assets资源包拖到项目中,放置到同一个目录下。
然后修改jsbundle的读取位置,将从服务器读取改成从本地读取。
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { return [[NSBundle mainBundle] URLForResource:@"index" withExtension:@"jsbundle"]; // return [self getBundleURL]; } - (NSURL *)getBundleURL { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif }
在iOS项目中,根据不同的业务类型加载不同的模块名称
RNContainerController * containerVC = [[RNManager sharedInstance] loadWithModuleName:@"News" initialProps:@{}]; [self presentModalViewController:containerVC animated:YES];
JSBundle产物介绍
RN 通过执行react-native bundle打包命令得到产物JSBundle。
"build-debug-ios": " react-native bundle --platform ios --entry-file index.js --bundle-output ./dest/bundle/index.jsbundle --assets-dest ./dest/bundle --dev true "
因为我们平时写的RN模块中会使用到图片,git,json文件这些资源,所以打出的产物也包含了js文件和资源文件。
产物JSBundle内容组成
//1.全局变量定义 var __BUNDLE_START_TIME__=this.nativePerformanceNow?nativePerformanceNow():Date.now(),__DEV__=true,process=this.process||{},__METRO_GLOBAL_PREFIX__='',__requireCycleIgnorePatterns=[/(^|\/|\\)node_modules($|\/|\\)/];process.env=process.env||{};process.env.NODE_ENV=process.env.NODE_ENV||"development"; //2.require, clear全局函数声明 (function (global) { "use strict"; global.__r = metroRequire; global[`${__METRO_GLOBAL_PREFIX__}__d`] = define; global.__c = clear; global.__registerSegment = registerSegment; var modules = clear(); var EMPTY = {}; var CYCLE_DETECTED = {}; var _ref = {}, hasOwnProperty = _ref.hasOwnProperty; if (__DEV__) { global.$RefreshReg$ = function () {}; global.$RefreshSig$ = function () { return function (type) { return type; }; }; } })() //3.RN模块定义(包括RN框架自己的,第三方库的,用户自定义的) __d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) { xxx xxx xxx },544,[1,262,306,21,50,91],"node_modules/react-native/Libraries/NewAppScreen/components/ReloadInstructions.js"); __d(function (global, _$$_REQUIRE, _$$_IMPORT_DEFAULT, _$$_IMPORT_ALL, module, exports, _dependencyMap) { var _interopRequireDefault = _$$_REQUIRE(_dependencyMap[0], "@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = News; var _react = _interopRequireDefault(_$$_REQUIRE(_dependencyMap[1], "react")); var _reactNative = _$$_REQUIRE(_dependencyMap[2], "react-native"); var _jsxRuntime = _$$_REQUIRE(_dependencyMap[3], "react/jsx-runtime"); var _jsxFileName = "/Users/admin/Documents/MyFile/react-native-container/src/News.tsx"; function News(params) { return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, { children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.SafeAreaView, { children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { style: { color: 'red' }, children: "Hello ReactNative" }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Switch, { children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, { children: "\u5F00\u5173" }) })] }) }); } },545,[1,50,2,91],"src/News.tsx"); __d(function(global, require, _importDefaultUnused, _importAllUnused, module, exports, _dependencyMapUnused) { module.exports = { "name": "AwesomeProject", "displayName": "AAAAA" } ; },546,[],"app.json"); //4.require方法调用 __r(54); __r(0);
从上面内容可知,jsbundle有四部分组成:
1.var 全局变量声明,包括对当前运行环境的定义,bundle 的启动时间、Process进程环境相关信息;
2.在(function() { })() 闭包中定义了对 define(__d)、 require(__r)、clear(__c) 的支持,以及 module(react-native及第三方dependences依赖的module) 的加载逻辑;
3.使用__d定义的模块信息,包括RN框架源码 js 部分、自定义js代码部分、图片资源信息,供 require 引入使用;
4.通过require执行模块代码,找到 __d 定义的代码块并执行,其中require中的数字即为 __d定义行中最后出现的那个数字。
参考文章:https://blog.csdn.net/qq_24694139/article/details/107540009
评论区