AppGyver Steroids/Supersonic debugging
Contents |
Because of an upcoming project I’m currently working my way through AppGyver Steroid / Supersonic. The idea is nice, develop once, deploy on both mobile platforms… However it has it quirks. These are however not the point of this post.
What I’ll be describing is the problems I’ve run in to and how I’ve solved them.
Debugging nightmare
According to the docs there are many ways to debug. However I found some don’t work and well at times locally is best. Here are a few tips.
Logging
The Steroids guide tells you multiple times that you can use supersonic.logger.log('Log me!');
.
This however does not work. It has to do with timing issues. This sucks, after some searching around someone on the forums pointed out how to solve this. Also see this Github Issue.
setTimeout(function(){
supersonic.logger.log('I log because I do not have a racecondition!');
},1);
Debug Javascript outside the iOS simulator
On Mac OS X Steroids expects you to always debug inside the iOS Simulator. Kinda cool, however if the lower end of AngularJS breaks (which it will) you are kinda left in the dark. Hooray for trickery.
Grab a small HTTP server that can run from a directory, I picked http-server.
Copying the Module to Debug
We must know which Module you want to debug. As every Module is rendered as an entire AngularJS ng-app
on it’s own it’s easy to debug, if you know how.
Now in your Terminal, go to the root of your Steroids project and do the following:
cd dist
cp theNameOfYourModule/theNameOfTheView.html .
http-server
Debug in your favourite browser
Now open up http://0.0.0.0:8080
in your browser, e.g. Chrome and fire up the Inspector. Behold! Debug information. Now you’ll be able to catch those small crazy syntax errors that Steroids does not leak through to their Console.
Rinse and repeat
As a simple one-liner I use the following when I’m debugging specific code:
cd .. && cd dist && cp app/theNameOfYourModule/theNameOfTheView.html . && http-server
The first is needed because after the files have been replaced by Steroids (well grunt
more likely but hey) the http-server
will have crashed and the local dir is no more (Terminal also lost track, the entire dir was removed). By changing to the dir above and back in right away you only have to move the cursor once in your terminal in total to restart the debugging fun.
AngularJS provider
Now this one should be relatively easy but it gave me a considerable headache before I figured out to say “the hell with it” and just hardcode something into the common
.
Let’s assume you have your own REST API and don’t want to use the wrappers Supersonic provides, now you do want abstraction and clean code… I mean who doesn’t?
Provider? Factory? Service? dafuq?
Blame AngularJS: https://docs.angularjs.org/guide/providers
Directory preparation
First create a dir inside app/
, let’s call it beersFactory
and make a file called index.js
. The reason for this is that Steroids will automatically copy every Module’s index.js
as app/moduleName.js
to dist/
.
Simple Factory
Now fill the file app/beersFactory/index.js
with the following
// Module name is beersFactory
angular.module('beersFactory', [
// Declare any module-specific AngularJS dependencies here
'supersonic'
]);
angular.module('beersFactory')
// the Factory name is called Beer, do not confuse the two
.factory('Beer', function($http, $q, supersonic) {
setTimeout(function(){
supersonic.logger.log('I am the BeerFactory!' );
},1);
return {
get: function get() {
return 'foo';
setTimeout(function(){
supersonic.logger.log('I am the default method called' );
},1);
},
doSomethingFunky: function somethingFunkyWillBeDone(withAVar) {
return 'bar';
}
}
}
);
Layout modification
Now we open up app/common/views/layout.html
and add this line above the _.each
<script
src=
"/app/beersFactory.js"
></script>
It will look something like this:
<script src="/app/beersFactory.js"></script>
<% _.each(yield.modules, function(module) { %>
<script src="/app/<%= module %>.js"></script>
<% }); %>
</head>
Common modification
Now we must edit the following file app/common/index.js
and make it look like the following (or similar at least).
angular
.module('common', [
'supersonic',
'beerFactory'
]);
Now in every Module that you include common
you’ll have beerFactory
injected.
Other module
Just make sure to add the beerFactory
inside your Module’s Controller and you are good to go, let’s assume we have the following file app/beers/scripts/IndexController.js
, add the new Provider.
// here we use the Factory name! Not the Module's!
.controller('IndexController', function($scope, supersonic, Beer) {
Finishing touches
Now you’ll be able to use the BeerFactory in your code and seperate that awful $http logic from the rest of your Controller. Be sure to defer your returns.
Defer
Ok quick bonus, cause I am writing now anyway ;) Here’s how to defer from your Factory so your code at least waits.
However be sure to checkout the AngularJS docs about it.
Inside the Factory:
get: function get() {
return $q(function (resolve, reject) {
// some code that does something and works
// it creates an object called data
resolve(data);
// in case it fails it creates another object called reason
reject(reason);
}
}
Now inside your Controller use this:
var promise = Beer.get();
promise.then(function(data) {
// now do something but with the returned data object
$scope.beers = data;
}, function(failboat) {
// do something with the error
console.log(failboat);
});
Final thoughts
I’m still treading lightly into the world that is known as Steroids/Supersonic. I can’t say I’m too impressed. Documentation is a serious issue. If any it’s filled with mistakes and other mishaps. Also, who has documentation without a Search function? It also doesn’t help their name is well, linked to things bodybuilders take to buff themselves even more. Community seems to not exist at all (at least on IRC).
If you noticed any mistakes on this page, please let me know.