DEV Community

Cover image for My endeavor for Ultimate Code Sharing in NativeScript+Angular.
Mahmoud Abduljawad
Mahmoud Abduljawad

Posted on

My endeavor for Ultimate Code Sharing in NativeScript+Angular.

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 they allocation of separate templates files was always bugging me. For those not familiar, NativeScript uses MVVM structure, where templates are isolated from the code. I am a fan of this approach, not React (or Flutter) where everything sets in one nice dish of spaghetti1. As I was looking at both template files for mobile (which is a flavour 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']) onScroll($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')
    public 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:

nativescript-pokedex

This project is a PoC for ultimate code sharing across web and mobile using Nativescript with Angular.

Read more about this project motivations at: https://dev.to/mahmoudajawad/my-endeavor-for-ultimate-code-sharing-in-nativescript-angular-2m73.

Demo

The results of this project are available as Github-Pages-hosted app at: https://mahmoudajawad.github.io/nativescript-pokedex/dist/nativescript-pokedex/.

How Much

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 done by creating set of components and directives that are used by web application to replicate the behaviour of XAML components used in template for mobile application.

Other elements of the app, such as services and utilities are mostly platform-specific, but to me that's totally fine, as in most cases these services and utilities would be abstracted and re-used again in other…

Footnotes:

Cover photo: PoC: "NativeScript Pokédex", a project with single code-base running across web, Android and iOS.
1 Personal opinion and preference.

Top comments (1)

Collapse
 
layzee profile image
Lars Gyrup Brink Nielsen

Interesting to focus on template sharing on the molecule and component level.