@bm-fe/react-native-multi-bundle 1.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INTEGRATION.md +371 -0
- package/LICENSE +21 -0
- package/README.md +240 -0
- package/package.json +86 -0
- package/scripts/build-multi-bundle.js +483 -0
- package/scripts/release-codepush-dev.sh +90 -0
- package/scripts/release-codepush.js +420 -0
- package/scripts/sync-bundles-to-assets.js +252 -0
- package/src/index.ts +40 -0
- package/src/multi-bundle/DevModeConfig.ts +23 -0
- package/src/multi-bundle/HMRClient.ts +157 -0
- package/src/multi-bundle/LocalBundleManager.ts +155 -0
- package/src/multi-bundle/ModuleErrorFallback.tsx +85 -0
- package/src/multi-bundle/ModuleLoaderMock.ts +169 -0
- package/src/multi-bundle/ModuleLoadingPlaceholder.tsx +34 -0
- package/src/multi-bundle/ModuleRegistry.ts +295 -0
- package/src/multi-bundle/README.md +343 -0
- package/src/multi-bundle/config.ts +141 -0
- package/src/multi-bundle/createModuleLoader.tsx +92 -0
- package/src/multi-bundle/createModuleRouteLoader.tsx +31 -0
- package/src/multi-bundle/devUtils.ts +48 -0
- package/src/multi-bundle/init.ts +131 -0
- package/src/multi-bundle/metro-config-helper.js +140 -0
- package/src/multi-bundle/preloadModule.ts +33 -0
- package/src/multi-bundle/routeRegistry.ts +118 -0
- package/src/types/global.d.ts +14 -0
- package/templates/metro.config.js.template +45 -0
- package/templates/multi-bundle.config.json.template +31 -0
- package/templates/native/android/ModuleLoaderModule.kt +227 -0
- package/templates/native/android/ModuleLoaderPackage.kt +26 -0
- package/templates/native/ios/ModuleLoaderModule.h +13 -0
- package/templates/native/ios/ModuleLoaderModule.m +60 -0
package/INTEGRATION.md
ADDED
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
# React Native 多 Bundle 系统集成指南
|
|
2
|
+
|
|
3
|
+
本指南将帮助你将多 Bundle 系统集成到你的 React Native 项目中。
|
|
4
|
+
|
|
5
|
+
## 目录
|
|
6
|
+
|
|
7
|
+
- [安装](#安装)
|
|
8
|
+
- [Metro 配置](#metro-配置)
|
|
9
|
+
- [Native 模块集成](#native-模块集成)
|
|
10
|
+
- [Android](#android)
|
|
11
|
+
- [iOS](#ios)
|
|
12
|
+
- [初始化多 Bundle 系统](#初始化多-bundle-系统)
|
|
13
|
+
- [配置模块](#配置模块)
|
|
14
|
+
- [构建多 Bundle](#构建多-bundle)
|
|
15
|
+
- [常见问题](#常见问题)
|
|
16
|
+
|
|
17
|
+
## 安装
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @bm-fe/react-native-multi-bundle
|
|
21
|
+
# 或
|
|
22
|
+
yarn add @bm-fe/react-native-multi-bundle
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Metro 配置
|
|
26
|
+
|
|
27
|
+
### 1. 复制 Metro 配置模板
|
|
28
|
+
|
|
29
|
+
将 `templates/metro.config.js.template` 复制到你的项目根目录,重命名为 `metro.config.js`。
|
|
30
|
+
|
|
31
|
+
### 2. 调整配置
|
|
32
|
+
|
|
33
|
+
根据你的项目结构,修改以下配置:
|
|
34
|
+
|
|
35
|
+
```javascript
|
|
36
|
+
// 模块路径规则(glob 模式)
|
|
37
|
+
const modulePaths = ['src/modules/**'];
|
|
38
|
+
|
|
39
|
+
// 共享依赖路径(这些代码会被打包到主 bundle)
|
|
40
|
+
const sharedDependencies = [
|
|
41
|
+
'node_modules/@bm-fe/react-native-multi-bundle/**',
|
|
42
|
+
'src/navigation/**'
|
|
43
|
+
];
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### 3. 环境变量(可选)
|
|
47
|
+
|
|
48
|
+
你也可以通过环境变量覆盖配置:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
RN_MULTI_BUNDLE_MODULE_PATHS='["src/modules/**"]' \
|
|
52
|
+
RN_MULTI_BUNDLE_SHARED_DEPS='["src/multi-bundle/**","src/navigation/**"]' \
|
|
53
|
+
npx react-native start
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Native 模块集成
|
|
57
|
+
|
|
58
|
+
### Android
|
|
59
|
+
|
|
60
|
+
#### 1. 复制 Native 模块文件
|
|
61
|
+
|
|
62
|
+
将以下文件从 `templates/native/android/` 复制到你的 Android 项目:
|
|
63
|
+
|
|
64
|
+
- `ModuleLoaderModule.kt` → `android/app/src/main/java/com/yourpackage/ModuleLoaderModule.kt`
|
|
65
|
+
- `ModuleLoaderPackage.kt` → `android/app/src/main/java/com/yourpackage/ModuleLoaderPackage.kt`
|
|
66
|
+
|
|
67
|
+
**重要**:修改文件中的包名 `com.yourpackage` 为你的实际包名。
|
|
68
|
+
|
|
69
|
+
#### 2. 注册 ModuleLoaderPackage
|
|
70
|
+
|
|
71
|
+
根据你使用的 React Native 架构版本,选择对应的方式:
|
|
72
|
+
|
|
73
|
+
##### 方式一:新架构(React Native 0.82+,使用 ReactHost)
|
|
74
|
+
|
|
75
|
+
如果你的 `MainApplication.kt` 使用 `ReactHost`(新架构),在 `PackageList` 中添加:
|
|
76
|
+
|
|
77
|
+
```kotlin
|
|
78
|
+
package com.yourpackage
|
|
79
|
+
|
|
80
|
+
import android.app.Application
|
|
81
|
+
import com.yourpackage.ModuleLoaderPackage
|
|
82
|
+
import com.facebook.react.PackageList
|
|
83
|
+
import com.facebook.react.ReactApplication
|
|
84
|
+
import com.facebook.react.ReactHost
|
|
85
|
+
import com.facebook.react.ReactNativeApplicationEntryPoint.loadReactNative
|
|
86
|
+
import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost
|
|
87
|
+
|
|
88
|
+
class MainApplication : Application(), ReactApplication {
|
|
89
|
+
override val reactHost: ReactHost by lazy {
|
|
90
|
+
getDefaultReactHost(
|
|
91
|
+
context = applicationContext,
|
|
92
|
+
packageList =
|
|
93
|
+
PackageList(this).packages.apply {
|
|
94
|
+
// Packages that cannot be autolinked yet can be added manually here
|
|
95
|
+
add(ModuleLoaderPackage())
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override fun onCreate() {
|
|
101
|
+
super.onCreate()
|
|
102
|
+
loadReactNative(this)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
##### 方式二:旧架构(使用 ReactNativeHost)
|
|
108
|
+
|
|
109
|
+
如果你的 `MainApplication.kt` 使用 `ReactNativeHost`(旧架构),在 `getPackages()` 方法中添加:
|
|
110
|
+
|
|
111
|
+
```kotlin
|
|
112
|
+
package com.yourpackage
|
|
113
|
+
|
|
114
|
+
import android.app.Application
|
|
115
|
+
import com.yourpackage.ModuleLoaderPackage
|
|
116
|
+
import com.facebook.react.ReactApplication
|
|
117
|
+
import com.facebook.react.ReactPackage
|
|
118
|
+
import com.facebook.react.PackageList
|
|
119
|
+
import com.facebook.react.ReactNativeHost
|
|
120
|
+
import com.facebook.react.defaults.DefaultReactNativeHost
|
|
121
|
+
|
|
122
|
+
class MainApplication : Application(), ReactApplication {
|
|
123
|
+
override val reactNativeHost: ReactNativeHost =
|
|
124
|
+
object : DefaultReactNativeHost(this) {
|
|
125
|
+
override fun getPackages(): List<ReactPackage> =
|
|
126
|
+
PackageList(this).packages.apply {
|
|
127
|
+
// Packages that cannot be autolinked yet can be added manually here
|
|
128
|
+
add(ModuleLoaderPackage())
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
override fun getJSMainModuleName(): String = "index"
|
|
132
|
+
override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG
|
|
133
|
+
// ... 其他配置
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// ... 其他代码
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
**注意**:React Native 0.82+ 默认使用新架构(ReactHost),推荐使用方式一。
|
|
141
|
+
|
|
142
|
+
#### 3. 确保 assets 目录存在
|
|
143
|
+
|
|
144
|
+
确保 `android/app/src/main/assets/` 目录存在,bundle 文件将放在这里。
|
|
145
|
+
|
|
146
|
+
### iOS
|
|
147
|
+
|
|
148
|
+
#### 1. 复制 Native 模块文件
|
|
149
|
+
|
|
150
|
+
将以下文件从 `templates/native/ios/` 添加到你的 iOS 项目:
|
|
151
|
+
|
|
152
|
+
- `ModuleLoaderModule.h`
|
|
153
|
+
- `ModuleLoaderModule.m`
|
|
154
|
+
|
|
155
|
+
在 Xcode 中:
|
|
156
|
+
1. 右键点击项目 → Add Files to "YourProject"
|
|
157
|
+
2. 选择这两个文件
|
|
158
|
+
3. 确保 "Copy items if needed" 已勾选
|
|
159
|
+
|
|
160
|
+
#### 2. 注册模块
|
|
161
|
+
|
|
162
|
+
iOS 端的模块会自动注册(通过 `RCT_EXPORT_MODULE`),无需额外配置。
|
|
163
|
+
|
|
164
|
+
**注意**:iOS 端的 bundle 加载实现可能需要根据你的具体需求调整。当前模板提供了基础框架。
|
|
165
|
+
|
|
166
|
+
## 初始化多 Bundle 系统
|
|
167
|
+
|
|
168
|
+
在应用入口(通常是 `App.tsx`)中初始化:
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
import React, { useEffect, useState } from 'react';
|
|
172
|
+
import { initMultiBundle, LocalBundleManager } from '@bm-fe/react-native-multi-bundle';
|
|
173
|
+
import { Platform } from 'react-native';
|
|
174
|
+
|
|
175
|
+
function App() {
|
|
176
|
+
const [ready, setReady] = useState(false);
|
|
177
|
+
|
|
178
|
+
useEffect(() => {
|
|
179
|
+
async function bootstrap() {
|
|
180
|
+
const result = await initMultiBundle({
|
|
181
|
+
// 模块路径规则(glob 模式)
|
|
182
|
+
modulePaths: ['src/modules/**'],
|
|
183
|
+
|
|
184
|
+
// 共享依赖路径
|
|
185
|
+
sharedDependencies: [
|
|
186
|
+
'node_modules/@bm-fe/react-native-multi-bundle/**',
|
|
187
|
+
'src/navigation/**'
|
|
188
|
+
],
|
|
189
|
+
|
|
190
|
+
// Manifest 提供者(可选,默认使用 LocalBundleManager)
|
|
191
|
+
manifestProvider: async () => {
|
|
192
|
+
return await LocalBundleManager.getCurrentBundleManifest();
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
// 预加载模块列表(可选)
|
|
196
|
+
preloadModules: ['settings'],
|
|
197
|
+
|
|
198
|
+
// 开发服务器配置(可选)
|
|
199
|
+
devServer: {
|
|
200
|
+
host: Platform.OS === 'android' ? '10.0.2.2' : 'localhost',
|
|
201
|
+
port: 8081,
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
// 错误处理回调(可选)
|
|
205
|
+
onError: (error) => {
|
|
206
|
+
console.error('MultiBundle error:', error);
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
if (result.success) {
|
|
211
|
+
setReady(true);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
bootstrap();
|
|
216
|
+
}, []);
|
|
217
|
+
|
|
218
|
+
if (!ready) {
|
|
219
|
+
return <LoadingScreen />;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// ... 其余代码
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## 配置模块
|
|
227
|
+
|
|
228
|
+
### 1. 创建 multi-bundle.config.json
|
|
229
|
+
|
|
230
|
+
将 `templates/multi-bundle.config.json.template` 复制到项目根目录,重命名为 `multi-bundle.config.json`。
|
|
231
|
+
|
|
232
|
+
### 2. 配置模块
|
|
233
|
+
|
|
234
|
+
编辑 `multi-bundle.config.json`:
|
|
235
|
+
|
|
236
|
+
```json
|
|
237
|
+
{
|
|
238
|
+
"formatVersion": 1,
|
|
239
|
+
"platforms": ["ios", "android"],
|
|
240
|
+
"main": {
|
|
241
|
+
"entry": "src/main-entry.tsx",
|
|
242
|
+
"version": "1.0.0"
|
|
243
|
+
},
|
|
244
|
+
"modules": [
|
|
245
|
+
{
|
|
246
|
+
"id": "home",
|
|
247
|
+
"entry": "src/modules/Home/index.ts",
|
|
248
|
+
"version": "1.0.0",
|
|
249
|
+
"dependencies": [],
|
|
250
|
+
"lazy": true
|
|
251
|
+
}
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### 3. 创建模块入口文件
|
|
257
|
+
|
|
258
|
+
每个模块需要有一个入口文件,例如 `src/modules/Home/index.ts`:
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
import HomeScreen from './HomeScreen';
|
|
262
|
+
|
|
263
|
+
const exports = {
|
|
264
|
+
routes: {
|
|
265
|
+
Home: HomeScreen,
|
|
266
|
+
},
|
|
267
|
+
components: {
|
|
268
|
+
HomeScreen,
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// 注册模块
|
|
273
|
+
const ModuleRegistry = globalThis.__ModuleRegistry;
|
|
274
|
+
if (ModuleRegistry) {
|
|
275
|
+
ModuleRegistry.registerModule('home', exports);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
export default exports;
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## 构建多 Bundle
|
|
282
|
+
|
|
283
|
+
### 使用 npm 脚本
|
|
284
|
+
|
|
285
|
+
在 `package.json` 中添加:
|
|
286
|
+
|
|
287
|
+
```json
|
|
288
|
+
{
|
|
289
|
+
"scripts": {
|
|
290
|
+
"bundle:ios": "node node_modules/@bm-fe/react-native-multi-bundle/scripts/build-multi-bundle.js ios",
|
|
291
|
+
"bundle:android": "node node_modules/@bm-fe/react-native-multi-bundle/scripts/build-multi-bundle.js android",
|
|
292
|
+
"bundle:ios:prod": "node node_modules/@bm-fe/react-native-multi-bundle/scripts/build-multi-bundle.js ios --env production",
|
|
293
|
+
"bundle:android:prod": "node node_modules/@bm-fe/react-native-multi-bundle/scripts/build-multi-bundle.js android --env production"
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 使用 CLI 命令
|
|
299
|
+
|
|
300
|
+
如果全局安装了包:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
multi-bundle-build ios
|
|
304
|
+
multi-bundle-build android --env production
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
### 构建产物
|
|
308
|
+
|
|
309
|
+
构建完成后,产物位于 `build/bundles/<platform>/` 目录:
|
|
310
|
+
|
|
311
|
+
- 主 bundle:`index.android.bundle` (Android) 或 `main.jsbundle` (iOS)
|
|
312
|
+
- 模块 bundle:`modules/<moduleId>.bundle` (Android) 或 `modules/<moduleId>.jsbundle` (iOS)
|
|
313
|
+
- Manifest:`bundle-manifest.json`
|
|
314
|
+
|
|
315
|
+
## 使用模块路由
|
|
316
|
+
|
|
317
|
+
### 方式一:使用 createModuleRouteLoader(推荐)
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { createModuleRouteLoader } from '@bm-fe/react-native-multi-bundle';
|
|
321
|
+
|
|
322
|
+
// 创建路由加载器
|
|
323
|
+
export const createHomeScreen = createModuleRouteLoader('home', 'Home');
|
|
324
|
+
|
|
325
|
+
// 在 React Navigation 中使用
|
|
326
|
+
<Stack.Screen name="Home" getComponent={createHomeScreen} />
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### 方式二:使用路由注册系统
|
|
330
|
+
|
|
331
|
+
```typescript
|
|
332
|
+
import { registerModuleRoute, getModuleRoute } from '@bm-fe/react-native-multi-bundle';
|
|
333
|
+
|
|
334
|
+
// 注册路由
|
|
335
|
+
registerModuleRoute('home', 'Home');
|
|
336
|
+
|
|
337
|
+
// 获取路由组件
|
|
338
|
+
const HomeScreen = getModuleRoute('home', 'Home');
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## 常见问题
|
|
342
|
+
|
|
343
|
+
### 1. 模块加载失败
|
|
344
|
+
|
|
345
|
+
- 检查 manifest 是否正确配置
|
|
346
|
+
- 确认模块 ID 与 manifest 中的 ID 一致
|
|
347
|
+
- 查看控制台错误信息
|
|
348
|
+
|
|
349
|
+
### 2. Metro 构建问题
|
|
350
|
+
|
|
351
|
+
- 确认 `metro.config.js` 配置正确
|
|
352
|
+
- 检查模块路径规则是否匹配实际路径
|
|
353
|
+
- 清除 Metro 缓存:`npx react-native start --reset-cache`
|
|
354
|
+
|
|
355
|
+
### 3. Native 模块未找到
|
|
356
|
+
|
|
357
|
+
- 确认已正确注册 ModuleLoaderPackage
|
|
358
|
+
- 检查包名是否正确
|
|
359
|
+
- 重新构建原生应用
|
|
360
|
+
|
|
361
|
+
### 4. 开发环境问题
|
|
362
|
+
|
|
363
|
+
- 确认开发服务器正在运行
|
|
364
|
+
- 检查 `devServer` 配置是否正确
|
|
365
|
+
- 验证 manifest URL 是否可访问
|
|
366
|
+
|
|
367
|
+
## 更多信息
|
|
368
|
+
|
|
369
|
+
- [API 参考](./src/multi-bundle/README.md)
|
|
370
|
+
- [示例应用](./examples/demo-app/README.md)
|
|
371
|
+
- [模块开发规范](./docs/模块%20Bundle%20开发规范.md)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 @bm-fe/react-native-multi-bundle
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# @bm-fe/react-native-multi-bundle
|
|
2
|
+
|
|
3
|
+
React Native 多 Bundle 系统 - 支持模块按需加载和独立更新
|
|
4
|
+
|
|
5
|
+
## 特性
|
|
6
|
+
|
|
7
|
+
- ✅ **模块按需加载**:支持懒加载,减少初始包体积
|
|
8
|
+
- ✅ **模块依赖管理**:自动处理模块间的依赖关系
|
|
9
|
+
- ✅ **模块状态管理**:完整的生命周期管理(idle/loading/loaded/failed)
|
|
10
|
+
- ✅ **路由加载器**:`createModuleRouteLoader`,完美支持 React Navigation `getComponent` API
|
|
11
|
+
- ✅ **预加载支持**:`preloadModule` 支持关键模块预加载
|
|
12
|
+
- ✅ **开发环境 Mock**:开发环境无需 Native 模块即可运行
|
|
13
|
+
- ✅ **TypeScript 支持**:完整的类型定义
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @bm-fe/react-native-multi-bundle
|
|
19
|
+
# 或
|
|
20
|
+
yarn add @bm-fe/react-native-multi-bundle
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
### 1. 初始化多 Bundle 系统
|
|
26
|
+
|
|
27
|
+
在应用入口(通常是 `App.tsx`)中调用 `initMultiBundle`:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { initMultiBundle, LocalBundleManager } from '@bm-fe/react-native-multi-bundle';
|
|
31
|
+
import { Platform } from 'react-native';
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
34
|
+
const [ready, setReady] = useState(false);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
async function bootstrap() {
|
|
38
|
+
const result = await initMultiBundle({
|
|
39
|
+
modulePaths: ['src/modules/**'],
|
|
40
|
+
sharedDependencies: [
|
|
41
|
+
'node_modules/@bm-fe/react-native-multi-bundle/**',
|
|
42
|
+
'src/navigation/**'
|
|
43
|
+
],
|
|
44
|
+
manifestProvider: async () => {
|
|
45
|
+
return await LocalBundleManager.getCurrentBundleManifest();
|
|
46
|
+
},
|
|
47
|
+
preloadModules: ['settings'],
|
|
48
|
+
devServer: {
|
|
49
|
+
host: Platform.OS === 'android' ? '10.0.2.2' : 'localhost',
|
|
50
|
+
port: 8081,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
if (result.success) {
|
|
55
|
+
setReady(true);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
bootstrap();
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
if (!ready) {
|
|
63
|
+
return <LoadingScreen />;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ... 其余代码
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### 2. 使用模块路由
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
import { createModuleRouteLoader } from '@bm-fe/react-native-multi-bundle';
|
|
74
|
+
|
|
75
|
+
// 创建路由加载器
|
|
76
|
+
export const createHomeScreen = createModuleRouteLoader('home', 'Home');
|
|
77
|
+
|
|
78
|
+
// 在 React Navigation 中使用
|
|
79
|
+
<Stack.Screen name="Home" getComponent={createHomeScreen} />
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 完整集成指南
|
|
83
|
+
|
|
84
|
+
详细的集成步骤请参考:[INTEGRATION.md](./INTEGRATION.md)
|
|
85
|
+
|
|
86
|
+
包括:
|
|
87
|
+
- Metro 配置
|
|
88
|
+
- Native 模块集成(Android/iOS)
|
|
89
|
+
- 模块配置
|
|
90
|
+
- 构建多 Bundle
|
|
91
|
+
|
|
92
|
+
## API 文档
|
|
93
|
+
|
|
94
|
+
### initMultiBundle
|
|
95
|
+
|
|
96
|
+
初始化多 Bundle 系统。
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
function initMultiBundle(config?: MultiBundleConfig): Promise<InitResult>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### createModuleRouteLoader
|
|
103
|
+
|
|
104
|
+
创建模块路由加载器函数(推荐,用于 React Navigation `getComponent` API)。
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
function createModuleRouteLoader(
|
|
108
|
+
moduleId: string,
|
|
109
|
+
routeKey: string
|
|
110
|
+
): () => React.ComponentType<any>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### preloadModule
|
|
114
|
+
|
|
115
|
+
预加载模块。
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
function preloadModule(moduleId: string): Promise<void>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
更多 API 文档请参考:[src/multi-bundle/README.md](./src/multi-bundle/README.md)
|
|
122
|
+
|
|
123
|
+
## 示例应用
|
|
124
|
+
|
|
125
|
+
查看完整示例:[examples/demo-app](./examples/demo-app/README.md)
|
|
126
|
+
|
|
127
|
+
## 版本管理
|
|
128
|
+
|
|
129
|
+
本项目使用 [standard-version](https://github.com/conventional-changelog/standard-version) 进行版本管理,遵循 [Conventional Commits](https://www.conventionalcommits.org/) 规范。
|
|
130
|
+
|
|
131
|
+
### 版本命令
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
# 自动判断版本类型
|
|
135
|
+
npm run version
|
|
136
|
+
|
|
137
|
+
# 指定版本类型
|
|
138
|
+
npm run version:patch # 1.0.0 -> 1.0.1
|
|
139
|
+
npm run version:minor # 1.0.0 -> 1.1.0
|
|
140
|
+
npm run version:major # 1.0.0 -> 2.0.0
|
|
141
|
+
npm run version:beta # 1.0.0 -> 1.0.1-beta.0
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## 发布流程
|
|
145
|
+
|
|
146
|
+
### 发布前检查
|
|
147
|
+
|
|
148
|
+
1. **确保代码已提交**
|
|
149
|
+
```bash
|
|
150
|
+
git status
|
|
151
|
+
git add .
|
|
152
|
+
git commit -m "chore: prepare release"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
2. **运行测试**
|
|
156
|
+
```bash
|
|
157
|
+
npm test
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
3. **检查打包内容**
|
|
161
|
+
```bash
|
|
162
|
+
npm pack --dry-run
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 发布 Beta 版本
|
|
166
|
+
|
|
167
|
+
Beta 版本用于测试新功能,不会影响 `latest` 标签。
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# 方式 1:使用便捷脚本(推荐)
|
|
171
|
+
npm run release:beta
|
|
172
|
+
|
|
173
|
+
# 方式 2:分步执行
|
|
174
|
+
npm run version:beta # 更新版本号为 beta(如:1.0.0 -> 1.0.1-beta.0)
|
|
175
|
+
npm run publish:beta # 发布到 beta 标签
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**安装 Beta 版本:**
|
|
179
|
+
```bash
|
|
180
|
+
npm install @bm-fe/react-native-multi-bundle@beta
|
|
181
|
+
# 或安装特定 beta 版本
|
|
182
|
+
npm install @bm-fe/react-native-multi-bundle@1.0.1-beta.0
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### 发布正式版本
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# 方式 1:使用便捷脚本(推荐)
|
|
189
|
+
npm run release
|
|
190
|
+
|
|
191
|
+
# 方式 2:分步执行
|
|
192
|
+
npm run version # 自动判断版本类型并更新 CHANGELOG
|
|
193
|
+
npm publish # 发布到 latest 标签
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**发布流程说明:**
|
|
197
|
+
1. `npm run version` 会根据提交信息自动判断版本类型(patch/minor/major)
|
|
198
|
+
2. 自动更新 `CHANGELOG.md`
|
|
199
|
+
3. 自动创建 git tag
|
|
200
|
+
4. `npm publish` 发布到 npm(默认 `latest` 标签)
|
|
201
|
+
|
|
202
|
+
### 版本标签说明
|
|
203
|
+
|
|
204
|
+
- **latest**:稳定版本,用户通过 `npm install @bm-fe/react-native-multi-bundle` 安装
|
|
205
|
+
- **beta**:测试版本,需要显式指定 `@beta` 标签安装
|
|
206
|
+
|
|
207
|
+
### 从 Beta 升级到正式版
|
|
208
|
+
|
|
209
|
+
当 beta 版本稳定后,发布正式版本:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
# 1. 更新版本号为正式版本(移除 beta 后缀)
|
|
213
|
+
npm version 1.0.1 --no-git-tag-version
|
|
214
|
+
|
|
215
|
+
# 2. 发布到 latest
|
|
216
|
+
npm publish
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## 开发
|
|
220
|
+
|
|
221
|
+
```bash
|
|
222
|
+
# 安装依赖
|
|
223
|
+
npm install
|
|
224
|
+
|
|
225
|
+
# 运行测试
|
|
226
|
+
npm test
|
|
227
|
+
|
|
228
|
+
# 运行示例应用
|
|
229
|
+
cd examples/demo-app
|
|
230
|
+
npm install
|
|
231
|
+
npm start
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## 许可证
|
|
235
|
+
|
|
236
|
+
MIT
|
|
237
|
+
|
|
238
|
+
## 贡献
|
|
239
|
+
|
|
240
|
+
欢迎提交 Issue 和 Pull Request!
|
package/package.json
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bm-fe/react-native-multi-bundle",
|
|
3
|
+
"version": "1.0.0-beta.0",
|
|
4
|
+
"description": "React Native 多 Bundle 系统 - 支持模块按需加载和独立更新",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"types": "src/index.ts",
|
|
7
|
+
"react-native": "src/index.ts",
|
|
8
|
+
"author": "Max",
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"react-native",
|
|
12
|
+
"multi-bundle",
|
|
13
|
+
"code-splitting",
|
|
14
|
+
"lazy-loading",
|
|
15
|
+
"module-loader",
|
|
16
|
+
"bundle",
|
|
17
|
+
"dynamic-loading"
|
|
18
|
+
],
|
|
19
|
+
"files": [
|
|
20
|
+
"src",
|
|
21
|
+
"scripts",
|
|
22
|
+
"templates",
|
|
23
|
+
"README.md",
|
|
24
|
+
"INTEGRATION.md",
|
|
25
|
+
"LICENSE"
|
|
26
|
+
],
|
|
27
|
+
"bin": {
|
|
28
|
+
"multi-bundle-build": "./scripts/build-multi-bundle.js"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"lint": "eslint .",
|
|
32
|
+
"test": "jest",
|
|
33
|
+
"version": "standard-version",
|
|
34
|
+
"version:patch": "standard-version --release-as patch",
|
|
35
|
+
"version:minor": "standard-version --release-as minor",
|
|
36
|
+
"version:major": "standard-version --release-as major",
|
|
37
|
+
"version:beta": "npm version prerelease --preid=beta --no-git-tag-version",
|
|
38
|
+
"publish:beta": "npm publish --tag beta",
|
|
39
|
+
"release:beta": "npm run version:beta && npm run publish:beta",
|
|
40
|
+
"release": "npm run version && npm publish"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"react": ">=18.0.0",
|
|
44
|
+
"react-native": ">=0.70.0"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@react-navigation/native": "^7.1.21",
|
|
48
|
+
"@react-navigation/native-stack": "^7.6.4",
|
|
49
|
+
"react-native-fs": "^2.20.0",
|
|
50
|
+
"react-native-safe-area-context": "^5.6.2",
|
|
51
|
+
"react-native-screens": "^4.18.0"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@babel/core": "^7.28.5",
|
|
55
|
+
"@babel/preset-env": "^7.28.5",
|
|
56
|
+
"@babel/runtime": "^7.28.4",
|
|
57
|
+
"@react-native-community/cli": "20.0.2",
|
|
58
|
+
"@react-native-community/cli-platform-android": "20.0.2",
|
|
59
|
+
"@react-native-community/cli-platform-ios": "20.0.2",
|
|
60
|
+
"@react-native/babel-preset": "0.82.1",
|
|
61
|
+
"@react-native/eslint-config": "0.82.1",
|
|
62
|
+
"@react-native/metro-config": "0.82.1",
|
|
63
|
+
"@react-native/typescript-config": "0.82.1",
|
|
64
|
+
"@rnx-kit/babel-preset-metro-react-native": "^3.0.0",
|
|
65
|
+
"@testing-library/react-native": "^13.3.3",
|
|
66
|
+
"@types/jest": "^30.0.0",
|
|
67
|
+
"@types/react": "^19.2.6",
|
|
68
|
+
"@types/react-test-renderer": "^19.1.0",
|
|
69
|
+
"babel-jest": "^30.2.0",
|
|
70
|
+
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
71
|
+
"eslint": "^9.39.1",
|
|
72
|
+
"jest": "^30.2.0",
|
|
73
|
+
"patch-package": "^8.0.1",
|
|
74
|
+
"postinstall-postinstall": "^2.1.0",
|
|
75
|
+
"prettier": "3.6.2",
|
|
76
|
+
"react-test-renderer": "^19.1.1",
|
|
77
|
+
"standard-version": "^9.5.0",
|
|
78
|
+
"typescript": "5.9.3"
|
|
79
|
+
},
|
|
80
|
+
"engines": {
|
|
81
|
+
"node": ">=18"
|
|
82
|
+
},
|
|
83
|
+
"publishConfig": {
|
|
84
|
+
"access": "public"
|
|
85
|
+
}
|
|
86
|
+
}
|