build lightweight web module
TRANSCRIPT
Build Lightweight Web Module
Morgan Cheng@morgancheng
May 26th, 2011
Expand Thriving Web Site
Inject Your Content Into Other Sites
Partner Website Server
Browser
Your Website Server
Partner Website Server
Browser
Your Website Server
Web Module
Cross Domain
JSONP
Inject Content with JSONP
• Create one hidden element• Send JSONP request • When JSONP data is received, compose HTML• Fill the hidden element with composed HTML• Show hidden element
Inject an iframe
iframe covering whole viewport
It is easy to create a big iframe. The hard part is how to close it.
Same Domain Callback
Hidden Proxy Iframe
Time to Wear Hacker’s Hat
Cannot be “javascript: … ”
Hidden Proxy Iframe
API Design First
<script src=“XXXXX_loader.js”></script>
<script> XXXXX.load(parameter);</script>
YAHOO.ABC.load(parameter);
YAHOO.ABC.load(parameter);Y.ABC.load(parameter);
YAHOO.ABC.load(parameter);Y.ABC.load(parameter);YABC.load(parameter);
YABC.load(‘wretch’, // appid. Mandatory1234, // spaceid. Mandatory100 // delay in ms. Optional
);
YABC.load(‘wretch’, // appid. Mandatory1234, // spaceid. Mandatory100, // delay in ms. Optional
‘tw’ // intl. Mandatory);
What if new Mandatory parameter is added?
YABC.load({ appid: ‘wretch’, spaceid: ‘1234’, delay: 100, intl: ‘tw’}); Better!
Config Object Pattern
Be Disciplined
Rules #1: Don’t Assume Too Much on Hosting Page
What?You Don’t Have YUI?
Rules #2: Don’t Be Obstructive to Hosting Page
Rules #3: Don’t Impact Hosting Page Performance
In a Word, We Have To DIY
And, It MUST Be Lightweight
Simplest Feature vs. Rich Feature
YAHOO.util.Connect.asyncRequest(‘GET’,‘http://www.example.com/jsonp’,{
success: sucessHandler,failure: failureHandler,argument: argumentObj
},postData
};
YAHOO.util.Connect.asyncRequest(‘GET’,‘http://www.example.com/jsonp’,{
success: sucessHandler,failure: failureHandler,argument: argumentObj
},postData
};
We Don’t Need Full Feature
This is What We Need
Minify-Friendly JavaScript
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Minify
Before 287 bytesAfter 119 bytesCompression Rate: 59%
What Can Be Minified?
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Comments are stripped
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Unnecessary White Spaces are Stripped
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Argument Names are Obfuscated
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Local Variable Names are Minified
What Can NOT Be Minified?
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Keywords are NOT Minified
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Global Variables are NOT Minified
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
Object Properties are NOT Minified
/* * Gets query string presentation of given object. */function toQueryString(params) { var encParams = [], encode = encodeURIComponent; for(key in params) { encParams.push(encode(key) + '=' + encode(params[key])); } return encParams.join('&');}
function toQueryString(c){var a=[],b=encodeURIComponent;for(key in c){a.push(b(key)+"="+b(c[key]))}return a.join("&")};
How About This?
Wait, Do We Need Minify If All Browsers
Support Gzip?
Gzip is no-loss compressionIt Doesn’t Understand JavaScript
JavaScript?
Gzip
~15% “Accept-Encoding: gzip, deflate”HTTP Headers Are Stripped
Evolution of Code
YABC = { load: function() {
// do something }};
YABC = { privateVariable: ‘hello’, privateFunction: function() { // do some private thing }, load: function() {
// do something }};
YABC = {privateVariable: ‘hello’, privateFunction: function() {
// do some helping }, load: function() {
// do something }};
Not Minifiable
(function() { var _privateVariable = ‘hello’;
function _privateFunction () {// do some private thing
}
YABC = { load: function() {
// do something }};
}())
Immediate Function Pattern
(function() { var _privateVariable = ‘hello’;
function _privateFunction () {// do some private thing
}
YABC = { load: function() {
// do something }};
}())
Minifiable
(function() { var win = window;
_privateVariable = ‘hello’;
function _privateFunction () {// do some private thing
}
YABC = { load: function() {
// do something }};
}())
“window” is used more than once
(function() { var win = window;
_privateVariable = ‘hello’;
function _privateFunction () {// do some private thing
}
YABC = { unload: function() { }, load: function() {
// do something }};
}())
(function() { var win = window;
_privateVariable = ‘hello’;
function _privateFunction () {// do some private thing
}
YABC = { unload: function() { }, load: function() {
// do something }};
}())
Every invocation of this method has to be “YABC.unload”
(function() { var win = window;
_privateVariable = ‘hello’,yabc;
function _privateFunction () {// do some private thing
}
var yabc = { unload: function() { }, load: function() {
// do something }};
YABC = yabc;}())
Local Invocation of “yabc.unload” can be minfied
(function() { var win = window;
_privateVariable = ‘hello’,yabc;
function _privateFunction () {// do some private thing
}
var yabc = { unload: function() { }, load: function() {
// do something }};
YABC = yabc;}())
YUI Developers,Looks Familiar?
Be a JavaScript Ninjia
(function() {// immediate functioning
}())
(function() {// immediate functioning
}())
!function() {// immediate functioning
}()
Saving 1 Byte
if (-1===indexOf(foo,’bar’)) {// do something
}
if (-1!==foo.indexOf(’bar’)) {// do something
}
if (~foo.indexOf(’bar’)) {// do something
}
Saving 4 Bytes
function escapeHTML(s) {return s.replace(/&/g, '&').replace(/>/g, '>').replace(/</g,'<').replace(/"/g, '"').replace(/'/g,''').replace(/\//g,'/');
}
function escapeHTML(s) {return s.replace(/&/g, '&').replace(/>/g, '>').replace(/</g,'<').replace(/"/g, '"').replace(/'/g,''').replace(/\//g,'/');
}
function escapeHTML(s, r) {r='replace';return s[r](/&/g,'&')[r](/>/g,'>')[r](/</g,'<')[r](/"/g, '"')[r](/'/g,''')[r](/\//g,'/’);
}
Saving 19 Bytes
History of code size
Raw Minified Gzipped Minfied + Gzipped
Prototype 14858 7817 4585 3262
Strip Functionality 8311 3755 3720 1901
minify-Friendly 8109 3664 3317 1809
JavaScript is NOT SlowBut, DOM is Slow
Module Versioning
Traditionally …
• http://www.example.com/v1/loader.js
• http://www.example.com/loader_20110510.js
Short Time Caching
Takeaways
• Make your partners happy
• Hack your own code. Hack it Hard!
• Minify JavaScript Code
Thank You!