Skip to content

Commit 7c66c07

Browse files
committed
docs: add sequence diagram to article
1 parent c6fec73 commit 7c66c07

5 files changed

Lines changed: 138 additions & 33 deletions

docs/article.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,21 @@ The response was... well, let's just say the React community wasn't exactly burs
88

99
And that was it. Case closed. The post quietly disappeared into the digital abyss where brave but unpopular ideas go to die... or not!
1010

11-
![Hold my beer meme](./images/hold-my-beer.png)
11+
<div align="center">
12+
<img src="./images/hold-my-beer.png" alt="Hold my beer meme" width="400" />
13+
</div>
14+
<br/>
1215

1316
Well, sometimes the "easier way around" is actually the boring way around, and where's the engineering joy in doing things the sensible way? I'm here to tell you that there **actually is a place for this idea**, and the `react-native-sandbox` package is here to prove it.
1417

1518
What if I told you that you *can* actually run React Native inside React Native? Not with WebViews (ew), not with some hacky iframe solution, but with actual, honest-to-goodness React Native components rendering other React Native components in isolated JavaScript contexts?
1619

1720
Yes, this is the story of how we took the concept of "nested apps" and made it so meta that even Christopher Nolan would be envious.
1821

19-
![Yo Dawg meme](./images/yo-dawg.png)
22+
<div align="center">
23+
<img src="./images/yo-dawg.png" alt="Yo Dawg meme" width="400" />
24+
</div>
25+
<br/>
2026

2127
So we put React Native in your React Native so you can render components while you render components! It's like when someone first figured out you could run a virtual machine inside a virtual machine.
2228

@@ -72,12 +78,20 @@ The `jsBundleSource` property is flexible and supports multiple ways to load you
7278

7379
You can also control security and permissions using `allowedTurboModules` to specify which native modules the sandbox can access i.e. whitelist approach
7480

81+
Communication works between the host app and sandbox instances using Fabric Native Components:
82+
83+
<div align="center">
84+
<img src="./communication-fabric-components.png" alt="Communication Architecture between Host and Sandbox" width="600" />
85+
</div>
86+
7587
## It's show time!
7688

7789
Our demo app is delightfully destructive—in the name of science, of course.
7890

79-
![Demo Screenshot](../apps/demo/docs/screenshot.png)
80-
91+
<div align="center" style="width: 240px; height: 300px; margin: 0 auto;">
92+
<img src="../apps/demo/docs/screenshot.png" alt="Demo Screenshot" style="width: 100%; height: 100%; object-fit: cover; object-position: top;" />
93+
</div>
94+
<br/>
8195
On the left, you'll see the "Main App" column running a component directly in the host application. On the right, the "Sandboxed" column runs the exact same component inside a `SandboxReactNativeView`. While they visually look identical, the sandboxed version is running in complete isolation.
8296

8397
```jsx
@@ -131,5 +145,9 @@ A: Yes. You can whitelist which native modules (TurboModules) are available to e
131145

132146
We have a lot of ideas of upcoming features in our [Roadmap](https://github.com/callstackincubator/react-native-sandbox?tab=readme-ov-file#-roadmap) is something is missing don't hesitate to [let us know](https://github.com/callstackincubator/react-native-sandbox/issues/new)
133147

134-
[![Let's see how deep recursive example goes](./images/how-deep.png)](https://github.com/callstackincubator/react-native-sandbox/blob/main/apps/recursive/README.md)
148+
<div align="center">
149+
<a href="https://github.com/callstackincubator/react-native-sandbox/blob/main/apps/recursive/README.md">
150+
<img src="./images/how-deep.png" alt="Let's see how deep recursive example goes" width="400" />
151+
</a>
152+
</div>
135153

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
@startuml
2+
3+
!theme aws-orange
4+
skinparam DefaultFontSize 16
5+
skinparam DefaultFontName "Inter, system-ui, sans-serif"
6+
7+
skinparam ParticipantBackgroundColor #F8FAFC
8+
skinparam ParticipantBorderColor #64748B
9+
skinparam ParticipantFontColor #1E293B
10+
skinparam ParticipantFontSize 14
11+
skinparam ParticipantFontStyle bold
12+
13+
skinparam ActorBackgroundColor #EFF6FF
14+
skinparam ActorBorderColor #3B82F6
15+
skinparam ActorFontColor #1E40AF
16+
17+
skinparam GroupBorderColor #E2E8F0
18+
skinparam GroupBackgroundColor #F1F5F9
19+
skinparam GroupFontColor #475569
20+
skinparam GroupFontSize 13
21+
skinparam GroupFontStyle bold
22+
23+
skinparam NoteBackgroundColor #F3F4F6
24+
skinparam NoteBorderColor #C4B5FD
25+
skinparam NoteFontColor #5B21B6
26+
skinparam NoteFontSize 12
27+
28+
skinparam ArrowColor #64748B
29+
skinparam ArrowFontColor #374151
30+
skinparam ArrowFontSize 12
31+
32+
skinparam SequenceMessageAlign center
33+
34+
participant HostReactInstance
35+
participant SandboxReactNativeView
36+
participant SandboxReactInstance
37+
participant "//SandboxReactNativeDelegate//" as Delegate
38+
39+
note over SandboxReactInstance
40+
**Isolated JavaScript VM**
41+
Separate JSI runtime with
42+
own global scope and context
43+
end note
44+
45+
group Initialize Sandbox
46+
47+
HostReactInstance -> SandboxReactNativeView : <SandboxReactNativeView>\n onMessage={handleMessage}\n onError={handleError}\n/>
48+
SandboxReactNativeView -> Delegate : create delegate with configuration
49+
SandboxReactNativeView -> SandboxReactInstance : create isolated React instance\n(via RCTReactNativeFactory)
50+
Delegate -> SandboxReactInstance : setup runtime & inject globals
51+
note right of SandboxReactInstance
52+
Manages and configures the
53+
isolated React instance, injects
54+
global ""postMessage"" and ""setOnMessage""
55+
functions into sandbox runtime
56+
end note
57+
58+
end
59+
60+
...
61+
62+
group Host -> Sandbox
63+
64+
HostReactInstance -> SandboxReactNativeView : postMessage(JSON.stringify({\naction: "SETUP_SND",\ndata: { unit: 'm', ...}\n}))
65+
SandboxReactNativeView -> SandboxReactInstance: call onMessage handler\n(via injected globals)
66+
67+
end
68+
69+
...
70+
71+
group Sandbox -> Host
72+
73+
SandboxReactInstance -> SandboxReactNativeView : global.postMessage({action: "ADD_MENU_ITEM"})
74+
SandboxReactNativeView -> HostReactInstance: onMessage callback\n(via Fabric Event Emitter)
75+
76+
end
77+
78+
...
79+
80+
group Error Handling
81+
82+
SandboxReactInstance -> SandboxReactNativeView : JavaScript error occurs
83+
SandboxReactNativeView -> HostReactInstance: onError callback\n(via Fabric Event Emitter)
84+
85+
end
86+
87+
@enduml
115 KB
Loading

docs/communication-turbo-modules.plantuml

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,59 +2,59 @@
22

33
skinparam DefaultFontSize 21
44

5-
participant AppReactInstance
6-
participant MultiReactMediatorModule1
5+
participant HostReactInstance
6+
participant SandboxReactNativeView
77

8-
participant "//ReactInstanceRegistry//" as ReactInstanceRegistry
8+
participant "//SandboxReactNativeDelegate//" as Delegate
99

10-
participant MultiReactMediatorModule2
1110
participant SandboxReactInstance
1211

13-
note over ReactInstanceRegistry
14-
It's not actual class or struct
15-
but rather a ""std::map"". To
16-
thread-safe access to registered
17-
""jsi::Runtime"" by ""std::string""
18-
symbolic name
12+
note over Delegate
13+
Creates isolated React instance,
14+
injects global ""postMessage"" and
15+
""setOnMessage"" functions into
16+
sandbox JavaScript runtime
1917
end note
2018

21-
group Register App
19+
group Initialize Sandbox
2220

23-
AppReactInstance -> MultiReactMediatorModule1 : registerRuntime("App", onSandboxMessage)
24-
MultiReactMediatorModule1 -> ReactInstanceRegistry : store pointer to jsi::Runtime
21+
HostReactInstance -> SandboxReactNativeView : <SandboxReactNativeView>\n onMessage={handleMessage}\n onError={handleError}\n/>
22+
SandboxReactNativeView -> Delegate : create isolated React instance
23+
Delegate -> SandboxReactInstance : setup runtime & inject globals
24+
note right of SandboxReactInstance
25+
""global.postMessage"" - send to host
26+
""global.setOnMessage"" - listen from host
27+
end note
2528

2629
end
2730

2831
...
2932

30-
group App start Sandbox
31-
32-
SandboxReactInstance -> MultiReactMediatorModule2 : registerRuntime("Sandbox", onAppMessage)
33-
MultiReactMediatorModule2 -> ReactInstanceRegistry : store pointer to jsi::Runtime
33+
group Host -> Sandbox
3434

35-
AppReactInstance -> MultiReactMediatorModule1 : postMessage(\n "Sandbox",\n {\n action: "SETUP",\n data: { language: 'PL', units: 'm' ...}\n }\n)
36-
MultiReactMediatorModule1 -> ReactInstanceRegistry : get pointer to jsi::Runtime
37-
MultiReactMediatorModule1 -> SandboxReactInstance: onAppMessage (via ""jsi::Runtime"")
35+
HostReactInstance -> SandboxReactNativeView : Commands.postMessage(\n JSON.stringify({\n action: "SETUP",\n data: { language: 'PL', units: 'm' ...}\n })\n)
36+
SandboxReactNativeView -> Delegate : postMessage(message)
37+
Delegate -> SandboxReactInstance: call onMessage handler\n(via ""jsi::Runtime"")
3838

3939
end
4040

4141
...
4242

43-
group Sandbox -> App
43+
group Sandbox -> Host
4444

45-
SandboxReactInstance -> MultiReactMediatorModule2 : postMessage(\n "App",\n {action: "ADD_MENU_ITEM"}\n)
46-
MultiReactMediatorModule2 -> ReactInstanceRegistry : get pointer to jsi::Runtime
47-
MultiReactMediatorModule2 -> AppReactInstance: onSandboxMessage (via ""jsi::Runtime"")
45+
SandboxReactInstance -> Delegate : global.postMessage(\n {action: "ADD_MENU_ITEM"}\n)
46+
Delegate -> SandboxReactNativeView: emit onMessage event\n(via Fabric Event Emitter)
47+
SandboxReactNativeView -> HostReactInstance: onMessage callback\nwith event data
4848

4949
end
5050

5151
...
5252

53-
group App -> Sandbox
53+
group Error Handling
5454

55-
AppReactInstance -> MultiReactMediatorModule1 : postMessage(\n "Sandbox",\n {action: "UPDATE_PROFILE"}\n)
56-
MultiReactMediatorModule1 -> ReactInstanceRegistry : get pointer to jsi::Runtime
57-
MultiReactMediatorModule1 -> SandboxReactInstance: onAppMessage (via ""jsi::Runtime"")
55+
SandboxReactInstance -> Delegate : JavaScript error occurs
56+
Delegate -> SandboxReactNativeView: emit onError event\n(via Fabric Event Emitter)
57+
SandboxReactNativeView -> HostReactInstance: onError callback\nwith error details
5858

5959
end
6060

-248 KB
Binary file not shown.

0 commit comments

Comments
 (0)