Operation Lazarus – resurrecting the Shoutem UI Toolkit

So I wanted my first post to be about setting up navigation in my React Native learning app, however, I had to decide which package I’d use to save myself the trouble of writing all my own components. I mean, it’s unavoidable, you always have to tweak something, but it helps a lot when you can just tweak a little bit of code instead of writing the whole thing.

At the time when I started, Shoutem UI was 100% functional only on version 0.43.4 of React Native. The active version at that time was 0.50.3. More than a little bit outdated, considering that versions 0.49 and 0.50 both included the obsoletion and breaking-changes of components, props, methods and libraries.

But I (with a generous amount of help from the Shoutem dev team) put in the time to go through everything, test it thoroughly, document what was undocumented and fix anything that popped up and here we are.

$ npm i @shoutem/ui --save

Go ahead. Enjoy it. Version 0.22.0, compatible with React Native 0.50.3.

Baby steps

I should make it clear, I work for Shoutem. I’m a tech support / technical writer / that guy that talks too long during the daily standup.

Taking that into account, I reached out to the developers in Shoutem and asked to work on the UI toolkit, forking what needed to be forked, fixing what needed to be fixed, as the title states, resurrecting the UI toolkit.

Step 1 – Fixing forked repositories

So what needed to be done? The biggest ball-ache was the switch from React.PropTypes to the prop-types package, which was a breaking change introduced with React version 16.0.0. If you check the actual shoutem/ui repository, the changes needed for that were introduced to it before I started working on my update.

So why was this the biggest ball-ache? Well because three packages the UI toolkit utilizes were out-of-date. react-native-transformable-image and it’s dependency react-native-view-transformer, as well as react-native-lightbox which also depends on react-native-view-transformer. A happy little love triangle.

Updating all the forks of those packages took a bit. lightbox not only used React.PropTypes, but also React.createClass, so that had to be replaced with prop-types and create-react-class packages. Luckily these packages were pretty simple, so things weren’t much of an issue. The biggest annoyance was testing them out.

Having limited experience with updating repositories like this, I found it pretty hard making sure that the dependencies all stayed in sync so that they all used the correct versions of the packages. Hence the ball-ache.

After I finished up all those changes and tested them out properly, I tagged them to their new versions and slapped them into the UI toolkit’s dependencies, that was step no. 1.

Step 2 – Updating Shoutem’s animation and theme packages

After fixing up the three forked repositories, getting them reviewed by the Shoutem dev team and merging them, I set onto the next task, which was updating the UI toolkit’s two “in-house” dependencies. The Shoutem Animation and Theme packages.

They also suffered from acute React.PropTypeitis, but it wasn’t all that hard to fix. The most notable time sink was the example app in the Animation repository, which showcased various animations.

Basically, it required me to make a brand new app and remake it’s predecessor, because of the change from using index.ios.js and index.android.js to just using App.js  introduced by React Native 0.50.0, as well as other details.

Once this was reviewed by the Shoutem dev team, I was allowed the honors of publishing the new versions of the npm packages.

@shoutem/animation version 0.12.0

@shoutem/theme version 0.11.0

Step 3 – Fixing the UI toolkit

There was surprisingly little work, considering that all the components were already fixed in previous commits, but details still remained.

React Native’s Image component no longer allows you to nest other components inside of it as of version 0.50.0. For that purpose, a separate component was made; ImageBackground. At first this seemed like something that would take quite a while to remedy, but thanks to “single source of truth”-esque principles, the entire UI toolkit uses the Image component which is defined in one single place.

@shoutem/ui/components/Image.js

The change was as simple as replacing:

import { Image } from 'react-native';

With:

import { ImageBackground } from 'react-native';

And that was it. Worked like a charm.

The second fix was less of a breaking change and more of a straight up obsoletion. The prop resizeMode no longer existed. So it was removed from theme.js and any components which had the prop specified in their JSX.

The third fix was an unusual oversight (I guess?) of not actually exporting the LinearGradient component.

And the last thing left to do was to make sure all the packages were sufficiently up to date to run everything on both Android and iOS. For the most part everything was fine, but two packages caused a bit of trouble on Android, which seems to generally be the more sensitive of the two platforms. react-native-photo-view and react-native-vector-icons.

Step 4 – Updating the examples

So this was, again, a bit of a pain in the buttocks. The RestaurantsApp example app had some components that needed to be fixed up a bit. Some components were changed to make more sense, like the removal of > icons at the end of un-interactable rows.

The create-react-native-app example was a bit more annoying however. Because the expo SDK uses BVLinearGradient, a native component, BUT renames it, it basically makes it impossible for the Shoutem UI toolkit to utilize that same native component. Which is fine, people that want to use LinearGradient from the @shoutem/ui will just eject from expo, right?

Well that wasn’t really the issue at hand. The issue was that the DropDownMenu component had a LinearGradient nested in it. Specifically in the DropDownModal.js file. And when you tried to open a drop down modal, your app would crash (redscreen in debug mode), which was unreasonable. If someone wants to use the DropDownMenu component they shouldn’t be forced to eject, it’s not a native component in and of itself after all.

To work around this issue, a simple if was implemented. If you can’t find the BVLinearGradient native component, don’t render the LinearGradient in the DropDownModal.js. Super simple:

renderGradient() {
  if(!NativeModules.BVLinearGradient){ 
    return null;
  }
  ...
}

NativeModules is a React Native method.

import { NativeModules } from 'react-native';

After that was done, all that remained were a few simple fixes to the example components used in the Examples component. It took me 4 tries to write that sentence and then I had to re-read it just to make sure I wrote the right thing and that it made sense.

Step 5 – Testing, testing and more testing

After everything was said and done, it was time to actually make sure the UI toolkit worked.

Even though the Examples component does a great job of showcasing the UI toolkit, it doesn’t utilize all the components the toolkit offers. Some notable examples were the ImageGallery, InlineGalleryand ImagePreviewcomponents, none of which have any documentation at the moment. Figuring out their styleName‘s had me digging through Shoutem’s extension’s used in their extension architecture as well as the UI toolkit’s theme.js file used for styling with the @shoutem/theme package.

Testing them to their full extent was also fun, having to figure out which props to shove where and how. Overall, great experience for learning how to dig through some else’s code with limited or no documentation.

After that was all said and done, it was time to publish this lovely piece of work.

@shoutem/ui version 0.22.0.

So what next?

Well, the next thing I’m going to do is document all those components that exist in the toolkit, but don’t show up in the Examples component or the documentation, as well as polishing up the documentation with better code snippets that show off the components properly.

Here’s a little preview of that:

export default class App extends Component<{}> {
 constructor(props) {
 super(props);
 }

  renderImageOverlay(photos) {
    return (
      <ImageGalleryOverlay
        styleName="full-screen"
        title={photos.title}
        description={photos.description}
      />
    );
  }

  render() {
    return (
      <ImageGallery
        data={photos}
        renderImageOverlay={this.renderImageOverlay}
      />
    );
  }
}

Where photos is an array of objects, each containing:

{
  "source": {
    "uri": "https://totally-legit-site.legit/legit-image.jpg"
  },
  "title": "Photo Title",
  "description": "A long winded description rarely read by the viewer."
}

 

Now that I have the Shoutem UI toolkit at my disposal again, I’ll revitalize my efforts on the Red Wheelbarrow learning app.  Thanks for taking the time to read, hope you enjoyed a glimpse into the world of resurrecting dead repositories and have a great day.

Remember,, this is definitely not a blog, written by definitely not Vlad.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s