Από ένα Web App σε ένα Windows 8.1 App

Γιάννης Παναγόπουλος http://www.progware.org/blog / @ipplos

Στόχος

Να δούμε τα εργαλεία, το workflow, την αρχιτεκτονική της εφαρμογής και τα patterns που αλλάζουν και χρειάζομαι για να μεταβώ από τον κόσμο των Web Applications στον κόσμο των Windows 8.1 Applications.

Εργαλεία Υλοποίησης

Από το Web στα Windows 8

Ξεκινάτε με τα απλά...

και αρχίζετε να νιώθετε κάπως έτσι

Και μετά θέλετε...

  • Να γράφετε γρηγορότερα HTML
  • Καλύτερη οργάνωση των CSS
  • Να μην πατάτε συνεχώς refresh στον browser
  • Όσο το δυνατό καλύτερο intellisense σε Javascript
  • Υποστήριξη CoffeeScript,TypeScript

Και αυτά γίνονται με ...

και αρχίζετε να νιώθετε πάλι κάπως έτσι

Αλλά στα Windows 8

?

Ξεκινάτε με τα απλά...

άντε πάλι...

Tweaks (Autoreload)

Ενεργοποιείστε στο Expression Blend το Autoreload

Tweaks (SASS)

Mindscape's Web Workbench Extension για υποστήριξη SASS όπως και στην προηγούμενη περίπτωση απλά δεν προστίθεται από το μενού

Τελικά η διαδικασία γίνεται...

Για αλλαγές στο CSS χρησιμοποιείτε Visual Studio

Για αλλαγές στην HTML χρησιμοποιείτε Expression Blend

(γιατί αυτό;)

Intellisense

  • Χρησιμοποιείτε IDs στα elements
  • Ό,τι βάζετε στο HTML αρχείο είναι ορατό στα js αρχεία που αναφέρει για Intellisense
  • Χρησιμοποιείτε το reference directive στην αρχή του αρχείου
    /// <reference path="/js/[file].js" />
    για τα υπόλοιπα

Typescript υποστήριξη

(VS<2013) Χρειάζεται να "πειράξετε" λιγο το .jsproj file

<ItemGroup>
    <AvailableItemName Include="TypeScriptCompile" />
</ItemGroup>
<ItemGroup>
    <TypeScriptCompile Include="$(ProjectDir)\**\*.ts" Exclude="$(ProjectDir)\**\*.d.ts" />
</ItemGroup>
<Target Name="BeforeBuild">
    <Exec Command="&quot;$(PROGRAMFILES)\Microsoft SDKs\TypeScript\tsc&quot; 
	       -target ES5 @(TypeScriptCompile ->'&quot;%(fullpath)&quot;', ' ')" />
</Target>
						

Ή να ενεργοποιείσετε την επιλογή:

Tools/Options/Text Editor/Typescript/Project/
Automatically compile...

Intellisense σε Typescript

Πρέπει επίσης να κατεβάσετε τις βιβλιοθήκες με τους τύπους για intellisense

και αρχίζετε να νιώθετε πάλι κάπως έτσι

Δομές

Βασική αρχή να αποφύγετε τις extra βιβλιοθήκες όπου δεν χρειάζεται

Classes, Namespaces

Αποφύγετε τις WinJS.Namespace, WinJS.Class και προτιμήστε τον γενικό τρόπο δημιουργίας κλάσεων ή αυτόν που προκύπτει από Typescript ή CoffeeScript.


var ipplos=ipplos || {};

ipplos.MyClass=function(arg1,arg2){
	this.property1=0;
	this.property2=arg1;
	this.demoFunction=function(){
		//...
	}
}
						

DOM Selectors

Προτιμείστε τους ECMAScript5 selectors (querySelector, querySelectorAll) αντί αυτού από την jQuery ($)


document.querySelector("div .class")

// αντί για

$("div .class")
						

Promises - Ασύγχρονες κλήσεις

Όλες οι κλήσεις του WinJS είναι ασύγχρονες ώστε το UI να είναι πάντα responsive

Τα WinJS τις διαχειρίζονται με Promises.

Τι καλό όμως έχουν τα Promises;

Χρήση Callbacks

Φανταστείτε τον ακόλουθο κώδικα που θέτει μια ασύγχρονη αναμονή


ipplos.AsycWithCallbacks = function () {
    this.waitFor=function(time,callback){
        setTimeout(callback,time);
    }
}

// Χρήση

asyncWithCallbackResult.innerText = "Μετράω 3 δευτερόλεπτα";
var async = new ipplos.AsycWithCallbacks();
async.waitFor(3000, function () {
    asyncWithCallbackResult.innerText = "Τα 3 δευτερόλεπτα πέρασαν";
});
						

Προβλήματα;

Προβλήματα με τα Callbacks


ipplos.AsycWithCallbacks = function () {
    this.waitFor=function(time,callback){
        setTimeout(callback,time);
    }
}

// Χρήση

asyncWithCallbackResult.innerText = "Μετράω 3 δευτερόλεπτα";
var async = new ipplos.AsycWithCallbacks();
async.waitFor(3000, function () {
    asyncWithCallbackResult.innerText = "Τα 3 δευτερόλεπτα πέρασαν";
});
						
  • Πρέπει να ελέγξετε αν είναι undefined ή null το callback
  • Και αν θέλετε να εκτελεστούν δύο μέθοδοι;
  • Και αν θέλετε να συγχρονίσετε δύο ασύγχρονες μεθόδους;
  • Την ώρα που εκτελείτε την μέθοδο πρέπει να δώσετε το callback

Λύση με χρήση promises

Δήλωση


ipplos.AsyncWithPromise = function () {
    this.waitFor = function (time) {
        return new WinJS.Promise(function (complete, error, progress) {
            setTimeout(complete,time);
        });
    }
}
						

Χρήση


twoAsyncWithPromiseResult.innerHTML = "Μετράω 3 δευτερόλεπτα
" var async = new ipplos.AsyncWithPromise(); var promise = async.waitFor(3000); promise.then(function () { twoAsyncWithPromiseResult.innerHTML += "Τα 3 δευτερόλεπτα πέρασαν
"; });

Δε χρειάζεται να δηλώσετε το callback αμέσως

Επίσης (Promises)

Μπορείτε να δηλώσετε παραπάνω από ένα callbacks


twoAsyncWithPromiseResult.innerHTML = "Μετράω 3 δευτερόλεπτα
" var async = new ipplos.AsyncWithPromise(); var promise = async.waitFor(3000); promise.then(function () { twoAsyncWithPromiseResult.innerHTML += "Τα 3 δευτερόλεπτα πέρασαν
"; }); promise.then(function () { twoAsyncWithPromiseResult.innerHTML += "Τα 3 δευτερόλεπτα πέρασαν ξανά
"; });

και να συγρονίσετε δύο ή περισσότερα Promises!


twoAsyncWithPromiseResult.innerHTML = "Μετράω 3 δευτερόλεπτα
" var async = new ipplos.AsyncWithPromise(); var promise = async.waitFor(3000); promise.then(function () { twoAsyncWithPromiseSequentiallyResult.innerHTML = "Τα 3 δευτερόλεπτα πέρασαν
"; return async.waitFor(5000); }) .then(function () { twoAsyncWithPromiseSequentiallyResult.innerHTML += "Τα 5 δευτερόλεπτα πέρασαν
"; });

Βοηθητικές μέθοδοι (Promises)

  • setPromise: Όταν είστε σε event handler
  • join: Για να φτιάξετε ένα νέο promise που εκπληρώνεται με ένα σύνολο από άλλα
  • wrap: Φτιάχνει ένα promise object από μέθοδο που δεν είναι
  • any: Εκπληρώνεται όταν ένα από τα promises

Πηγές

AJAX Κλήσεις για δεδομένα

Προτιμείστε την WinJS.xhr από αυτήν που σας παρέχει μία βιβλιοθήκη

GET


var queryStringParams = 'Username=ipplos' + '&' + 'LangID=' + '1';
WinJS.xhr({ url: ipplos.urls.base + 'APIEndpoint?' + queryStringParams }).then(
 	function (serverData) {
		//...
});
						

POST


var formparams = 'Username=ipplos' + '&' + 'LangID=' + '1';
WinJS.xhr({ url: ipplos.urls.base + 'APIEndpoint',
            type: "POST",
            data: formparams,
            headers: { "Content-type": "application/x-www-form-urlencoded" }
		  }).then(
 	function (serverData) {
		//...
});
						

Και καταναλώστε ανάλογα

XML


WinJS.xhr({ url: ipplos.urls.base + 'APIEndpoint?' + queryStringParams }).then(
 	function (serverData) {
		var serverDataXML = = serverData.responseXML;
		//... serverDataXML.querySelector("...")
});
						

JSON


WinJS.xhr({ url: ipplos.urls.base + 'APIEndpoint?' + queryStringParams }).then(
 	function (serverData) {
		var serverDataObj = JSON.parse(serverData.response);
		//...
});
						

Ajaxify your data!

XML or JSON

Δύο αντιπροσωπευτικά είδη εφαρμογών

Single Page Applications (SPA)

Παιχνίδι, χρηστική, γενικά εφαρμογές σε javascript που δεν αλλάζουν σελίδα στον browser

Πηγή: Windows 8 Design Inspiration

Master - Detail εφαρμογές

Παρουσίαση συγκεκριμένης πληροφορίας οργανωμένη σε κατηγορίες - υποκατηγορίες με master - detail δομη αλλά και εφαρμογές με αυτή τη δομή

Πηγή: Windows 8 Design Inspiration

Single Page Applications (SPA)

Πρακτικά πολύ λίγες αλλαγές

Master - Detail Web Εφαρμογές

  • Τα δεδομένα σας τα διαχειριζεστε "server-side"
  • Μετάβαση από σελίδα σε σελίδα με αλλαγή URL (Stateless!)
  • Διατήρηση πληροφοριών με Session ή Client side data

Page-Control Navigation

WinJS.UI.PageControl

Δουλεύει με DOM code injection.

Με τον τρόπο αυτό διατηρεί την ψευδαίσθηση κοινού context μεταβλητών και στοιχείων μεταξύ των σελίδων

Page Control Anatomy (html)

Page Control Anatomy (js)

Και η οργάνωση .js και .css αρχείων σε κάθε σελίδα;

Page-Control Navigation

Χρήσιμα να θυμόμαστε

  • Ένα pool για όλα τα .css και .js ανεξάρτητα του που εμφανίζονται
  • Άρα τα αρχεία τοποθετούνται στις .html σελίδες μόνο για λόγους οργάνωσης (Intellisense)
  • Αυστηρή οργάνωση των .css rules σε κάθε σελίδα με full-path qualified names (SASS)
  • Όχι κώδικα στην HTML γιατί θα τρέξει μόνο μία φορά
  • Όχι αρχικοποιήσεις κατευθείαν στο Page Control αντικείμενο

Model-View View-Model

Δηλωτικός τρόπος δημιουργίας και ενημέρωσης του UI

WinJS Data Binding επιλογές

Αλλά και άλλα frameworks

  • Knockoutjs
  • Angularjs
  • ...

Οτιδήποτε χρησιμοποιείτε στο web με μία επιφύλαξη...

Localization

  • Χρήση resource files για την κάθε γλώσσα (strings/el-GR/resources.resjson)
  • Δήλωση του default-languages στο manifest
  • Αναφορά στα resources μέσω binding data-win-res="{winControl: {label:'addToMyGuide'}}"
  • Μπορείτε να "force" μία γλώσσα με κώδικα
  • Ενεργοποίση με εντολή WinJS.Resources.processAll();

Authentication

  • Ξεχνάμε το Forms Authentication
  • Ξεχνάμε το Basic Autentication
  • Υλοποίούμε το service μας με token
  • Χρησιμοποιούμε Auth, OpenID

Authentication Service Broker

Ευχαριστώ

Από ένα Web App σε ένα Windows 8.1 App

Γιάννης Παναγόπουλος http://www.progware.org/blog / @ipplos