tag:blogger.com,1999:blog-89977275884223916562024-03-13T00:15:26.288-07:00Parashuram's blogaxemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comBlogger361125tag:blogger.com,1999:blog-8997727588422391656.post-91392487683455529042019-10-24T13:13:00.003-07:002019-10-24T13:18:05.285-07:00Debugging React Native iOS Apps with SafariReact Native has great developer experience, and the debugging workflow is at the core of the workflows. Today, we use Chrome to debug JavaScript in React Native apps. In this blog, I explore an alternative approach to the debugging workflow using Safari. <br />
<br />
<h3>
How debugging works today</h3>
To start debugging, we open the developer menu (using Cmd+D) and select "Debug with Chrome". This action tells the Metro Packager to open the Chrome browser and the JavaScript code now runs on Chrome, instead of running on the device. A web socket connection between Chrome and the device/emulator via metro is responsible delivering the JS commands to Chrome, and sending the results of the statements back to the emulator. <br />
<br />
<h3>
Issues with Chrome as a Debugger</h3>
The entire debugger setup is pretty clever as it brings the classic web development workflow to mobile. However, there are a few issues with this setup<br />
<ol>
<li>The JS VM running on the device is JavaScript Core (JSC), and is different from V8/Chrome during debug mode. These JS VM differences could lead to hard to fix bugs. </li>
<li>Communication during debug mode is over a web socket, which is inherently asynchronous. This poses a problem for cases when native modules expose synchronous APIs. The issue only gets larger Fabric and TurboModules, which have many more synchronous methods. </li>
<li>Many developers currently using the JS Profiler in Chrome to understand the performance of their React Native app. The profiles are not accurate since they have that web socket layer, introducing a level of network latency, which is not present in the real app. </li>
</ol>
<br />
<h3>
Using Safari</h3>
Turns out, Safari can be used to connect to apps that run JSC. For React Native apps, we can use Safari to debug JavaScript and use workflows like setting breakpoints, inspecting variables, etc. However, the JSC debugger in Safari does not use the network stack, which means that the sourcemap URL in the index.bundle file is not evaluated, leaving us to debug one giant JS file.<br />
To work around this, we an use inline sourcemap that can be enabled by a single line change in the <span style="font-family: "courier new" , "courier" , monospace;">Appdelegate.m</span> file.<br />
<br />
In the file sourceURLForBridge, replace return [[RCTBundleURLProvider sharedSettings]... with the following<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">[NSURL URLWithString:[[[[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil] absoluteString] stringByAppendingString:@"&inlineSourceMap=true" ]];</span><br />
<br />
This line simply appends a <span style="font-family: "Courier New", Courier, monospace;">inlineSourceMap=true</span>, making metro return the sourecmaps with the index.bundle file. <br />
Once this is setup, Safari can successfully recognize the sourcecmaps and open the source files correctly. <br />
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/GrGqIIz51k4" width="100%"></iframe>
<br />
<br />
<h3>
Next Steps</h3>
<br />
Note that this method works with emulators, it does not work with the device. Now that we have Safari working, I would also like to get the JS Profiler in Safari, to give us accurate JS execution information, which should help improving performance of the apps. axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-17941600575653123962019-09-05T07:09:00.003-07:002019-09-05T07:25:38.128-07:00Using Flipper with React Native<a href="https://fbflipper.com/">Flipper</a> is a great developer tool for debugging mobile apps and quite popular in the Android and iOS communities. As a companion app for the mobile app development process, it provides tools to inspect network traffic and understand the native UI view hierarchy. With its extensible plugin API, Flipper is now an indispensable tool for many developers at Facebook who work on the family of mobile apps.<br />
<br />
<h3>
<u>Using Flipper with existing React Native Apps today</u></h3>
If you are using a version of React Native lesser than 0.62, you would have to follow these steps to enable Flipper. These steps are applicable to both existing brownfield and greenfield React Native projects, and projects created from the command line. <br />
This is mostly due to conflicting versions of Yoga. React Native ships Yoga as a part of the repo, while Flipper picks it up from gradle/cocoapods. <br />
Note that these issues have been resolved in the master branch. <br />
<br />
<center>
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/O2NHrOAOXFg" width="100%"></iframe>
</center>
<br />
The code in the video is also available in <a href="https://github.com/nparashuram/ChainReactApp2019/commit/e526da5b74f8ae920d9b99ac1e221bc3a3de7549">a commit</a> that can be used as a reference for integration. <br />
<h3>
<i>
Android</i></h3>
Assuming <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app></span> is the root of your react native project, <br />
<ul>
<li>Create a new file called in <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app>/android/src/debug/java/com/your/package/name/ReactNativeFlipper.java</span> and copy the contents from <a href="https://github.com/facebook/react-native/blob/69020a8e877d68af2fec0becd008f3a48c3af8e7/template/android/app/src/debug/java/com/helloworld/ReactNativeFlipper.java">here</a>. This class is responsible for initializing and adding all the plugins needed. This file is added to the "debug" folder since we don't want Flipper to be packaged in our production app. </li>
<li>In <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app>/android/src/main/java/com/your/package/name/MainApplication.java</span></li>
<ul>
<li><span style="font-family: "courier new" , "courier" , monospace;">A</span>dd <a href="https://github.com/facebook/react-native/blob/69020a8e877d68af2fec0becd008f3a48c3af8e7/template/android/app/src/main/java/com/helloworld/MainApplication.java#L49-L77">this new function</a> and its <a href="https://github.com/facebook/react-native/blob/69020a8e877d68af2fec0becd008f3a48c3af8e7/template/android/app/src/main/java/com/helloworld/MainApplication.java#L4,L11">imports</a>. This function uses reflection to ensure that Flipper is not bundled in the production copy of your app. </li>
<li>In the <span style="font-family: "courier new" , "courier" , monospace;">onCreate</span> method, add <span style="font-family: "courier new" , "courier" , monospace;">initializeFlipper(this, getReactNativeHost().getReactInstanceManager());</span> to start Flipper. </li>
</ul>
<li>In <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app></span>/android/app/build.gradle, inside dependencies section, add <a href="https://github.com/facebook/react-native/blob/69020a8e877d68af2fec0becd008f3a48c3af8e7/template/android/app/build.gradle#L194-L198">these lines</a> for including Flipper in the project. Note that in the dependencies, we exclude some dependencies like Yoga since we want to use the version of Yoga that is packaged with React Native. </li>
</ul>
Open the Flipper Desktop Client and you should be able to see your app, with plugins like native UI hierarchy manager, Databases, Network requests, Shared Preferences and Images. <br />
<br />
<h3>
<i>iOS</i></h3>
The iOS
integration is a little tricky since there is no simple way to exclude Yoga from cocoapods. I have fixed this issue using two diffs (<a href="https://github.com/facebook/react-native/commit/a58dd9683da6135bca119a8b0ae5d0ea5382cf4c">1</a>, <a href="https://github.com/facebook/react-native/commit/82a8080f0704e83079d0429e4e367f5131052e64">2</a>). <br />
<ul>
<li>Patch React Native with my changes by running this <a href="https://gist.github.com/axemclion/b78d00c7092a2ee78d242192a847ff73">gist of find/replace</a> of shell commands. </li>
<li>Make the changes from <a href="https://github.com/facebook/react-native/commit/70274f4e9166dbe9da2d04953a95c2909b455d1d#diff-a3c6c8e64fbbd1efef345c45e3811571R4">this commit</a> to the <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app>/ios/Podfile</span><span style="font-family: "courier new" , "courier" , monospace;"> </span>and <span style="font-family: "courier new" , "courier" , monospace;"><your_rn_app>/ios/app_name/AppDelegate.m</span></li>
<li>Run pod install to install the additional cocoapods for flipper</li>
<li>Run the app</li>
</ul>
Open the Flipper Desktop Client, and you should be able to see the plugins for Layout, Network and User preferences.<br />
<br />
You can also check out the sample <a href="https://github.com/facebook/react-native/tree/master/RNTester">RNTester app</a> that has flipper integration and could use the commits for Android and iOS as examples for integrating. <br />
<h3>
<u>Flipper by Default</u></h3>
Fixes for the conflicts due to different versions of Yoga are solved and are in master. This means that the new templates come with files like ReactNativeFlipper.java.<br />
<br />
Hence, for versions of React Native >= 0.62<br />
<ul>
<li>For Android, simply add <span style="font-family: "courier new" , "courier" , monospace;">initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); </span> to MainApplication.java's <span style="font-family: "courier new" , "courier" , monospace;">onCreate</span> method. </li>
<li>For iOS, add [AppDelegate initializeFlipper:application]; as the first line in AppDelegate.m's <span style="font-family: "courier new" , "courier" , monospace;">didFinishLaunchingWithOptions</span> method. </li>
</ul>
If you are using a brownfield app with newer versions of React Native, these steps will still apply if you have updated your project with the latest template.<br />
Alternatively, you can use react native from source and update your package's dependency of react-native to point to <span style="font-family: "courier new" , "courier" , monospace;">github:facebook/react-native#master</span> instead of a specific version. <br />
<br />
<br />
<h3>
<u>Next Steps</u></h3>
<ol>
<li>Create a plugin that can help visualize React Performance. similar to the diagram from a <a href="http://blog.nparashuram.com/2019/07/chain-react-measuring-performance-of.html">previous conference talk</a>. </li>
<li>Work with the community on adding more plugins (like redux, redux-saga, mobx, etc.) to make the React Native developer experience even better !! </li>
</ol>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-35147143324604095232019-07-31T10:31:00.000-07:002019-07-31T10:31:04.325-07:00Chain React - Measuring Performance of React Native AppsChainReact 2019, Portland<br /><br /><br />
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/nphKGWjhg2M" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-74843055468621642582019-07-16T22:06:00.001-07:002019-07-16T22:07:42.091-07:00Measuring Performance of Hermes in React NativeFacebook <a href="https://code.fb.com/android/hermes/">announced Hermes</a>, the new JavaScript Engine at the <a href="https://www.youtube.com/watch?v=zEjqDWqeDdg">keynote</a> at Chain React 2019. During the talk, we saw some videos and numbers, showing Hermes and the current JavaScript engine side by side. This blog post dives deeper into those experiments and how those experiments were structures. The goal is to make the experiments reproducible and verifiable.<br />
<br />
<h4>
<u>
Goal</u></h4>
The goal of the experiments is to understand how the different JavaScript engines impact the performance of React Native. Currently, we can run React Native with JSC, Hermes and V8. <br />
While benchmarks like <a href="https://chromium.github.io/octane/">Octane</a> compare JavaScript execution in isolation, these experiments test the engine in a mobile environment, where engine startup and first run matter. <br />
<br />
<h4>
<u>
The Apps</u></h4>
To ensure that the tests represent real world scenarios, we run end to end scenarios on apps that sit on either end of the spectrum. <br />
<ol>
<li><a href="https://github.com/nparashuram/ChainReactApp2019">Chain React Conference app</a> - A small scale React Native app with minimal network dependencies but a fair amount of content. </li>
<li><a href="http://github.com/nparashuram/mattermost-mobile">Mattermost app</a> - A real world app, with complex interactions, layouts and functionality used regularly by many people, but for business reasons. </li>
</ol>
All these apps needed to be open source for me to be able to modify their source code, and for others to be able to run the tests.<br />
<br />
<h4>
<u>Test Scenario</u></h4>
Cold Start was the only scenario tested to get metrics like cold start time, memory consumption, APK size and the entire startup timeline. Scenarios like animations, scroll perf and navigation have dependencies on the native environment, and may not be a good for testing different JavaScript engines.<br />
<br />
<h4>
<u>Setup </u></h4>
<u><b>Upgrade to 0.60</b></u>: At the time of testing, ChainReact and MatterMost were not on React Native 0.60. The first order of business was to upgrade them to the latest version. React Native 0.60 for Android comes with non trivial changes (like AndroidX), and automated scripts were used to facilitate the upgrade. Commits for the upgrade are available in <a href="https://github.com/nparashuram/ChainReactApp2019/commit/40b121042a51f85307cf4b05a9fc23d98e5c29a4">ChainReact</a> and <a href="https://github.com/nparashuram/mattermost-mobile/commit/1105b27e3c905ef9063224ae8a79e85b189fa6ad">Mattermost</a> repo forks. <br />
<br />
<b><u>Adding Instrumentation:</u> </b>Instrumentation was to both the apps, to get data points on the Java start up path, as well as the mount times for components. Instrumentation was added based on a <a href="http://blog.nparashuram.com/2018/11/react-native-performance-playbook-part-i.html">previous blog post</a> and the performance data was sent to a server running on port 3000. This work is available as commits in <a href="https://github.com/nparashuram/ChainReactApp2019/commit/b9633cdf8e4cd5c65807c5200e910e2cf3be494d">ChainReact</a> and <a href="https://github.com/nparashuram/mattermost-mobile/commit/e9058e805d0bc4f79c314aef2277d73670249c6f">MatterMost</a> repo forks. <br />
<br />
<b><u>Network Isolation:</u></b> To remove flakiness due to network, the networking module was overridden with an <a href="https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.Builder.html#proxy-java.net.Proxy-">OKHTTP point to a proxy</a>. The proxy saves all responses needed for TTI and replays them with equal delays for all tests. <br />
<br />
<b><u>Test Script:</u> </b>The tests were run 100 times on an Android Pixel device for each app, for each engine. The tests were automated, and the app was launched using intents. The test concluded when the instrumentation server received data. The script would then run <span style="font-family: "courier new" , "courier" , monospace;">adb shell dumpsys meminfo</span> to understand the memory usage.<br />
<br />
<h4>
<u>
Results</u></h4>
Of the 100 iterations, the 75th percentile TTI was chosen, and here are the results. <br />
<br />
<h3>
Mattermost Mobile App</h3>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://code.fb.com/wp-content/uploads/2019/07/hermesstats-1.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="443" data-original-width="800" height="353" src="https://code.fb.com/wp-content/uploads/2019/07/hermesstats-1.jpg" width="640" /></a></div>
These were the numbers shown at Marc's keynote, and compared JSC and Hermes.<br />
<ul>
<li>TTI Traces - <a href="https://nparashuram.github.io/mattermost-mobile/jsc/trace-jsc.html">JSC</a> vs <a href="https://nparashuram.github.io/mattermost-mobile/hermes/trace-hermes.html">Hermes</a></li>
<li>Memory Usage - <a href="https://nparashuram.github.io/mattermost-mobile/jsc/mem-jsc.txt">JSC</a> vs <a href="https://nparashuram.github.io/mattermost-mobile/hermes/mem-hermes.txt">Hermes</a></li>
<li>APK Size - <a href="https://nparashuram.github.io/mattermost-mobile/jsc/size-jsc.html">JSC</a> vs <a href="https://nparashuram.github.io/mattermost-mobile/hermes/size-hermes.html">Hermes </a></li>
</ul>
Looking at the traces, we can see that both cases had similar amount of work done during the initial phases when the Java code executes. The divergence is visible when React Native is executed and further visible as React runs the reconciliation to mount components.<br />
The APK size links also show the tree maps of sizes, and the large difference can be attributed to the fact that Mattermost needed to use the "intl" version of JSC.<br />
<br />
<h3>
ChainReact App</h3>
The Chain React app was tested across the three VMs (V8, JSC and Hermes), and here are the results from the 75th percentile.<br />
<br />
<br />
<center>
<blockquote class="twitter-tweet" data-theme="light">
<div dir="ltr" lang="en">
Did someone say they wanted to try out <a href="https://twitter.com/HermesEngine?ref_src=twsrc%5Etfw">@HermesEngine</a> ? Well, there is a build of the <a href="https://twitter.com/ChainReactConf?ref_src=twsrc%5Etfw">@ChainReactConf</a> conference app, running on new engine !! <a href="https://t.co/gYsBEY8WRd">pic.twitter.com/gYsBEY8WRd</a></div>
— Parashuram (@nparashuram) <a href="https://twitter.com/nparashuram/status/1149359709943500800?ref_src=twsrc%5Etfw">July 11, 2019</a></blockquote>
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script> </center>
The APK Size, timeline and memory usage can be found in <a href="https://nparashuram.github.io/ChainReactApp2019/">this list</a>. Similar to the mattermost app, the timelines diverge during the JavaScript execution phase. The APK size is also different, primarily due to the engine embedded.<br />
<br />
<h4>
<u>Conclusion</u></h4>
While I have tried to make the tests representative of real world apps, I would highly recommend instrumenting and testing your own apps for results and pick the right JavaScript engine for your React Native app. V8 supports snapshots, and JSC just landed the ability to have bytecode, and I am working on adding those variations to the tests too. <br />
I am also working on getting Hermes working with the <a href="https://github.com/Kudo/react-native-js-benchmark">react-native-js-benchmark</a>. In the meantime, here are some ideas that you could use to improve the performance of your React Native app. <br />
<br />
<br />
<center>
<blockquote class="twitter-tweet">
<div dir="ltr" lang="en">
Slide-Tweets from my talk about <a href="https://twitter.com/reactnative?ref_src=twsrc%5Etfw">@reactnative</a> performance. Hoping that this would help people fix perf issues in their apps<br />
<br />
Here is a summary of the different things i spoke about. <a href="https://t.co/RnLPbmiJgT">pic.twitter.com/RnLPbmiJgT</a></div>
— Parashuram (@nparashuram) <a href="https://twitter.com/nparashuram/status/1149734259751473152?ref_src=twsrc%5Etfw">July 12, 2019</a></blockquote>
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script> </center>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-24984051236036712232019-04-30T07:00:00.002-07:002019-07-14T23:20:35.762-07:00Building React Native<div style="text-align: center;">
React Amsterdam, April 10-12, 2019, Kromhouthal, Amsterdam
<br /></div>
<h3 style="text-align: center;">
Building React Native
</h3>
<div style="text-align: center;">
</div>
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/5sQw8C36Xa4" width="100%"></iframe>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-35109563990376258072019-04-23T11:25:00.000-07:002019-04-23T11:50:07.680-07:00Lazy Native Modules - React Native (Android)In a <a href="http://blog.nparashuram.com/2018/11/react-native-performance-playbook-part-i.html">previous post</a>, I wrote about leveraging React Native's built in instrumentation to understand the startup path for React Native apps. Armed with this data, we can start optimizing the various segments of the timeline that corresponding to loading React Native.<br />
<blockquote class="tr_bq">
<b><i>Target: This post documents ideas to improve startup times for applications that have a many native modules.</i></b></blockquote>
<h3>
Background</h3>
<a href="https://facebook.github.io/react-native/docs/native-modules-setup">Native Modules</a> enable JavaScript to call methods in Java or ObjectiveC and React Native's vibrant ecosystem has native modules for most scenarios an app would need. Installing native code is as simple as running <span style="font-family: "courier new" , "courier" , monospace;">npm install</span> and <span style="font-family: "courier new" , "courier" , monospace;">react-native link</span>. Consequently, many apps eventually start building up a large registry of these modules. <br />
Though many native modules are used much later during the lifetime of
the app, the setup today initializes all of them as soon as the user
starts the application. Moving this initialization closer to when the module is actually used can help speed up the startup time of React Native apps.<br />
<br />
<h3>
Adding Native Modules today</h3>
To add a native module today, most people use the convenience provided by react-native link. In addition to modifying the Gradle file, it also updates <span style="font-family: "courier new" , "courier" , monospace;">MainApplication.java</span> to initialize the module. For example, when the <a href="https://github.com/react-native-community/react-native-device-info">DeviceInfo Module</a> is added using <span style="font-family: "courier new" , "courier" , monospace;">react-native link</span>, the function with list of packages in the file looks as follows. <br />
<br />
<pre style="background: #ffffff; color: black;"><span style="color: #7f9fbf; font-weight: bold;">@Override</span>
<span style="color: maroon; font-weight: bold;">protected</span> List<ReactPackage> getPackages() <span style="color: purple;">{</span>
<span style="color: maroon; font-weight: bold;">return</span> <span style="color: #bb7977; font-weight: bold;">Arrays</span><span style="color: #808030;">.</span><span style="color: #808030;"><</span>ReactPackage<span style="color: #808030;">></span>asList<span style="color: #808030;">(</span>
<span style="color: maroon; font-weight: bold;">new</span> MainReactPackage<span style="color: #808030;">(</span><span style="color: #808030;">)</span>
<span style="background-color: lemonchiffon;"><span style="color: maroon; font-weight: bold;">new</span> RNDeviceInfo<span style="color: #808030;">(</span><span style="color: #808030;">)</span></span>
<span style="color: #808030;">)</span><span style="color: purple;">;</span>
<span style="color: purple;">}</span>
</pre>
<!--Created using ToHtml.com on 2019-04-23 04:56:57 UTC -->
<br />
<br />
This way of initialization not only "classloads" RNDeviceInfo, but also invokes the constructor. As it turns out, the device info module also <a href="https://github.com/react-native-community/react-native-device-info/blob/1042169a86d3abb8c6b0e85b431bbdfc6144ac13/android/src/main/java/com/learnium/RNDeviceInfo/RNDeviceModule.java#L59">performs some non-trivial computations</a> which adds up to the startup time of the app. <br />
<br />
<h3>
Opportunities for Optimization</h3>
<ol>
<li>During startup, React Native does not really need to full module, it just needs to know the name of the module and a few other details so that the module can be <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java#L133,L134">added it to a list</a>. When we call <span style="font-family: "courier new" , "courier" , monospace;">require('react-native-device-info')</span> in our code, it still does not an instance of the module, but just the l<a href="https://github.com/facebook/react-native/blob/c9c8f8d5b33716da50060dc23a591cb813157098/ReactCommon/cxxreact/ModuleRegistry.cpp#L81">ist of methods and their signatures</a>. The actual module needs to be constructed when only one of the methods is actually called.</li>
<li>Additionally, the open source structure of native modules dictates all modules to be <a href="https://facebook.github.io/react-native/docs/0.58/native-modules-android#register-the-module">wrapped in React packages</a> even if they don't provide ViewManagers or JavaScript modules, adding an extra layer of abstraction.</li>
</ol>
<br />
<h3>
Lazy React Packages</h3>
By wrapping the constructor using a Java <a href="https://docs.oracle.com/javaee/6/api/javax/inject/Provider.html">Provider</a>, we still set the native module without invoking the constructor. This can be achieved by using <a href="https://github.com/facebook/react-native/blob/7e9d6ea51dbdfb0bc3e0f589c84564a6cb838a1c/ReactAndroid/src/main/java/com/facebook/react/LazyReactPackage.java">LazyReactPackage</a> instead of the default ReactPackage.<br />
An example using this provider pattern would be <a href="https://github.com/facebook/react-native/blob/1ca9a9553763a89c977f756b45486f8b9cedab80/ReactAndroid/src/main/java/com/facebook/react/shell/MainReactPackage.java#L120,L124">MainReactPackage</a>. To adopt this to our applications, we would reach into the native module and add the class extending from <span class="pl-e"><a href="https://github.com/facebook/react-native/blob/1ca9a9553763a89c977f756b45486f8b9cedab80/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactContextBaseJavaModule.java">ReactContextBaseJavaModule</a> in a list wrapped in LazyReactPackage. </span><br />
<span class="pl-e">Note that when using LazyReactPackage, we still need to provide additional information about that native module that is otherwise obtained from evaluating the module. Hence, we have the method to getReactModuleInfos, that supplies additional information like class name, module name, is it a C++ module, can it be overridden, etc. This information can either be hand crafted as in the example, or generated using a pre-processing step in <a href="https://github.com/facebook/react-native/blob/7e9d6ea51dbdfb0bc3e0f589c84564a6cb838a1c/ReactAndroid/src/main/java/com/facebook/react/module/processing/ReactModuleSpecProcessor.java">ReactModuleSpecProcessor</a> if integrated into the build system. </span><br />
<br />
<h3>
<span class="pl-e">Turbo React Packages</span></h3>
Even if the above method of Lazy React Package does not call the constructor, it still ends up creating anonymous classes due to the providers. In a large. multi-dex app, it will also perform classloads for the native modules at startup. We can eliminate these side effects using a TurboReactPackage and using the <a href="https://bitbucket.org/axemclion/react-native-example-lazy-native-modules/src/c0362ec69983584e62b2651d58aa093654590f34/android/app/src/main/java/com/rn_nm_perf/MainApplication.java?at=master&fileviewer=file-view-default#MainApplication.java-43:48">getModule method</a> that returns the native module given the name. <br />
<a href="https://bitbucket.org/axemclion/react-native-example-lazy-native-modules/src">This project</a> has a full React Native application that uses this pattern to make module loading fast. It is also instrumented with ReactMarkers, and can show that the PROCESS_PACKAGES step is now a fraction of the original time during startup.<br />
This package is also a step torwards the new <a href="http://blog.nparashuram.com/2019/01/react-natives-new-architecture-glossary.html#turbomodules">TurboModule architecture</a>, where JavaScript can get a native module by its name.<br />
<i><b>I would recommend using <span style="font-family: "Courier New", Courier, monospace;">TurboReactPackage</span> when adding native modules. </b></i><br />
<br />
<h3>
Fast by Default</h3>
React Native already supports <span style="font-family: "Courier New", Courier, monospace;">LazyReactPackage</span> and the newer <span style="font-family: "Courier New", Courier, monospace;">TurboReactPackage</span> today. <br />
To make this work with <span style="font-family: "Courier New", Courier, monospace;">react-native link</span> today, the following changes would be needed.<br />
<br />
<ol>
<li>If the native modules does not have View Managers or JSModules, don't add the Package that is exposed</li>
<li>Instead look for the class that eventually extends ReactContextBaseModule and add that to a list maintained in MainApplication</li>
<li>Generate the meta data needed for <span style="font-family: "Courier New", Courier, monospace;">ReactModuleInfo</span> in the same package, so that we have all the information without having to evaluate the actual package. </li>
</ol>
<br />
To prevent breaking changes, we could use a flag to specify that we want to use this new way of adding native modules to newer projects.<br />
These techniques can already be used in hybrid apps since they don't use react-native link anyway. We could switch <span style="font-family: "Courier New", Courier, monospace;">ReactPackage</span> to use <span style="font-family: "Courier New", Courier, monospace;">TurboReactPackage</span> and change the methods to take advantage of the performance savings. <br />
<br />
<h3>
More Optimizations</h3>
Even if we defer loading native modules, some native modules are called during the startup process. The JavaScript thread pauses while this call happens. By making native modules lazy, we would end up making JavaScript wait longer as the native module is initialized before the actual call. For native modules that area part of startup, we could still initialize them in a separate thread in parallel to when JavaScript is being parsed. <br />
We can simply spawn a new thread and call <a href="https://github.com/facebook/react-native/blob/7e9d6ea51dbdfb0bc3e0f589c84564a6cb838a1c/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java#L426">CatalystInstance.getModule(moduleName)</a> which initializes the modules in a <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java#L127,L139">thread safe way</a>.<br />
<br />
<h3>
Next steps</h3>
In a follow up post, I plan to write about optimizing that first network call, and adding custom loading state before the first React Native screen shows up. In the meantime, ping me on twitter for questions on this post, or your comments on if you were able to use this in your application. axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-64433632852903675862019-01-15T10:36:00.003-08:002019-04-23T11:01:22.381-07:00React Native's new architecture - Glossary of termsAs the React Native team is working on the <a href="http://blog.nparashuram.com/2018/11/react-native-road-map.html">new architecture</a>, there have been a few terms used to describe the various pieces. This post aims to clarify some of the terms and points to places in the repository with relevant code. <br />
<br />
<h3 id="bridge">
The Bridge</h3>
In the current architecture of React Native, the communication between JavaScript and Java/ObjC happens over "the bridge".<br />
<ul>
<li>This bridge is a queue to send messages encoded as JSON strings between JavaScript and Java/ObjC. During every tick, we dequeue messages from the front of the queue and process them. This way of messaging is fundamentally asynchronous. </li>
<li>The bridge also exposes an interface for Java/ObjC to schedule
JavaScript execution, typically used for callbacks from Native Modules.</li>
<li>The bridge is also tied to the lifecycle of React Native. Starting or stopping React Native usually means that the bridge is initialized or torn down. </li>
</ul>
To explore the bridge in more concrete terms, we can install a <a href="https://gist.github.com/axemclion/2f47ba4a5e2190eaf32eeb9e80cefcd5">MessageSpy</a> to look at the exact bytes that are sent back and forth. Also note that while the bridge is async, we can use<span style="font-family: "courier new" , "courier" , monospace;"> </span><span style="font-family: "courier new" , "courier" , monospace;"><span class="pl-k">@ReactMethod</span>(<span class="pl-c1">isBlockingSynchronousMethod</span> <span class="pl-k">=</span> <span class="pl-c1">true</span>)</span>for one-off <a href="https://github.com/facebook/react-native/blob/803e993e6a8e68c62870e27ce4a45b485e244ec4/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMethod.java#L38">synchronous method</a> calls.<br />
While this asynchronous communication is great in most cases, there are certain use cases where we would prefer JavaScript to draw views on the screen synchronously; a problem that the new architecture aims to solve.<br />
<br />
<h3 a="" href="https://en.wikipedia.org/wiki/Remote_procedure_call" id="jsi>
JavaScript Interface (JSI)</h3>
Instead of using the bridge for queuing messages, the new architecture allows us to directly " invoke="" think="">
RPC</h3>
) Java/ObjC methods.<br />
An analogy would be how we call DOM methods from JavaScript in the browser. For example, in the statement <span style="font-family: "courier new" , "courier" , monospace;">var el = document.createElement('div');</span> the variable <span style="font-family: "courier new" , "courier" , monospace;"><b>el</b></span> holds a reference not to a JavaScript object, but to an object that was possibly instantiated in C++. When JavaScript calls <span style="font-family: "courier new" , "courier" , monospace;">el.setAttribute('width', 100)</span>, we end up synchronously invoking the <span style="font-family: "courier new" , "courier" , monospace;">setWidth</span> method in C++ that changes the actual width of that element.<br />
In React Native, we can similarly use the JavaScript interface to invoke methods on UI Views and Native Modules that are implemented in Java/ObjC. <br />
The snippet below shows a simple usage of JSI and how we could expose Java/ObjC objects to JS. <br />
<br />
<br />
<script src="https://gist.github.com/axemclion/e7faeb4ee9d89832040e96d6837b269d.js"></script>
<br />
Most of the code for JSI resides in the <a href="https://github.com/facebook/react-native/tree/master/ReactCommon/jsi">jsi folder</a> in React Native and is written in C++.<br />
<br />
<h3 id="fabric">
Fabric</h3>
Fabric was the first part of the re-architecture that was announced. While it only deals with the user interface of the new architecture, it is sometimes wrongly used to refer to the entire re-architecture work. <br />
In the current architecture, all UI operations (like creating native views, managing children, etc). are handled by a native module called <a href="https://github.com/facebook/react-native/blob/a689711f680bb23795dea6391627383ca6973f88/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java">UIManagerModule</a>. The React Reconciller sends UI commands over the bridge, which are eventually handled by this module and delegated to <a href="https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIImplementation.java">UIImplementation</a>. This in turn creates <a href="https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/ReactAndroid/src/main/java/com/facebook/react/uimanager/ReactShadowNode.java">shadow nodes</a> that represent the layout tree and are passed to Yoga to determine the relative co-ordinates based on the Flex box styles that are passed in from JS. <br />
In the new system, the UI operations are <a href="https://github.com/facebook/react-native/blob/c30c803b89be8ef03403314702bf9ec439e6d9ce/ReactCommon/fabric/uimanager/UIManagerBinding.cpp">directly exposed to JavaScript</a> as functions using the JSI interface described above. The new <a href="https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/ReactCommon/fabric/uimanager/FabricUIManager.cpp">UI manager</a> can then create <a href="https://github.com/facebook/react-native/blob/master/ReactCommon/fabric/core/componentdescriptor/ComponentDescriptor.h">ComponentDescriptors</a> and the Shadow Nodes for specific view types (like Text, View or Images), and then communicate with Java/ObjC to draw platform specific UI.<br />
<br />
<h3 id="turbomodules">
TurboModules </h3>
The JSI system can also be used to call leverage device capabilities like bluetooth or other sensors by exposing functions that JS can call. This is similar to how browsers expose functions like <span style="font-family: "courier new" , "courier" , monospace;">navigator.geolocation.getCurrentPosition</span> that, when invoked in JavaScript, trigger the respective C++ call in the browser. <br />
In the current system, a <a href="https://github.com/facebook/react-native/blob/1151c096dab17e5d9a6ac05b61aacecd4305f3db/ReactCommon/cxxreact/ModuleRegistry.cpp#L70">table with information about module</a> names and methods is created. When JS calls a specific native module, the indices of the module and methods are passed to Java/ObjC, which then <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/jni/react/jni/MethodInvoker.cpp#L182">invoke the specific methods</a>. The arguments and return values are also <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/Arguments.java">converted</a> between JavaScript and JNI/ObjC objects.<br />
In the new system,<br />
<ol>
<li>We expose a <a href="https://github.com/facebook/react-native/blob/7fbccdea22993b56988685174492583b16dc69db/ReactCommon/turbomodule/core/TurboModuleBinding.cpp#L25">JSI object</a> a top level "Native Module Proxy", called <span style="font-family: "courier new" , "courier" , monospace;">global.__turboModuleProxy</span>. </li>
<li>To access a native module, say SampleTurboModule, application code will then call in <span style="font-family: "courier new" , "courier" , monospace;">require('NativeSampleTurboModule')</span>. </li>
<li>Inside NativeSampleTurboModule.js, we call <a href="https://github.com/facebook/react-native/blob/7fbccdea22993b56988685174492583b16dc69db/Libraries/TurboModule/TurboModuleRegistry.js#L28">TurboModuleRegistry</a><a href="https://www.blogger.com/null">.getEnforcing()</a> which then calls the <span style="font-family: "courier new" , "courier" , monospace;">global.__turboModuleProxy("SampleTurboModule")</span></li>
<li>Calling <span style="font-family: "courier new" , "courier" , monospace;">global.__turboModuleProxy </span>function triggers the JSI function that we exposed in Step 1. This is where the platform divergence happens.</li>
<li><span style="font-family: "courier new" , "courier" , monospace;"></span>We invoke a <a href="https://github.com/facebook/react-native/blob/7fbccdea22993b56988685174492583b16dc69db/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp#L56">getModule</a> function that is defined for Java and ObjC. This function takes in a string, and returns a JSI object for the specific <a href="https://github.com/facebook/react-native/blob/master/ReactCommon/turbomodule/core/TurboModule.cpp">TurboModule</a>.</li>
<li>To get a TurboModule JSI object, we first get the Java/ObjC <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java#L51">implementation</a> and then <a href="https://github.com/facebook/react-native/blob/7fbccdea22993b56988685174492583b16dc69db/ReactCommon/turbomodule/core/platform/android/JavaTurboModule.cpp">create JSI object</a> from it. </li>
</ol>
Now that we have a JSI object for "SampleTurboModule", can invoke methods on this JSI object from JavaScript. During the calls, we also need to convert JSI Values to JNI for argument parameters, and the reverse when sending back results.<br />
Like in the current architecture, most types including boolean, strings, Maps, Arrays, Callbacks and Promises are supported.<br />
<br />
<br />
<h3>
CodeGen</h3>
In both TurboModule and Fabric, interface available to JavaScript could be defined using <a href="https://github.com/facebook/flow">Flow</a> (or TypeScript). We can further leverage this interface definition to generate many of the C++ classes, and the interfaces/protocols for Java/ObjC implementations. For example, in case of TurboModules, the C++ class that wraps the Java/ObjC class and exposes the methods using a JSI object can be generated. <br />
This will ensure that all JavaScript calls have implementations available on the native side, and will continue to ensure this with over the air updates like code push. <br />
<br />
<h3>
Conclusion</h3>
In terms of backward compatibility, most of the JavaScript application code does not have to change as a result of the new architecture. The Java/ObjC code written for custom View Managers or Native Modules will have to change, but many of them can be code-modded to use the new system. A compatibility layer can also be written that will let custom View Managers and Native Modules to continue working in the new system.<br />
In terms of timelines, most of the JSI code has already landed in the repository at the time of writing this post. A lot of the Fabric code is also in the repository, and updates to TurboModules continue to roll out. Since this is a mostly backward compatible, there does not have to be a single date of release, but more of a gradual rollout. You can follow the React Native repository, and the issues about <a href="https://github.com/react-native-community/discussions-and-proposals/issues/4">Fabric</a> and <a href="https://github.com/react-native-community/discussions-and-proposals/issues/40">TurboModules</a> for updates. axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-41586422945146906322018-12-03T10:17:00.000-08:002018-12-03T10:29:10.568-08:00Using React Native's Plugins with Flutter (Android version)<a href="https://flutter.io/">Flutter</a> allows you to build beautiful native apps on iOS and Android from a single codebase. Like most cross-platform mobile application development frameworks, platform specific APIs and device capabilities are exposed to the developer environments using <a href="https://flutter.io/docs/development/packages-and-plugins/developing-packages#developing-plugin-packages">plugins</a>.<br />
<a href="https://facebook.github.io/react-native/">React Native</a>, another framework to build mobile apps using JavaScript and React, also has a similar concept, called <a href="https://facebook.github.io/react-native/docs/native-modules-ios">Native Modules</a>.<br />
<br />
<h4>
Native SDKs for Hybrid Frameworks</h4>
React Native has been around for a while and in addition to the
numerous packages created by the community, companies also expose their
services (think <a href="https://medium.com/square-corner-blog/square-reader-sdk-for-react-native-a1b6fc19c5c2">Square</a>, <a href="https://facebook.github.io/react-native/blog/2018/03/05/AWS-app-sync">AWS</a>, <a href="https://documentation.onesignal.com/docs/react-native-sdk-setup">OneSignal</a>, <a href="https://www.mapbox.com/help/first-steps-react-native-sdk/">MapBox</a>, <a href="https://github.com/urbanairship/react-native-module">UrbanAirShip</a>) to React Native apps using native modules. However, many services are only available as iOS and Android SDKs; developers building on the newer hybrid frameworks usually are left to create their own adapters.<br />
I ran into this problem a few years ago when I was porting my <a href="https://cordova.apache.org/">Cordova</a> app to the still new React Native framework. While all the Cordova plugins in my app were well supported first-party or community modules, none of them had existed for React Native back then. Instead of re-implementing every module, I explored the idea of creating an adapter to use <a href="http://blog.nparashuram.com/2015/10/using-cordova-plugins-in-react-native.html">Cordova Modules in a React Native</a> application.<br />
The share of Android and iOS apps are still significantly higher and creating an adapter for every hybrid framework like <a href="https://cordova.apache.org/">Cordova</a>, <a href="https://visualstudio.microsoft.com/xamarin/">Xamarin</a>, <a href="https://www.nativescript.org/">NativeScript</a>, <a href="https://facebook.github.io/react-native/">React Native</a> and <a href="https://flutter.io/">Flutter</a> may be too much work. Having been a Cordova committer, worked in a team adjacent to Xamarin, studied NativeScript and now contributing to React Native, I believe that the patterns for invoking native modules in all these hybrid frameworks may be similar enough to be able to create a "universal" system. By simply defining a "cross-platform" API and using a system of adapters, SDKs may be able to support all hybrid frameworks well. <br />
<br />
<h4>
React Native to Flutter</h4>
The promise of write-once-run-everywhere has historically been perilous, and it may would help to take smaller baby steps. As a start, I tried the approach to use native modules from React Native in my Flutter app; a port that was surprisingly simple.<br />
Plugins can be bootstrapped using Flutter's CLI that <a href="https://flutter.io/docs/development/packages-and-plugins/developing-packages#step-1-create-the-package-1">generates</a> both the dart file and the corresponding Java code. The <span class="pl-en"><span style="font-family: "courier new" , "courier" , monospace;">onMethodCall</span> function in Java has an if-else condition that is responsible for executing the right method that the application code in dart invokes. <br />In React Native, methods exposed to JavaScript are annotated with <span style="font-family: "courier new" , "courier" , monospace;">@<a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactMethod.java">ReactMethod</a></span>. When the native modules is "required" in JavaScript, the methods on the module are <a href="https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaModuleWrapper.java#L73">discovered using reflection</a>. We can use the same method to use React Native modules in Flutter. </span><br />
<span class="pl-en"><a href="https://gist.github.com/axemclion/0413850124d3fd2939dcb285dabbadc9">For the demo</a>, we use the <a href="https://facebook.github.io/react-native/docs/native-modules-android#the-toast-module">ToastModule</a> that is also used as an example in the React Native documentation. We lazily create a map of string method names to the actual implementation and invoke it when dart calls the method. </span>
<br />
<blockquote class="twitter-tweet" data-conversation="none" data-lang="en">
<div dir="ltr" lang="en">
Here is React Native's Toast Module working in the Flutter app. Next up, re-create RN's native module playground in Flutter :P <a href="https://t.co/nr6aa3h8NN">pic.twitter.com/nr6aa3h8NN</a></div>
— Parashuram (@nparashuram) <a href="https://twitter.com/nparashuram/status/1069426280523694080?ref_src=twsrc%5Etfw">December 3, 2018</a></blockquote>
The only challenge is that most of the native modules refer to other React Native bridge classes, many of which we would have to import or stub out. In this case, we simply had to stub out most of the classes.<br />
Additionally, in production, we would not discover the methods at runtime, but would instead generate the <span class="pl-en"><span style="font-family: "courier new" , "courier" , monospace;">onMethodCall </span></span>if-else at compile time to call the appropriate React Native methods. <br />
<br />
<h4>
The Universal Modules System</h4>
<br />
While the above method is not perfect, it does get existing React Native modules to work with Flutter. Ideally, we would not need the reflection and instead just have a "universal" interface that can generate plugins for Flutter, React Native and other hybrid systems.<br />
Service SDKs could simply define something like a Typescript file containing the individual method, their arguments and return types that map to the iOS and Android SDKs and the entire plugin code could be generated. Note that TurboModules will use this code generation approach, with the source of truth for the API being in JavaScript. This method would also eliminate the React Native specific code present in all the dependencies. <br />
<br />
As I was working on this, <a href="https://twitter.com/sjchmiela">Stanisław Chmiela</a> pointed out the <a href="https://t.co/0uRXfP9ly4">work that Expo has been doing</a> in this area. The video does talk of a "Swagger like" API definition for the interfaces. It works with React Native, with an unreleased implementation for Flutter. Extending it to Cordova or NativeScript should not be very hard either. <br />
<br />
Though this is still pretty early, I believe that this idea of a universal module system does hold promise and could help ensure that native modules in all the hybrid frameworks are well maintained, and get the same amount of attention that native iOS or Android SDKs get. <br />
<br />
<script async="" charset="utf-8" src="https://platform.twitter.com/widgets.js"></script>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-23546287047873083002018-11-27T11:17:00.000-08:002018-11-27T11:17:00.536-08:00React Native Performance Playbook - Part I<h3 style="text-align: left;">
<i>
Getting Ready - Setting Up Instrumentation</i></h3>
<br />
Over the last six months, I have been working on improving the performance of React Native. I specifically focussed on the startup time in Android brownfield apps and we were able to reduce the time by half. Even as we wait for the new UI architecture (<a href="https://github.com/react-native-community/discussions-and-proposals/issues/4">Fabric</a>) and synchronous native modules (<a href="https://github.com/react-native-community/discussions-and-proposals/issues/40">TurboModules</a>) to rein in significant performance wins, there are many low hanging fruits that could be leveraged today to improve performance<b><br /></b><br />
In this series of blog posts, I wanted to outline some of the work we did and how they could apply to your mobile apps. <br />
<h4>
Background</h4>
When working on performance, it is easier to focus on a well defined scenario, and then apply the lessons in a broader context. Android startup time in React Native apps is a common source of pain and makes for a good candidate for this blog post. To define it more specifically<br />
<ul>
<li>The scenario starts with the <span style="font-family: "courier new" , "courier" , monospace;">onCreate</span> of the application.Though there is a is non-trivial amount of work done from when the user clicks the icon to the <span style="font-family: "courier new" , "courier" , monospace;">onCreate</span>, it is not React Native specific. General Android optimizations will help. </li>
<li>The scenario ends when the application loads and the user can interact with it. This metric, also called Time-To-Interaction (TTI), is app specific and needs to be defined in the application code, as explained later. </li>
</ul>
Before we jump into optimizing code, we will need to setup instrumentation to understand the application startup time better. This will help us identify the areas that warrant a deeper dive and will validate any code changes that we make later. <br />
We will look at collecting data from production as it better represents the behavior of the app in the real world. We can always augment this with local <a href="https://facebook.github.io/react-native/docs/performance#profiling">profiling</a> tools that are available to React Native apps.on local builds. <br />
<br />
<h4>
From React Native</h4>
React Native already has markers indicating the various steps during the startup process. By adding listeners to the events from ReactMarker, we can report back all the information that the framework gives us during startup.<br />
<ol>
<li>Copy the contents of the file <a href="https://gist.github.com/axemclion/f01cbb32fcb5b14bf6b4fd4594192825#file-perflogger-java"><span style="font-family: "courier new" , "courier" , monospace;">PerfLogger.java</span></a> to your app's <span style="font-family: "courier new" , "courier" , monospace;"><app_root>/android/app/src/main/java/com/nparashuram/PerfLogger.java</span>. This file adds a listener to <span style="font-family: "courier new" , "courier" , monospace;">ReactMarker</span>, and stores the performance events with Thread IDs and time stamps.</li>
<li>In your application's <span style="font-family: "courier new" , "courier" , monospace;">MainApplication.java</span>, look for the <span style="font-family: "courier new" , "courier" , monospace;">onCreate</span> method, and initialize the PerfLogger just after the <span style="font-family: "courier new" , "courier" , monospace;">super.onCreate()</span>; line using this - <span style="font-family: "courier new" , "courier" , monospace;">new PerfLogger(getReactNativeHost()).initialize()</span>; </li>
</ol>
<h4>
</h4>
<h4>
Defining end of TTI</h4>
Now that we have started collecting the performance markers, we also need to define when to stop recording. For this blog post, we defined the "end of startup" to be when content is rendered on the screen and the user can interact with it. <br />
This is usually application specific. Some applications would immediately render content while others may have to show a loading screen, perform a network request and then display the response. In either case, you can distill "loading-complete" down to the appearance of a specific React component on the screen. <br />
Add a prop <span style="font-family: "courier new" , "courier" , monospace;"><a href="https://facebook.github.io/react-native/docs/view#nativeid">nativeID</a>="tti_complete"</span> to that element. For example, if we are displaying a feed, the last View on the feed could be <span style="font-family: "courier new" , "courier" , monospace;"><View nativeID="tti_complete"></span>. <br />
The <span style="font-family: "courier new" , "courier" , monospace;">PerfLogger java</span> code waits for the native UI element with the nativeID to be drawn, and then makes all performance data available to your JavaScript code.<br />
<br />
<h4>
The JavaScript code</h4>
On the JavaScript side, include <a href="https://gist.github.com/axemclion/f01cbb32fcb5b14bf6b4fd4594192825#file-perf-js">perf.js</a> in your application code. When <span style="font-family: "courier new" , "courier" , monospace;">PerfLogger.java</span> sees that TTI is complete, it populates a global JS variable with all the data, which can then be sent to a server.<br />
A significant portion of startup also includes the execution of JS code. You could use the <a href="https://gist.github.com/axemclion/f01cbb32fcb5b14bf6b4fd4594192825#file-perf-js-L172">ComponentLogger</a> defined in <span style="font-family: "courier new" , "courier" , monospace;">perf.js</span> to mark the start and stop of mounting components. We would typically start with large sections on the UI, and add wrap more components as we want to get more fine grained data. Since this is also pure JS code, you could experiment with various
combinations and iterate fast using over the air updates like code push.<br />
This component simply wraps your component and stores timestamps for them.<br />
The <span style="font-family: "courier new" , "courier" , monospace;">perf.js</span> file also converts this data to a format that can be loaded in chrome://tracing and sends it to a server after a timeout. In the real world, the data should be sent in the same way any other analytics information is sent. <br />
<br />
<h4>
<span style="font-family: inherit;">Analyzing the data</span></h4>
Once we start getting data from production, we can start looking at data from individual traces. Note that using averages here may not help since averages of the ranges do not add up. Instead, we could pick a trace that represents a certain percentile. For example, if our goal is to make our app load in under 1 second for the 75th percentile, we could pick the trace representing P75. <br />
The tracing file can be loaded in chrome://tracing to drill deeper into individual sections. For this post, I looked at the <a href="https://github.com/mattermost/mattermost-mobile">MatterMost app</a>, and here is how a sample trace may look.<br />
<br />
<img alt="" class="media-image" data-height="862" data-width="2047" src="https://pbs.twimg.com/media/Dsygw97UwAAPkPq.jpg:large" style="height: 340px; margin-top: 0px; width: 800px;" /><br />
<br />
Since we also collect thread information, we can see the four threads on which React Native runs. To differentiate React Native code from application logic, I just made that a separate Process 0 at the very top. Note how we record both the loading screen, and the actual content that is rendered, before marking TTI complete.<br />
<br />
<h4>
</h4>
<h4>
Next Steps</h4>
In the next part of this series, we will look at how we can use this data to start optimizing sections. I would like to base the post on real data, so if you were able to collect this information, Contact me <a href="http://twitter.com/nparashuram">@nparashuram</a> I would love to analyze it and talk about the parts we should optimize. axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-5841533512640456192018-11-21T08:01:00.002-08:002018-11-21T08:01:19.087-08:00React Native Road MapAt ReactConf 2018 (October 25-26, 2018) at Henderson, Nevada, I spoke about React Native's new architecture covering the JavaScript interface (JSI), UI re-architecture (called Fabric) and the new native module system (called TurboModules). <br />
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/UcqRXTriUVI" width="100%"></iframe>
<br />
I dove into more details and added a little bit of "Star Wars fun" on the same topic at React Next (Nov 4, 2018) at Tel Aviv, Israel.<br />
<br />
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/FX_WBhuioGo" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-66676594118386465412018-07-27T10:15:00.001-07:002018-07-27T10:18:02.714-07:00Chain React 2018 - React Native Fabric ArchitectureChain React Conference 2018, July 11-13 2018, Portland OR<br />
<br />
Topic: React Native's new Fabric renderer<br />
<br />
<br />
<iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/83ffAY-CmL4" width="100%"></iframe>
<br />
Link to slides - <a href="https://www.slideshare.net/axemclion/chain-react-2018-the-state-of-react-native">https://www.slideshare.net/axemclion/chain-react-2018-the-state-of-react-native</a>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-56018951120131437312018-07-06T09:25:00.003-07:002018-07-06T09:25:58.806-07:00React Native in an iOS/Android appAs a web developer, the potential to use JavaScript for building iOS and Android apps has always excited me. My first encounter with such a framework was <a href="https://cordova.apache.org/">Apache Cordova</a>, an open source project with contributions from individuals and corporations like Google, Microsoft, Adobe, IBM, Intel, etc. I soon became a committer and started building <a href="https://blogs.msdn.microsoft.com/visualstudio/2016/01/28/apache-cordova-development-lands-on-visual-studio-code/">developer tools</a> for it as a part of my previous job. <br />
At my new job, I wanted to continue working on mobile frameworks and joined the React Native team. Before moving full time on React Native Open Source, I took a slight detour and worked on the company's flagship app, parts of which are written in React Native (RN) . This blog post is a brief account of my experiences with using RN in a large scale iOS/Android app.<br />
<br />
<h2>
Brownfield and Green Field Apps</h2>
The main app has many years worth of code in it, spanning multiple teams over many thousand commits. The features are built using an array of internal and <a href="https://componentkit.org/">open</a> <a href="https://fblitho.com/">sourced</a> frameworks. Moving the entire app to one framework would be a herculean task for an app of this scale. The teams pick the technology for specific features based on technical merit, developer workflow and team skill-set. Thus, RN is used alongside the other frameworks and UI components, APIs and developer tools are also shared widely. <br />
This is what is typically called a “brownfield” app in the community, as opposed to “greenfield” apps that are bootstrapped using RN from scratch. Internally however, this distinction is fluid since all apps are viewed as iOS or Android apps, using preexisting engineering infrastructure to various degrees. <br />
<h2>
Developer workflow</h2>
Most developers using React Native to build features, use Nuclide with its excellent Flow support. Nuclide is also pretty well integrated with technologies across the stack and has support for debugging and inspecting elements. It also proves useful occasionally when using the iOS debugger for native code. <br />
I have also found myself dabbling in IntelliJ and XCode when developing/bridging native components or tracking down bugs that span languages. To produce simple test cases for reproducing bugs, we also have a standalone “<a href="https://stackoverflow.com/questions/33779296/what-is-exact-meaning-of-kitchen-sink-in-programming">kitchen sink</a>” app with all components. <br />
One of the biggest differences between the open source setup and our workflow was the use of BUCK as a build system; primarily proving useful due to its cached artifacts in a big project, reducing the overall build times. Most common tasks like adding new screens, generating tests, etc. are automated. <br />
<h2>
Native Components and Modules</h2>
To the end user, the entire app is one cohesive experience and parts of the app using RN should be no different from the rest of the app. The entire app has well defined user interface guidelines and CSS based styling in RN makes its implementation easy. Bridging native UI components for controls that exist is preferred as it promotes style consistency and is such controls are also well tested. We do not use react-native link, but instead rely on the BUCK files to manage JS and native dependencies separately, adding dependencies directly into the native code. <br />
Flow definitions are used to ensure correctness between the JS API and the Java/ObjC implementations. This is vital for over the air updates as it ensures that JavaScript does not call into API methods that do no exist. Many other companies using React Native also seem to have similar tooling, and it would be awesome to see some of these tools open sourced. <br />
<h2>
Navigation</h2>
Our iOS and Android apps have their own navigation system to push view controllers or start activities using Intents. The RN navigation module plugins into this system and exposes API methods that make switching between RN and native screens seamless. <br />
<ul>
<li>Each “route” declares a unique name and defines parts of the navigation UI like the title bar, action buttons, etc. </li>
<li>This information is then used to generate a JSON file at build time. </li>
<li>The RN navigation module uses this file to open the correct screen without having to wait for JavaScript to load or show a “redirection” screen.</li>
</ul>
Though the actual screen is drawn asynchronously, the navigation UI transitions smoothly as all the information can be inferred from the JSON file. This mechanism also helps when loading a screen directly from deep linking or clicking on a push notification. <br />
<h2>
Loading Screens</h2>
As you may have deduced from above, the JavaScript VM may not load until a screen needs it. The navigation also does not wait for React Native screen to be ready before pushing it into the viewport. As a result, there may be a momentary blank screen before JavaScript can kick in to show loading shimmers.<br />
To mitigate this, I experimented with adding a loading screen in native code, possibly generated at build time from RN routes. The two issues that I noticed include<br />
<ol>
<li>Duplicating A/B testing logic that happens at runtime to ensure that the loading screens have the same appearance as the fully-loaded screens. </li>
<li>Adding more native code during bridge startup also seems to delay RN start. This is only a problem when a network fetch may be faster than the time to start up the bridge. </li>
</ol>
In most cases, network was slower, and in addition to native loading screens, we found we could pre-load JS modules eagerly and even render parts of the component tree to be ready for the next React reconciliation cycle.<br />
<a href="https://facebook.github.io/react-native/docs/systrace.html">Systrace</a> also comes in very handy when trying to understand the performance semantics of such optimizations. <br />
<h2>
Data Fetch</h2>
Most of the RN data fetches happen over <a href="https://facebook.github.io/relay">Relay</a>. However, there are also cases where we would need to re-use data that are already fetched by native screens. Having a single data fetch strategy would be ideal but for now, we just have a one-off data pre-fetcher so that the network portion of the critical path could be handled earlier. This native pre-fetcher also lends itself into interesting cases where we could predictively fetch data or even load the RN bridge if we believe that there is a high possibility for the user to request it. <br />
<h2>
Conclusion</h2>
While I have tried to cover some of the areas of RN I touched in the main app, there are many more areas like A/B testing, gesture handling, etc that I could not go over. Overall, I had a good exposure to complex React Native hybrid app development in the last six months. I learnt that it is important to embrace the platform and build for it. <br />
<br />
The React Native team has expertise in iOS, Android and JavaScript, and were very helpful in my journey. Coming in as a Web Developer turned Program Manager, I now find myself now working with iOS and Android native code. I realize the importance of continuous learning and stepping outside my comfort zone to learn from other platforms ! <br />
I look forward to my next set of projects where I am hoping to help the React Native community. axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-21191121353741950542018-04-10T14:36:00.000-07:002018-04-10T14:36:02.187-07:00Reactathon Keynote - Building apps with React NativeDay 2 Keynote - Building apps with React Native <br />
March 22, 2018 at Reactathon 2018, San Francisco<br />
<br />
<br />
<iframe allow="autoplay; encrypted-media" allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/1hvQ8p8q0a0?rel=0" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-50686489176565610122017-09-14T09:41:00.000-07:002017-09-14T09:41:03.378-07:00A/B Testing for React Native apps with CodePush<a href="https://en.wikipedia.org/wiki/A/B_testing">A/B Testing (or Split Testing)</a> is a way to optimize user behavior by serving different web pages to a random set of visitors and measuring metrics that determine the relative efficacy of each user interface design.<br />
A/B testing on Websites is simple since the changes can be deployed and reverted quickly. On the contrary, doing this on mobile applications may require explicitly defining the scope of the A/B Experiment before submitting the apps to App Stores. Iterating on the experiments based on incoming metrics may also be delayed by the App Store processes. Scoping down the experiments to audience segments can also get tricky and may also need to be premeditated.<br />
Though React Native generates native iOS and Android apps, the underlying JavaScript Engine that drives the app can utilize technologies like <a href="https://microsoft.github.io/code-push/">CodePush</a> to enable web-like A/B tests. This post describes a way to use CodePush and other services in <a href="http://mobile.azure.com/">Mobile Center</a> to set up A/B tests just as easily as one would do for websites.<br />
<h3>
Requirements</h3>
The three main requirements and the corresponding solutions for running A/B tests for React Native are. <br />
<ol>
<li>Setup A/B experiments that can be improved as we start collecting user behavior data. For this, we need the ability to update the app instantly. </li>
<ul>
<li>Solution: CodePush. </li>
</ul>
<li>"Push" the experiments to the user rather than wait for the user to requests. We would also want to control the audience to ensure that confounding factors are eliminated</li>
<ul>
<li>Solution: Push Notifications, with the ability to define Audience segments</li>
</ul>
<li>Collect data about user activity on the app to declare a winner in the A/B tests. For a mobile app, the analytics solution should not simply stream data to the server, but collect it (even when the app is offline) and send them to the server in batches. </li>
<ul>
<li>Solution: Mobile App Analytics. </li>
</ul>
</ol>
While I am using Mobile Center as it is convenient to pick up all the services from one place, any other solution for Notifications or analytics would also work.<br />
<h3>
App Setup</h3>
To get started, the <a href="https://docs.microsoft.com/en-us/mobile-center/sdk/getting-started/react-native">SDKs</a> need to be installed on the React Native app using <span style="font-family: "courier new" , "courier" , monospace;">npm install react-native-code-push mobile-center-analytics mobile-center-push</span> and added to the project using the <span style="font-family: "courier new" , "courier" , monospace;">react-native link</span> command. The link command also asks for mobile center keys and code-push deployment keys. You may need <a href="https://docs.microsoft.com/en-us/mobile-center/sdk/push/react-native-android">additional setup</a> like configuring Google Cloud Messaging or enabling APNs for integrating Push notifications with the React Native app. <br />
We would also have to add a snippet to listen to push notifications that are sent from the server. <br />
<br />
<script src="https://gist.github.com/axemclion/3777f43d257b7c286253a78dc66cabf5.js"></script>
This would be the basic app that needs to be distributed to our users.
<br />
<h3>
Starting the experiments</h3>
<ol>
<li>Define an A/B experiment case. This can range from simple things like the color of a checkout button to complicated workflow differences.</li>
<li>Make changes to the code to incorporate the experiment. It would also help to save this experiment in the corresponding branch in source control. </li>
<li>Track user behavior by adding the track method at the appropriate points in code. We may also want to add additional information with the tracking information that identifies the specific case for which data is collected. </li>
<li>Next, we would also create one <a href="https://microsoft.github.io/code-push/docs/cli.html#deployment-management">deployment</a> per case and <a href="https://microsoft.github.io/code-push/docs/cli.html#releasing-updates-react-native">release a bundle update</a> for each of the deployment. Even if the app uses CodePush, these updates will not yet be available
on the apps since they apps use a Staging or a Production Deployment by
default. </li>
<li>We would use Push Notifications to let the apps know about the new
deployment key and the snippet above that is set up to run on receiving a
push notification would do the job. Create a new push notification to be sent to the user as per the <a href="https://docs.microsoft.com/en-us/mobile-center/push/#sending-push-notifications">tutorial</a>.</li>
<li>Specify the codepush deployment key corresponding to the experiment case as the <a href="https://docs.microsoft.com/en-us/mobile-center/push/#custom-data-in-your-notifications">custom data </a>in the push notification with the key called "<span class="pl-k"></span><span class="pl-smi">codePushDeploymentKey</span>". </li>
<li>Select the right <a href="https://docs.microsoft.com/en-us/mobile-center/push/audiences#audiences">audiences</a> that would receive the push notification and have their app updated with the specific experiment case. </li>
</ol>
As users start recieving the notification, codepush's sync method will start picking up the new bundle with the experiment. Once the user performs actions on the app, analytics would be able to send data back to the server for that use case. <br />
<h3>
Conclusion</h3>
While this may not be available as an end-to-end scenario in Mobile Center yet, we can already use the existing infrastructure to A/B test our React Native apps and deliver better apps. Some points to note.<br />
<ul>
<li>As with CodePush, note that you will not be able to add experiments that require changing native code. </li>
<li>App Stores explicitly forbid changing the intent and behavior of apps. Ensure that the A/B tests still stay within what is allowed by the App Stores.</li>
<li>Many complex A/B testing scenarios are usually a matrix of features and experiments simultaneously. While this post does not cover those cases, the methodology described above can be used to build such a complex system. </li>
</ul>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-6818441502691000262017-07-18T13:25:00.003-07:002017-07-18T13:25:44.432-07:00ChainReact 2017 - Zero to DevOps<b>Chain React 2017, Portland</b><br />
<br />
<b>Title</b>: Zero to DevOps<br />
<br />
<b>Abstract</b> <br />
React Native brought the web’s enviable development patterns to mobile,
without needing to sacrifice native UI. Code Push for React Native
brings web like release agility to mobile apps by enabling developers to
update apps instantly. This talk will cover the next iteration of Code
Push and how it fits into a complete suite of DevOps services built for
called Mobile Center, built for React Native. We will look at the end to
end workflow - from a single commit on github triggering continuous
builds and tests, to the final, signed app distributed to testers,
clients or end users. From monitoring services like JavaScript enabled
crashes to understanding user behavior with analytics, we will look at
ways to get better mobile apps to your users. We will look at the
internals of Mobile Center to use with your existing toolchain, other
services that are planned as a part of the suite, and integration with
popular community tools and services.<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/f_-S0ZhVmvQ" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-46584803309653066782017-06-27T09:21:00.003-07:002017-06-27T09:21:56.342-07:00React Amsterdam - Web Like Release Agility for React Native Apps<div style="text-align: center;">
Title: Web like release agility for React Native Apps</div>
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/itDrJ5VWZ3k" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-33954420208079224802017-04-04T11:13:00.001-07:002017-04-04T18:12:05.061-07:00React Native Packager vs Haul<div style="text-align: center;">
<i>What packages faster ? Haul or React Native ? <a href="http://blog.nparashuram.com/2017/04/react-native-packager-vs-haul.html#results">Jump</a> to results </i></div>
<br />
A few days ago, the good folks at Callstack.io released an new, drop-in replacement for the <a href="https://github.com/facebook/react-native/tree/master/packager">React Native packager</a> called <a href="https://github.com/callstack-io/haul">Haul</a>. Over the weekend, I ran experiments to compare the performance of the two systems, to understand these two packagers better. I also wanted to see if I can add support for Haul into <a href="http://mobile.azure.com/">Mobile Center</a> (an end to end devops service for React Native apps) ! <br />
<h2>
Goal</h2>
As a developer, I would like to see code changes show up on the React Native app as soon as possible. The goal of this experiment was to study the performance characteristics of the two packagers and how they improve the edit-reload development cycle.<br />
Though Haul and React Native packagers perform the same function, the
technology stack differs quiet a bit; from HTTP server (connect vs
express) to the way bundling is triggered (file watching vs external
request). For a fair comparison, the impact of these differences must be eliminated so that we compare the core "packager" of each stack.<br />
Like any scientific experiment, this process needs to eliminate impact
of external factors, be statistically significant and available for
anyone to replicate to view the results.<br />
<h2>
Methodology</h2>
To run these tests, clone the <a href="https://github.com/nparashuram/Haul-vs-ReactNative">repository</a>, install npm dependencies and run <span style="font-family: "courier new" , "courier" , monospace;">npm test</span>. The three steps used to design the experiment are as below. <br />
<h3>
Step1: Instrument</h3>
The code in node_modules/haul or node_modules/react-native is <a href="https://github.com/nparashuram/Haul-vs-ReactNative/blob/e7812dae3beb2d7e0b0a4eeb88cca0d633884be0/src/profiler.js">patched</a> to include Node's <a href="https://nodejs.org/api/process.html#process_process_hrtime_time">high resolution timer</a> that indicates the start and end of the packaging process. For React Native, the probe is placed around call to the transformer while we rely on <a href="https://webpack.github.io/docs/list-of-plugins.html#progressplugin">progress plugin</a> in case of Haul. I would invite experts on the packagers to re-validate if this is the right place to instrument the code. <br />
I also tried using the <a href="https://github.com/node-inspector/v8-profiler">v8-profiler</a> to measure memory usage and method calls, but it kept crashing on Haul, so no additional data could be collected there. <br />
<br />
<h3>
Step 2: Observe</h3>
In a typical real world scenario, a developer starts up the packager, heads over to their editor, makes changes to files, includes components, and then expects to see the bundle loaded on the phone.<br />
This workflow was automated with the test suite that starts the packager using child_process.fork, and then starts adding components or trees of components to the main file. The results seem to indicate that the occurrence of a change matters more than the contents of the change. <br />
<br />
<a href="https://asciinema.org/a/3hxgz9629wufaxle14q9j8zi6" target="_blank"><img src="https://asciinema.org/a/3hxgz9629wufaxle14q9j8zi6.png" width="100%" /></a>
<br />
<h3>
Step 3: Measure</h3>
Since our packagers are instrumented, a message with the time to package is printed out on the console. I had initially tried using IPC to send messages, but reading the information from the stdout is much more reliable and accurate. A series of timestamps for every change is collected and tabulated. The entire scenario was repeated 100 times and outliers eliminated to obtain a statically significant result. <br />
For each test run, the packager cache was completely cleared at the beginning and subsequent runs used the transformer cache (in case of React Native), or <a href="https://github.com/amireh/happypack#how-it-works">happypack</a> (in Haul). <br />
<h2>
Results <a href="https://www.blogger.com/null" name="results">#</a></h2>
Here are the graphs from the two test cases. React Native Packager claims that it was designed for fast compilation and targets of sub-second edit-reload cycle - the numbers prove it.<br />
<br />
<iframe frameborder="0" height="400" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/15keONTXMQvipXabjrjtU5A_IcGbnG5Kxj7tFLBmeKYs/pubchart?oid=498362367&format=interactive" width="100%"></iframe>
<iframe frameborder="0" height="400" scrolling="no" seamless="" src="https://docs.google.com/spreadsheets/d/15keONTXMQvipXabjrjtU5A_IcGbnG5Kxj7tFLBmeKYs/pubchart?oid=1798475949&format=interactive" width="100%"></iframe>
<br />
There was not much difference in the initial load with empty cache, indicating that React Native packager was clearly benefiting from storing the modules in memory. However, ReactNative packager is slower when launching the packager a second time since all its in-memory cache is blown away. Haul on the other hand is blazing fast since it picks up the on-disk cache from the previous run on the packager.<br />
The other interesting observation is the rate at which time increases in the second chart when the number of components increase. Also note that the v8-profiler showed that the rate of memory increase in React Native packager was much higher.<br />
<br />
<i><a name="update">Update 1 </a>: @<a href="https://twitter.com/grabbou">grabbau</a> <a href="https://twitter.com/grabbou/status/849330689023643648">pointed</a> out that there were some improvements in the master branch of Haul. Repeating the test from Haul master does show promises, but it is still a little slower than the stock React Native packager. </i><br />
<br />
<i>Update 2: <a href="https://twitter.com/sahrens2012">Spencer</a> also <a href="https://twitter.com/sahrens2012/status/849343936611184641">said</a> that internally at facebook, they have a global shared cache to make the first load times faster. </i> <br />
<h2>
Conclusion</h2>
Performance is just one aspect to consider when choosing a packager. Haul addresses other important <a href="https://www.facebook.com/groups/react.native.community/permalink/951866284948950/?comment_id=951905058278406&comment_tracking=%7B%22tn%22%3A%22R2%22%7D">issues</a> like symlinks, haste duplicates or custom packagers like typescript. While each of these can technically be solved in the React Native packager, I like Haul for bringing it all together and making it simple. Given that Haul is new, it does lack other developer features like systraces, opening debugging in custom editors, etc - parts that don't necessarily belong to the packager component.<br />
Could the React Native transformer be made pluggable to allow a web pack based packager, bringing us best of both worlds ?axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-53061948411865877062017-03-21T11:48:00.001-07:002017-03-21T11:57:30.776-07:00Debugging create-react-native-app with VSCode<a href="https://expo.io/">Expo</a> and Facebook recently <a href="https://facebook.github.io/react-native/blog/2017/03/13/introducing-create-react-native-app.html">released</a> a command line tool called create-react-native-app that makes getting started with React Native easy. With this tool, you can start developing mobile applications for iOS and Android without having to install the SDKs for each of the platforms. This is very similar to the <a href="https://itunes.apple.com/us/app/phonegap-developer/id843536693?mt=8">Phonegap Developer App</a> or <a href="https://itunes.apple.com/us/app/ionic-view/id849930087?mt=8">Ionic View</a> for Cordova apps and works by uploading only the JavaScript part of the application to the player app. Consequently, you can develop and debug iOS apps from a Windows machine without even needing to connect the phone via a USB. <br />
VSCode already supports debugging Expo apps and has support to attach to a packager that is already running.<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/0_MnXPD55-E" width="100%"></iframe>
<br />
<br />
To get started <a href="https://code.visualstudio.com/download">download</a> VSCode and install the <a href="https://marketplace.visualstudio.com/items?itemName=vsmobile.vscode-react-native">React Native tools</a> extension for VSCode. The extension gives you the ability to debug source code right from inside the editor, supports syntax highlighting and completion and has code snippets for popular React constructs. <br />
<br />
<h3>
Time travel debugging </h3>
The extension uses Node to debug the Expo app. If we replace Node with node-chakracore, we also get the ability to use time travel debugging. To try out time travel debugging with create-react-native-app and VSCode<br />
<br />
<ol>
<li>Download node-chakra <a href="https://nodejs.org/download/chakracore-nightly/">nightly builds</a> - it supports Mac, Windows and Linux :)</li>
<li>Grab the <a href="https://gist.github.com/axemclion/ee760a748bd6390d0f3540ea0c292caf#file-debugger-js">debugger code</a> and save it as debugger.js - this is the same code that runs when a React Native app is debugged on Chrome</li>
<li>To start recording a trace</li>
<ol>
<li>Create a folder called logs, adjacent to debugger.js</li>
<li>Run <span style="font-family: "courier new" , "courier" , monospace;"><path-to-node-chakra>/bin/node --record debugger.js</span> </li>
</ol>
<li>To replay a debugging session </li>
<ol>
<li>Start up VSCode, head to the debug pane and <a href="https://code.visualstudio.com/docs/nodejs/nodejs-debugging#_launch-configuration-snippets-for-common-scenarios">create a new configuration</a> to debug a node project</li>
<li>Add the <a href="https://gist.github.com/axemclion/ee760a748bd6390d0f3540ea0c292caf#file-launch-json">additional key value pairs</a> to the configuration (as shown in the video). This basically sets the node executable to be ChakraCore, points it to the location of the logs that are used for time travel, and sets up source maps</li>
<li>Hit the debug button - you will now see "Reverse Continue" and "Step back" in addition to the usual debug workflow controls</li>
</ol>
<ol>
</ol>
</ol>
The time travel debugging part is still experimental, but if it sounds fun, let me know, and I would love to make it a part of the extension.Thanks to the <a href="https://twitter.com/mrkmarron">amazing</a> <a href="https://twitter.com/AruneshC">folks</a> on the Chakra team for making this possible !axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-70703490054803286502017-03-13T22:49:00.000-07:002017-03-17T07:33:53.833-07:00ReactConf - Web like Release and Development Agility<h2>
ReactConf 2017, Santa Clara</h2>
Links from the slides<br />
<h3>
Mobile Center and CodePush</h3>
<ul>
<li>Sign up at <a href="http://mobile.azure.com/">http://mobile.azure.com?utm_source=react_conf_2017</a>. Pick a repository from Github and Bitbucket, and start build for every commit. Other services include Crashes with full sourcemap support, and Analytics with support for <a href="https://reactnavigation.org/docs/guides/screen-tracking">react navigation</a>. </li>
<li><a href="https://www.youtube.com/watch?v=lfqZ8Uy2p3U">Video</a> and blog post showing setting up devops for React Native from scratch.</li>
<li>CodePush documentation at <a href="http://codepush.tools/">codepush.tools</a>. Will soon be integrated into Mobile Center. </li>
</ul>
<h3>
VSCode for React Native</h3>
<ul>
<li>Debug React Native apps from VSCode - Install <a href="https://marketplace.visualstudio.com/items?itemName=vsmobile.vscode-react-native">React Native Tools extension</a></li>
<li>Excellent Flow <a href="https://github.com/flowtype/flow-for-vscode">support</a></li>
<li>Node-Chakra supports Time Travel Debugging - install Node-Chakra using NVS. </li>
<li><a href="https://www.youtube.com/watch?v=waiZsNI4SYA">Video</a> and <a href="http://blog.nparashuram.com/2016/08/time-travel-debugging-with-reactnative.html">Blog post</a> of Time travel debugging </li>
</ul>
<h3>
User Gesture Mirroring</h3>
<ul>
<li>Github: <a href="http://github.com/nparashuram/maya-kai">nparashuram/mayakai</a></li>
<li><a href="https://www.youtube.com/watch?v=ODSD0tfZjtU">Video</a> and <a href="http://blog.nparashuram.com/2016/09/user-interaction-sync-for-reactnative.html">Blog post</a> for User gesture mirroring</li>
<li>Also works on <a href="http://blog.nparashuram.com/2017/02/exponent-apps-testing-on-multiple-form.html">Exponent</a>, can be used to create a <a href="http://blog.nparashuram.com/2015/11/virtual-device-wall-for-cordova-apps.html">virtual device wall</a>. </li>
</ul>
<br />
Slides available on Docs.com - <a href="https://doc.co/19Qwun">https://doc.co/19Qwun</a><br />
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/iMLpUVZseEg" width="100%"></iframe>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-88385316514122307402017-02-23T08:56:00.001-08:002017-02-23T09:02:05.736-08:00Exponent Apps - testing on Multiple Form factors<blockquote class="tr_bq">
Want to test your exponent app on multiple screen sizes ? Check out <a href="http://github.com/nparashuram/maya-kai">maya-kai</a>
</blockquote>
Exponent is a great way to build mobile apps - you get all the benefits of React Native, with none of the pain of installing the Android SDK or XCode. Since Exponent is now <a href="http://www.reactnative.tools/tutorials/2016/10/10/exponent/">integrated into VSCode</a>, my developer workflow pretty much involves firing up the VSCode editor and debugging the app running on exponent in my devices.<br />
Despite an efficient authoring workflow, testing my app across devices is still a little cumbersome. With the need to support different devices and screen sizes, I still have to perform the typical test scenarios manually over all the devices. <br />
<h2>
User gesture mirroring for React Native</h2>
Last year, I had <a href="http://blog.nparashuram.com/2016/09/user-interaction-sync-for-reactnative.html">blogged</a> about a <a href="http://github.com/nparashuram/maya-kai">project</a> that lets you mirror user gestures across devices for React Native apps. This has the same functionality that <a href="http://browsersync.io/">browsersync</a> has for websites. This library lets you interact with just one device and as the test scenario progresses, you can view the user controls across other devices with different screen sizes. Though this library was for originally meant for React Native, the code is all JavaScript and uses React's Event Model. This blog post explores the idea of trying out the library with apps on Exponent. <br />
<h2>
Exponent + Maya-kai </h2>
Surprisingly, no changes were required to make it work with Exponent! I simply <span style="font-family: "courier new" , "courier" , monospace;">npm install maya-kai --save</span> and import it in main.js using <span style="font-family: "courier new" , "courier" , monospace;">var mk=require('maya-kai'); mk.start();</span> The devices (2 phones, 1 iPad) were on the LAN, so I just needed to ensure that the maya-kai server was accessible to them.<br />
<br />
To automate this even more, I added a task that also launches my app on all the connected Android devices when I start the tests. <br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">adb devices | egrep '\t(device|emulator)' | cut -f 1 | xargs -t -J% -n1 -P5 adb -s % shell am start -a android.intent.action.VIEW -d exp://<exponent URL></span><br />
<br />
I was unable to find an equivalent for iOS though.<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/-v71Z2Qwjao" width="100%"></iframe>
Other developer workflow actions like live reload and hot module replacement also worked on all devices. General developer is also faster since there is no native app "install" process here.<br />
<h2>
Wishlist for Exponent </h2>
<ul>
<li>If user gesture mirroring is be something built into Exponent, additional setup steps would not be needed anymore. </li>
<li>It would also be good to automate the process of launching the app for iOS devices when starting tests. </li>
<li>There is also no dev vs production mode, so I am currently using 2 different apps, one for testing, and the other one being the real, published app, without Maya-kai embedded. </li>
</ul>
<h2>
Conclusion</h2>
I think that this workflow is great for quickly testing multiple form
factors. I could simply publish my exponent app, launch it on
multiple devices and interact with them. This is also a neat way
to share screen with remote clients - simply enable gesture mirroring
and you can walk someone through you app's workflow. <br />
I am also looking at integrating this with Appetize, enabling a <a href="http://blog.nparashuram.com/2015/11/virtual-device-wall-for-cordova-apps.html">virtual device wall</a>, something that I did for Cordova applications.axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-39951010480229610362017-02-06T15:18:00.001-08:002017-02-06T15:18:28.069-08:00React Native - Zero to DevOpsUsing http://mobile.azure.com to set up the DevOps pipeline for React Native applications<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="400" src="https://www.youtube.com/embed/lfqZ8Uy2p3U" width="100%"></iframe>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-84844681245171491882016-10-21T09:03:00.003-07:002016-10-21T09:03:26.427-07:00React Native - Under the hood - Connect.tech 2016React Native under the hood<br />
Presented at Connect.tech 2016, Atlanta GA<br />
<br />
Abstract: ReactNative is a way to create native applications for iOS, Android and Windows devices in JavaScript. In this session, we will look under the covers at the technology that enables ReactNative to drive native user interface components. We will look at a typical developer workflow and the way ReactNative is tied to developer tools. We will round it off with ways to deliver updates to your app without needing to submit updates to the app store. <br />
<br />
<br />
<iframe allowfullscreen="True" frameborder="0" height="377px" scrolling="no" src="https://docs.com/d/embed/D25192523-5208-4470-8800-000983506517%7eMe3a3a6aa-bb86-1337-99d6-c4385e2edaa2" style="max-width: 100%;" width="100%"></iframe>
<br />
<br />
Direct Link : <a href="https://doc.co/D8fsNT">https://doc.co/D8fsNT</a>axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-85407288192786656142016-10-18T10:30:00.000-07:002016-10-18T10:30:04.059-07:00Velocity NY 2016 - Using Chrome Traces to Measure Web and Performance<h2 style="text-align: center;">
Velocity Conference, New York, September 19-22</h2>
<br />
<br />
<b>Title</b><br />
Using Chrome traces to measure rendering performance of web pages and mobile apps<br />
<br />
<b>Abstract</b><br />
Ten years ago, increasing the performance of a website usually meant
tweaking the server-side code to spit out responses faster. Today, it is
mostly about ensuring that content is delivered to the user as fast as
possible. However, it is still very hard to measure the user experience
in terms of the smoothness and runtime performance of a website.<br />
Chrome has excellent devtools that help fixing rendering performance
issues in web pages. Parashuram Narasimhan demonstrates how to create
scripts that use the same source of information as the devtools to
automatically measure metrics like frame rates, paint times, and layout
calculations and explains how this method is being used to continuously
track rendering performance of web apps.<b> </b>Topics include:<br />
<ul>
<li>How to leverage the same source that Chrome DevTools use to collect trace information about a web app’s performance</li>
<li>Understanding the events in a Chrome trace and tips and tricks to parse and aggregate them into usable metrics</li>
<li>How to plug this back into any web performance system like
WebPagetest or Speedcurve so that this information can be monitored
continuously </li>
</ul>
<div style="text-align: center;">
<iframe allowfullscreen="" frameborder="0" height="500" src="https://www.youtube.com/embed/feHZMdG6uTw" width="100%"></iframe>
Direct Link: <a href="https://www.youtube.com/watch?v=feHZMdG6uTw">https://www.youtube.com/watch?v=feHZMdG6uTw</a></div>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-34086285769659058142016-10-11T16:38:00.001-07:002016-10-11T16:41:55.178-07:00ReactRally - Rise of Web Workers<h3 style="text-align: center;">
<a href="http://www.reactrally.com/">ReactRally</a> - August 25-26, Salt Lake City, UT</h3>
<br />
<br />
<br />
<br />
<br />
<iframe allowfullscreen="" frameborder="0" height="500" src="https://www.youtube.com/embed/BJZx4twjt-I?start=46" width="100%"></iframe>
<br />
<br />
<br/>
<h5>Direct Link: <a href="https://www.youtube.com/watch?v=BJZx4twjt-I&t=46">https://www.youtube.com/watch?v=BJZx4twjt-I&t=46</a></h5>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.comtag:blogger.com,1999:blog-8997727588422391656.post-60589904377853472992016-09-16T04:42:00.001-07:002016-09-16T04:42:37.990-07:00Rise of the Web Workers - NationJSSlides from the presentation at <a href="http://nationjs.com/" target="_blank">NationJS</a>. <br />
<h3 class="speaker-talk-description">
Links</h3>
<ul>
<li><a href="http://github.com/axemclion/browser-perf/" target="_blank">browser-perf</a> - a tool to automate calculating performance metrics like frame rates for a website </li>
<li><a href="http://web-perf.github.io/react-perf">web-perf.github.io/react-perf</a> - Tracing ReactJS performance across versions of the library</li>
<li><a href="http://github.com/web-perf/react-worker-dom">React-worker-dom</a> - Implementation of ReactJS in a web worker. <a href="https://github.com/web-perf/react-worker-dom/tree/r-15">Alternate</a> implemenetation using jsdom like proxy. </li>
</ul>
<h3>
Slides</h3>
<br />
<div style="margin-bottom: 5px; max-width: 100%; width: 752px;">
<a href="https://docs.com/parashuram-np/2784/rise-of-web-workers" style="font-family: "segoe ui"; font-size: 13px; margin-left: 18px; text-decoration: none;" target="_blank" title="Rise of Web Workers">Rise of Web Workers</a><span style="font-family: "segoe ui"; font-size: 13px;">—</span><a href="https://docs.com/parashuram-np" style="font-family: 'Segoe UI'; font-size: 13px; text-decoration: none;" target="_blank">Parashuram NP</a></div>
<iframe allowfullscreen="True" frameborder="0" height="599px" scrolling="no" src="https://docs.com/d/embed/D25192828-1437-2498-7580-001969758699%7eMe3a3a6aa-bb86-1337-99d6-c4385e2edaa2" style="max-width: 100%;" width="752px"></iframe>
<h3>
Abstract </h3>
<div class="speaker-talk-description">
Modern web applications are awesome. And complicated. The Javascript
libraries that power them today do a lot of work to abstract out the
hard parts. Whether using constructs like Virtual DOM, or fancy change
detection algorithms, the amount of work that the Javascript library
does is only increasing.
</div>
<div class="speaker-talk-description">
Unfortunately, all this work now competes for the same resources that
the browser needs, to do things like render a page, or apply styles. In
many cases, this makes the browser slow, preventing the web application
from attaining its full, smooth experience.
</div>
<div class="speaker-talk-description">
Web workers have been in the browser for a while, but they have mostly
been used for engaging demos like adding mustaches in a cat video :)
</div>
<div class="speaker-talk-description">
In this talk, we will explore how mainstream Javascript libraries like
React or Angular use Web Workers to get great performance. We will look
at quantitative numbers from hundreds of test runs that conclusively
show how Web Workers can make apps faster. Finally, we will also look at
practical examples to convert existing examples, and the potential
limitations of this approach. </div>
axemclionhttp://www.blogger.com/profile/10684165552621181878noreply@blogger.com