Wednesday, April 24, 2013

Deferred Loading

On my job we are trying to decrease time for loading pages as much as it is possible, we simply want 'fast pages'. We don't want our users waited for 2 seconds each time they load page. We are focusing to keep not more then 0.5-1 second per page and we are doing really a lot in that area. Nowadays It's quite common for most of websites to include javascripts just in head area (or at bottom area) as static html so each time we load pages they will be not responsive till all resources will be loaded. I want to share how to load of javascript files (or any another resouces) just after page loads. It could increase speed dramatically. This solution loads all javascrip files deferred after page load on onload event. That snippet should be minimized and be present on every page where you want to use deferred loading.

Snippet of deferred loader
(function(){
 function deferred(success){
    if (typeof window.onload != 'function') {
   window.onload = success;
  } else {
   var old = window.onload ;
   window.onload = function() {
    old();
    success();
   }
  }
 }

 function getScript(url,success){
  var script=document.createElement('script');
  script.src=url;
  var head=document.getElementsByTagName('head')[0],done=false;
  script.onload=script.onreadystatechange = function(){
    if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
   done=true;
   success();
   script.onload = script.onreadystatechange = null;
   head.removeChild(script);
    }
  };
  head.appendChild(script);
 }

 function getScripts(urls, success){
  var total = 0;
  function trySuccess(){
   total++;
   if(total == urls.length)success();
  }
  
  for (var i = 0; i < urls.length; i++) {
   getScript(urls[i],trySuccess);
  }
 }
 
 var DeferredLoader = window.DeferredLoader = {};
 DeferredLoader.getScript = getScript;
 DeferredLoader.getScripts = getScripts;
 DeferredLoader.deferred= deferred;
})();

How to use loading, in that example we load jQuery, then when it's loaded we load kissmetrics libraries and only then utils.
var urls = {
 jquery: "/javascript/jquery-1.9.1.min.js",
 dependent: ["/javascript/util-2013-04-10m.js"],
 kissmetrics:['//i.kissmetrics.com/i.js','//doug1izaerwt3.cloudfront.net/' + window._kmk + '.1.js' ]
};

DeferredLoader.deferred(function () {
 DeferredLoader.getScript(urls.jquery, function () {
  DeferredLoader.getScripts(urls.kissmetrics, function () {
   DeferredLoader.getScripts(urls.dependent, function(){})
  })
 })
})

Wednesday, March 06, 2013

Rewriting URL in Domino using DSAPI

I will briefly describe what we were aiming to achieve. In order to open page with parameters Domino requires to add ?open or ?opendocument action and only after that Domino allows to add parameters. It's quite annoying for us due to some integration with another systems, those systems expect they can simply add parameters just after our pages, i.e.: http://www.host/page?parameter=123 etc. Also important reason - we simply do not like this ?open or ?opendocument in URL.

we want to be able to that:
www.host/page?opendocument&parameter=123 ==> www.host/page?parameter=123

I got couple helpful comments in my previous article about URL control in Domino, that helped me to look on different solutions, thanks guys. However I decided that those solutions a bit complicated to setup and they could do some impact on page load time.

I've been working on DSAPI solution last days and finally with some help I've made it! Now we have full control with our URLs, at least I've such feeling :). Let me share my small success to all of you.

Here you can find main steps you need to do. Please keep in mind, I've updated my code a bit as our logic has many rules when exactly to add parameters.

1. Enable flag to catch Rewrite URL event.
filterInitData->eventFlags = kFilterRewriteURL;
2. Link 'rewrite URL' event with you function.
DLLEXPORT unsigned int HttpFilterProc(FilterContext* context, unsigned int eventType, void* eventData) {
 switch (eventType) {
  case kFilterRewriteURL:
   return RewriteURL(context, (FilterMapURL *) eventData);
  default:
   return kFilterNotHandled;
 }
}
3. Finally the main logic, that makes URL rewriting.
int RewriteURL(FilterContext* context, FilterMapURL* pEventData) {
 FilterParsedRequestLine pReqData;
 unsigned int errid=0;

 // if there are no parameters in URL - nothing to do.
 if (strstr(pEventData->url, "?")==NULL) return kFilterNotHandled;
 // read request as we are going to update query.
 context->ServerSupport(context, kGetParsedRequest, &pReqData, NULL, NULL, &errid);
 // if query starts from opendocument - nothing to do
 if (strncmp(pReqData.pQueryUri, "opendocument", strlen("opendocument"))==0) return kFilterNotHandled;
 // adding opendocument before query and put result in pEventData->pathBuffer
 sprintf(pEventData->pathBuffer, "%s?opendocument&%s", pReqData.pPathUri, pReqData.pQueryUri);

 return kFilterHandledEvent;
}
Solution we did works like a charm and what is very important it does not affect page load time (we measured of course)

Related topics
DSAPI for Domino
Solution for Lotus Domino to the trailing slash problem
Replacement for DSAPI in Java/XPages

Sunday, March 03, 2013

Mongodb - Enable Authentication

Basically it is very easy to do,
  • 1. open mongodb shell
  • 2. open admin db and add admin user (you need to have 1 user otherwise you can' lose access to your databases at all)
  • use admin
    db.addUser("admin","12345")
    
  • 3. Enable authentication auth=true (simply un-comment it) in config file 'sudo vi /etc/mongodb.conf', save changes and restart mongodb service
  • sudo service mongodb restart
    
For more information please read Security Practices and Management

Wednesday, February 27, 2013

Fighting for control of URL in Domino

We have really annoying problem for years with our URLs on all websites based on Domino. We use classic approach because we want control all tags + we like jQuery more etc. Our problem is about mandatory action [?open | ?opendocument] for pages with parameters, so if you want to add parameters to your page (i.e. param1=123) you have to add [?open | ?opendocument] just after your URL and only then you are allowed to add parameters.

Not really a huge problem, however we want to use new tracking code from google. That tracking has problems with [?open | ?opendocument]: it does not work correctly in case if first parameter is ?open. So now its blocker for us and we want to fix it for all another cases as well. We want to have possibility get rid off ?open | ?opendocument

Question in few words: "is it possible to get this URL working?"
http://www.e-conomic.com/accountingsoftware?parameter=123
instead of this
http://www.e-conomic.com/accountingsoftware?open&parameter=123

We've tried redirect, substitutions - no success ofc :(.

Next in my queue is DSAPI and I'm sure it can solve that problem (at least from documentation) however I'm not able to do that due to my experience with DSAPI and very very low information in the web.

I've played with different events in DSAPI: kFilterStartRequest, kFilterRawRequest and kFilterRewriteURL and tried to change incoming URL from request but did not success with it. Does any of you guys can give me tips :) what I do wrong or maybe there is another solution how to achieve that quest?

Tuesday, February 05, 2013

Nodejs and compression of HTML, JS, CSS

To decrease loading time for pages, it is always nice to minify your HTML, CSS and JS. Also to decrease number of requests we inject our minified CSS/JS directly on our pages (ofc we will do that unless our CSS/JS have small size), so minus 2 requests to all pages.

Now time to write couple lines of real code

1. UglifyJS - compress JS

var uglifyJS = require("uglify-js");

var result = uglifyJS.minify("filename.js");
console.log(result.code);

2. Sqwish - compress CSS

var sqwish = require('sqwish');
var filename=app.get('filename.css');
fs.readFile(filename, 'utf8', function(err, data) {
    if (err) throw err;
    var minifiedCss = sqwish.minify(data)
    console.log(minifiedCss);
})

3. HTMLMinifier - compress HTML

var htmlminifier = require('html-minifier');
var minifiedHTML = htmlminifier.minify(data, {
 removeComments: true,
 removeCommentsFromCDATA: true,
 collapseWhitespace: true,
 collapseBooleanAttributes: true,
 removeAttributeQuotes: true,
 removeEmptyAttributes: true
});
So at the result we decreased size of our pages a lot and also decreased number of requests which is also nice, we all love "fast pages".