Back to Blog Home
← all posts

Brain-storming an alternative solution to web/mobile code sharing

June 22, 2020 — by Mahmoud Abduljawad

Preface

Sharing code is something NativeScript has always been well suited for since after all, it's just JavaScript. It's also a topic that always makes for a fascinating and exciting discussion since there are many effective strategies to share code with NativeScript.

The following post was written by a talented developer, Mahmoud Abduljawad, and offers another look at this fun topic. You can find more from Mahmoud on the following:

Here's the post which can also be found dev.to here

Code Sharing

Single code-base running across Web, Android and iOS utilizing Angular and NativeScript.

Code Sharing: The Challenge

A recent experience with Flutter fueled my passion for code sharing across web and mobile. Flutter team is making an ambitious promise about it, but that seems to need another year or so from my own perspective. I eventually went back to NativeScript, which I've been using for the past three years to develop mobile apps, and began to think what can be done to reach an ultimate code sharing status across web and mobile.

The challenge of sharing single code-base is the different mechanisms each platform is having. Such issues can be easily spotted in hybrid frameworks such as NativeScript, React Native, or Xamarin, where you might end-up need to add conditional code per the platform. Taking that to whole lot of different underlying structure from mobile APIs to web APIs is another big task.

Brain-storming an Alternative Solution

As I was looking at a newly created project following the NativeScript own guide on the same, which is already a great path into sharing the code-base across web and mobile, but still the allocation of separate templates files has always bugged me. For those not familiar, NativeScript uses MVVM structure, where templates are isolated from the code. I am a fan of this approach as opposed to React (or Flutter) where everything sets in one nice dish of spaghetti (Just my personal opinion). As I was looking at both template files for mobile (which is a flavor of XAML) and web (a basic HTML Angular template), I had a thought, what if I am able to use single template language for both web and mobile! Luckily, Angular always helped me building proof of concepts with its great structure. I began building components for:

  1. Label: XAML element representing a text.
  2. Button: XAML element repressing a button.
  3. Image: XAML element representing an image.

The work was very basic that I simply had the following elements:

@Component({
    selector: 'Label',
    template: `{{ text }}`,
})
export class XAMLLabel {
    
  @Input('text') text: string = '';
}

@Component({
    selector: 'Button',
    template: `{{ text }}`,
})
export class XAMLButton {
    
  @Input('text') text: string = '';
    
  @Output('tap') tap: EventEmitter<any> = new EventEmitter<any>();

  @HostListener('click', ['$event']) onTap($event) {
      if (this.tap.observers.length > 0) {
          this.tap.next($event);
      }
  }
}

@Component({
    selector: 'Image',
    template: `
    <img [src]="_src" [attr.async]="(loadMode == 'async') ? 'on' : 'off'">
    `,
})
export class XAMLImage {

    _src: string = '';
    
    @Input('src')
    set src(v: string) {
        try {
            if (v[0] == '~') {
                this._src = v.slice(2);
            } else {
                this._src = v;
            }
        } catch (error) {

        }
    }

    
    @Input('loadMode') loadMode: 'async' | 'sync' = 'async';
}

That is very basic work in Angular, where I just needed to add some Input, and Output attributes to interact with XAML components. I created a XAMLModule that is only imported for the web application, and not mobile, and, happily I had a PoC sporting single code shared across web and mobile.

Journey Continued

Once I had this little success, I began to implement more components. I added StackLayout and GridLayout which as their names suggest, are layout elements in XAML. Since I am a fan of Bootstrap and very regularly use it, I decided to build the layout elements atop Bootstrap framework, which kind of worked. I had to introduce breaking changes and alt uses to get the elements to behave on the web the same they do on the mobile. That said, it wasn't that much of a tricky path to take, but I ended up building most of the work on pure CSS grid methodology. At this point I already had my PoC taking shape--My Pokédex app is becoming more of a working app across web and mobile. I always built Pokédex apps as PoC's as it releases me from the pain of bringing up an idea, as well as enjoying seeing my beloved childhood creatures again and again.

End Results

At pages (or, screens) level, I had total of 321 lines of code spanning across templates and code. Out of which, 17 lines, or 5.2%, are web-specific, and 12 lines, or 3.7%, are mobile-specific! That's up-to 96.3% code-sharing across pages of the app. This was so fascinating results for me!

Beside the cover photo of this post, here are two more screenshots:

Screenshot of macOS screen with Firefox window, Android emulator, and, iOS simulator running NativeScript Pokédex proof of concept app

Screenshot of macOS screen with Firefox window, Android emulator, and, iOS simulator running NativeScript Pokédex proof of concept app

Additional to sharing the code-base across web and mobile, I implemented some events handling process, as well as dynamic generation of CSS grid values, which results in allowing me to create responsive layouts for the web as well using the very same XAML template.

Thoughts on the Process

I was amazed I was able to produce such results across two weeks of work. The reason is, if it's doable, why not! Apps built with Flutter for web are SEO-graded at big O. That was a real concern to me when I began tinkering with Flutter. The results of this project for web are way more better than what anything I can achieve in Flutter, and that brings me to the final idea which is setting this project as baseline to begin a broader attempt at building a complete method allowing richer developer experience sharing the code across web and mobile.

For now, you can see the results of the project yourself at:

https://mahmoudajawad.github.io/nativescript-pokedex/dist/nativescript-pokedex/

You, as well, can have a look at the full source code at:

github mahmoudajawad/nativescript-pokedex