Nativescript: Rendering NativeScript templates on the web (nothing to do with WebView)

Created on 23 Feb 2016  路  29Comments  路  Source: NativeScript/NativeScript

I am interested in expanding the idea of NativeScript modules from iOS and Android to the web. I am just starting to get into NativeScript, so there may be some things I am missing here, it seems like there is no reason why you can't translate something like this:

<Label text="hello world" /> 

to

<span>hello, world</span>

Yes, I picked something super easy, but my point is just that I believe the number of things that don't have literally ANY web equivalent are extremely small. To prove my point, you can see the React community trying to do exactly what I am suggesting here with React Native:

https://github.com/necolas/react-native-web

I use Angular 2 so I know it is possible at the very least to create a new Angular 2 renderer that reads in NativeScript XML and spits out HTML, but I would imagine that this may be the type of thing we want deeper in NativeScript core.

I guess I am looking for feedback from the NativeScript community on two levels:

  1. Feasibility of doing NativeScript for the Web
  2. Assuming it is not impossible and there is interest, thoughts on how to best organize this type of effort

I don't have the bandwidth to do something like this by myself, but if there were other people interested I would love to work together to make this happen.

question

Most helpful comment

All 29 comments

Hey @jeffwhelpley,

Interesting suggestion! For sure you will be able to share code (your business logic for example) between web and native app if you use Angular 2 together with NativeScript.

On theory you/we should be to add additional platform no matter web, osx, windows, etc. since every component/module implementation is separated in different file depending on the platform and our tools will select only relevant files when you publish the app. You can check for example how our Label is implemented:
https://github.com/NativeScript/NativeScript/tree/master/ui/label

Maybe we can have something like this for web:

label.web.ts

export class Label extends common.Label {
    private _web: HTMLSpanElement;

    constructor(options?: definition.Options) {
        super(options);

        // Here this._context can be HTMLDocument
        this._web= this._context.createElement("span");
    }

    get web(): HTMLSpanElement{
        return this._web;
    }

    get _nativeView(): HTMLSpanElement{
        return this._web;
    }

Yes, I agree that from the framework perspective, NativeScript should have a general interface and we can create adapters for any type of target environment.

If you guys would be able to add this type of ability to core, I would be more than happy to experiment with trying to implement some web-based implementations for the different controls.

I could also create a plugin to begin some experimentation here utilizing your suggestion @enchev
We could start with a few key elements to kick things off.

A good starting challenge:

  • Label -> span
  • TextField -> input[type="text"]

    • secure -> input[type="password"]

    • hint -> [placeholder]

  • Switch -> input[type="checkbox"]
  • Image -> img

    • src -> [src]

  • SegmentedBar -> ul class="segmented-bar"

    • items -> li

  • ListView -> ul class="list-view"

    • items -> li

    • itemTap="tapFn" -> bind each li to tapFn

    • if using nativescript-angular -> li (click)="tapFn"

It would allow us to try out all the use cases to better define what edge cases there may be and/or other challenges lay ahead here.

A build tool that could also compile html -> {N} xml would also be amazing in this realm.

Yes, I would like to have this also. As this would enable to cover web and mobile in an easy way.
Also created some directives which are enabled me to run the same directives on both ends, so it is kind of working fine.

@NathanWalker it would be awesome if you could do a prototype of some sort.

Btw, @eesdil I think you probably updated your comment, but I think you were asking about navigation before. I actually think that there is a way to unify native and web navigation. Typically web navigation doesn't have the concept of a stack since the browser handles the back button, BUT I really don't think that has to be the case. I actually think we can and should have a stack-based version of navigation for the web just like on native.

One other comment I wanted to bring up for this discussion. Watching the ReactConf videos and I saw Ben Albert mention that they want the React community to tackle this specific problem for React Native:

https://www.youtube.com/watch?v=-RJf2jYzs8A&feature=youtu.be&t=1312

I think he explains pretty well why doing native for the web makes a lot of sense.

@jeffwhelpley no, eventually wanted to raise concern about the layout model..., but after I realised that we are talking about creating nativescript app which will be converted to web app and not web app which is translated into ns...

Based on what @tjvantoll explained during Angular Air the other day, sounds like we need basically 2 things to make this a reality:

  1. web runtime similar to what is available for Android here and iOS here
  2. controls.web.ts files for the various components that should be supported on the web similar to what is, for example, found here for iOS.

Building a web-runtime sounds fairly straight-forward and I agree with what @tjvantoll said on the show, likely less complex than the ios and android runtimes.

I'll try to watch that React video above soon to understand how they are thinking of tackling it.

My main question would be to any who are interested in this sort of thing is:

A. Do you want to use tns as your primary build tool and write everything in {N} xml to have the framework generate all the web/html components?

Main concern here is the 1-1 parity with controls and dealing with situations where say this:

<StackLayout>
  <Label text="Bleeding Edge"></Label>
  <SegmentedBar items="{{items}}"></SegmentedBar>
</StackLayout>

translates to this html:

<div>
  <span>Bleeding Edge</span>
  <ul class="segmented-bar">
    <li>... what to do with items? ... (angular would make this easy, see below)</li>
  </ul>
</div>

if using angular (preferred :+1: ), this is more clear:

<div>
  <span>Bleeding Edge</span>
  <ul class="segmented-bar">
    <li *ngFor="item of items">{{item.title}}</li>  // `title` would be the default as it's the property SegmentedBar uses for it's label
  </ul>
</div>

Of course we get into situations where the translation would need help. Either extra attributes on the XML to allow the translation to be more granular to allow say a binding with {{item.name}} instead of the default title lets say.

B. Do you want to use your existing web build pipeline writing everything in html and utilizing a setup that can translate your web views to {N} views that you maintain yourself:

I have a proven setup for this path here: https://github.com/NathanWalker/angular2-seed-advanced

This path is more comfortable for web developers as you would just write your app as any other web app and then just create mirrors of your web views in {N} xml, then let the app framework (in the seed) do the view translations for you at runtime.
The main consideration with this path is methods won't always have a 1-1 parity with the web. {N} controls have arguments with specific properties that must be taken into consideration to determine certain user actions therefore some conditional logic may need to exist throughout the shared codebase. Example of this can be seen here:
https://github.com/NathanWalker/angular2-seed-advanced/blob/master/src/frameworks/i18n.framework/components/lang-switcher.component.ts#L24-L36

In most cases, it appears to be pretty simple conditional logic so not a bad tradeoff.

Hey, @NathanWalker thanks for writing that up. So, there are actually two different ways to do this:

  1. Implement a generic solution without any help from Angular
  2. Build a solution on top of Angular 2

From the NativeScript project perspective, it would seem like the first option is the most obvious choice since you would think that it is good to not have NativeScript tightly coupled to Angular. However, the first option will be much harder to implement and require more time/effort. Even if want the first option in the long run, I would really suggestion going with the second for now to just prove this out.

Regardless of the two choices above, it should be easy enough to include the ability to generate static HTML at the command line. The more tricky thing comes when you start thinking about the runtime. For that reason, I would strongly suggest that at least initially we think of the runtime for this type of solution as tied to another web-based framework. In other words:

  1. Create the generic, vanilla JS controls that do the translation from NativeScript elements to HTML
  2. Build into the NativeScript CLI the ability to generate static HTML from the command line
  3. Then do a specific runtime implementation for Angular (and perhaps down the road for React or whatever, but that would be later).

If that seems palatable, then there are actually three options for how we implement this specifically with Angular 2 (need to do some research to see which is better):

  1. Most desirable solution is if it is just a matter of creating a series of custom components. In that way, NativeScript on the web is just like another UI component toolkit.
  2. If there are issues with the NativeScript template XML, we can use Angular 2 transforms to modify it at build time into something more suitable.
  3. If that doesn't work for some reason, we can always create a custom rendering engine on top of Angular 2. This is relatively straightforward, but not ideal since it requires a little more work.

If we can get by with 1 and 2 then there are a lot of crazy stuff we are going to be able to do.

@jeffwhelpley I'm going to initially tackle this with the the (first) option 2 as you suggest. Agreed, an Angular implementation will prove out quicker I think as well. Then we back it out to vanilla.

I see this as becoming another runtime option for tns, so I would work towards implementing another command line option, which will likely be this:

tns add platform web
tns run web

It would add a web build to platforms and run that.
Out of the 3 strategies you suggest (angular components, transforms, or custom rendering engine), I like the first at the moment. I could see the beginning of the web runtime including angular and providing that component toolkit. This should be the least friction way to prove things out. Then angular could be removed to provide the vanilla runtime.

In order to proceed, I'm going to cc a couple core team members that may be able to provide a pointer to a good workflow in adding another command to the cli and developing on that locally.

/cc @Plamen5kov @slavchev @jasssonpet @ivanbuhov @hdeshev

If anyone had a 1-n* punch list of how to setup a good dev workflow to add a new runtime to the cli so I could work on this would be appreciated. In meantime, I will see what I can sort through.

When working on nativescript-cli, I usually do the following:

  1. Clone/checkout the nativescript-cli repo to some folder, update its submodules and start a compiler+watcher using grunt watch:ts
  2. I go to a NativeScript project folder, and define a fish function named dtns (Debug TNS) which just forwards all its cmdline args to the developer build:
    function dtns
        ~/w/nativescript-cli/bin/nativescript $argv
    end

a bash version would probably look like (untested):

    dtns() {
        ~/w/nativescript-cli/bin/nativescript $@
    }
  1. I change the code in ~/w/nativescript-cli, let the FS watcher do its thing, and then run commands using dtns <somecommand> in my project dir. I usually do that until my app works, I get the tests to pass [1] or I just console.log my way to success.
  2. A thing to keep in mind is that nativescript-cli shares code with another project, and keeps a lot of code in the lib/common dir, which is really a git submodule pointing to mobile-cli-lib. All changes you do there, have to get accepted to that repo via a PR, and then you need to open a new PR for nativescript-cli that includes a commit updating the submodule SHA.
  3. A note about editor configs: nativescript-cli and mobile-cli-lib use tabs for indentation :scream:

[1] You run tests and coverage with the grunt watch:devall command.

Of course, you should take all of the above with a grain of salt, since I'm just a casual contributor there. @teobugslayer and @rosen-vladimirov may offer additional tips.

This is really excellent @hdeshev Very helpful. Thank you, I'll see what I can do with that.

Has any progress about issus?

Hi @Alphmega, there was some discussion about this at ngConf this past week amongst myself and the core team. We are thinking of going the inverse way first either via a webpack plugin or a build step that could generate NativeScript xml views from html. The reason for this is there's far more html view templates in the world right now than NativeScript xml views and being able to generate NativeScript xml from existing html view templates could help people get going with NativeScript.

However, nothing is off the table here so curious to hear your thoughts/opinions.

@NathanWalker I probably need to hear more but I would think the main issue with that approach is that while almost all NativeScript XML can be translated into HTML + some JS functionality, I don't think the inverse is true.

Also, even if you could do something in the reverse direction, it doesn't really help doing static HTML to NS XML. Really what we want is interop/reusability between NS and web templates.

@jeffwhelpley

Really what we want is interop/reusability between NS and web templates.

I also have similar thoughts and I think that this is the best way to go. Now, it is subjective how we define _best_ but my reasoning comes from the simplicity and the maintainability. I would like to hear other opinions though.

What we really need here is just a solid use case to help define things a bit more. Anyone wanna take a stab? Doesn't need to be long by any means but something like "User should be able to do X and then do Y with the expectation of Z happening.", but flush that out a bit more.

{N} runtime creates a NativeScript app which is built with xml views out the box. Add nativescript-angular into the mix, and you can begin building Angular Components with {N} xml views (using .html suffix). Running tns emulate ios and tns emulate android run the app in their respective emulators.

How does this strategy mix with the above and with a user who may be cloning the official angular2 seed or any other seed?

At a high level, as we talked about from the beginning the goal is to share templates between native and web. There are many variations for what this actually means or how this would work, but here is the way I was thinking it would potentially work with Angular 2.

  1. You create your native app first using NativeScript and the standard XML templates. No different than today.
  2. To run your app on the web, the first step may require us to either do a transformation of the template using the Angular 2 template transformers and/or a custom renderer. We would not build the solution on either of these, but they are good safety nets in case # 3 doesn't work for whatever reason.
  3. Almost every NativeScript XML element has a custom Angular 2 component for the web.

So, with the way I am thinking, no changes are necessarily needed to the NativeScript core. You would instead leave that as a decoupled black box and just build out a suite of Angular 2 components, services, transformers and potentially a renderer that provides functional equivalence.

Now, maybe after doing this there are certain things that just don't work on the web, but I suspect that is less than you may initially think. Of course, this only works for Angular 2 and is not a generalized solution for other frameworks. But...who uses anything other than Angular? ;-)

Ok perfect, thanks @jeffwhelpley ! That actually clears up quite a few things I was initially curious about and gives me a couple ideas. I will target June for some type of prototype.

What? Mind Blown!

This is amazing.
I find one of the biggest pains for me is in the multiple UI's that have to be maintained, which makes me think of ionic and the web view solution as an easy out. Not the best solution but a quick solution with one UI across all devices.
I really like the idea of a potential hmtl -> {N} translater or transpiler which would help reduce the need to maintain multiple UI's.across web and native. This would also increase the potential adoption rate of {N} amongst traditional web developers looking to move to mobile since they could use their existing html & javascript knowledge.
I take on board the comments about not all HTML can be translated to an equivalent {N}. But given what i have read it sounds like there is a vast amount that can be.
Kudos to you Jeff & Nathan for the pioneering work that you are doing here. The community is going to benefit massively from your work.

Hey folks,

I'm closing this one. Please use log any future bugs and features here:
https://github.com/NathanWalker/nativescript-angular-web-components

I know this is closed. But if this thing is possible, nativescript would become to go platform for almost any application out there.

@prijindal +1
I noticed the respository by @NathanWalker wasn't update any longer. is that still in development?
I also believe this should be part Nativescript Core as the Implementation flow is usually design -> HTML template (more people know how to do that, that's also why Ionic2 is more popular) -> [--> XML for Nativescript] -> TS Logic -> etc.

@dragGH102 It's an open source project welcome to community contributions ;)

The NativeScript team is very busy working on many amazing things for the platform and not sure they need to be diverted to that particular feature as it _can_ be achieved solely by the community. If you'd like to get involved, feel free to send me an email (walkerrunpdx [at] gmail).

@jeffwhelpley @hdeshev @NathanWalker, check out : http://alibaba.github.io/weex/doc/components/div.html, they're supporting html elements natively on ios&android, It's much easier for web developers not having xml templates but just html templates. It will be nice if NativeScript supports this!

@zhaxi - The reason I down voted this idea is the making another "derivitive" of html makes no sense (at least to me). If you know HTML, doing the XML templates are very simple to do.

This issue was closed quite a while ago, but I am curious if there has been any more consideration here. I'm not so much looking for being able to present mobile app as html, but more so be able to share "custom components" with web and mobile.

As it sits now (my best understanding) is that nativescript brings familliar conventions and will allow us to reuse stuff like services etc (which is beneficial) but sharing very little with the ui.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings