Showing posts with label SEO. Show all posts
Showing posts with label SEO. Show all posts
Tuesday, October 6, 2015
Do we need HTML and CSS when we got JavaScript or more? A case for AbsurdJS, Meteor, Famo.us and CoffeeScript.
Introduction
AbsurdJS is an amazing project. What is it about? A processor for your HTML and CSS in JavaScript. In JSON to be more precise.The problem
CSS was invented for designers. But do you really know that much designers that are able to provide you with a nice CSS rules that will be awesome on all screens? You are favored by gods if it is your case. Most of the time, they will provide you with some PSD (what an ugly form of design), AI (if you are lucky), Sketch or SVG (here, it is not anymore based on luck, it is like having an angel upon your shoulders).The same goes with HTML. Semantics that appears with HTML5 were added for SEO. But do you know that much SEO guys that will give you the right HTML code? I haven't seen any in my whole 20 years on the web carrier(though SEO is not that long of a job).
Thus, why are we using 3 languages for writing our codes. Is that right? Do we have to? Is it done for helping us and keeping separation of concerns? Funny. Patterns like this exists since the dawn of design patterns from the GoF. And what if we need to synchronize this HTML, CSS and JS back together for animations purposes? We request back in our code the HTML tags that we have just declared? We hooks on the CSS? If we need a color theme, do we have to write it twice or more? Funny, too. Even media queries for responsive web designs, seems like an odd way of reproducing the abstract factory pattern (or the bridge depending on if you know to who you are distributing your files).
The solutions
There are many. Generally, I was keen on using preprocessors: SASS, LESS, Stylus, YAML, Jade, Blade, CoffeeScript, Typescript, Dart, ... But, it finally does not give me a proper answer to the problems previously mentioned. It still need glue code to make all of this work together properly. Things started to shape up when I end up using Meteor, Famo.us and Velocity.js. The Blaze component of Meteor is transforming your HTML, more precisely, your HTML templates using Spacebar, a derivative of Mustache, into JS code. The same goes with Famo.us. It creates HTML and CSS rules that plays well together so that they limit layout trashing issues and combines this technics with advanced physic and animation engine. The same goes with Velocity.js. This jQuery plugins brings back synchronized CSS animations in with JS.Still, plain vanilla JavaScript is a pain to write. While there are plenty of transpilers that could lessen the burden (like Dart and Typescript, to mention the most used ones), none have proven to be as easy as CoffeeScript to me.
Conclusion
Now the solution starts to shape up. Why not use the power of AbsurdJS, Meteor, Famo.us and CoffeeScript? This combination would be a real full stack. It would goes from the persistance layer, the application server to the front end with one and only one language. A transpiled one that even lessen the number of lines that you need to write.
Labels:
CoffeeScript,
Innovation,
Jade,
Meteor,
Meteor.js,
SEO,
WPO
The fastest loading screen for Meteor
Introduction
Meteor offers a great way to build web apps at an incomparable speed. It leverages the power of Javascript anywhere. In production, its powerful server side build system named Isobuild transpiles all your HTML files into JS files, thanks to Blaze, and packs them with your JS files. This operation leads to a single JS file loaded by a tiny initial HTML loader that bootstraps your app.Depending on your development strategy, this single JS file can end up very fat. This could seriously annoy your first time users who will wait many seconds before seing something on their screen. Of course, proxying your servers with Gzip or SPDY capable fronts greatly helps lowering this initial loading. Truncating this JS file could also help. Using a multiple domains strategy and CDNs also offer great loading time cuts. Still, on mobile, with a bad network access like GPRS, these several seconds rapidly become a problem. To understand the ins and outs of web performance optimization, WPO, I strongly recommend reading the book High Performance Browser Networking by Ilya Grigorik.
What is this about?
Not to be confused with the great masterpiece fast render from Arunoda Susiripala which is used for fastening the initial data required from your collections, the technic that I expose hereafter tackles the initial page load time, PLT. The first paints on the screen, if you prefer. This first paint comes even before the tiny initial HTML loader is fully loaded by your users's terminal.On a regular Meteor app, while your users connect to your site and till the initial load of the JS file, their browser remains blank. Of course, they could see that something is happening. Almost all browser display at least a progress indicator. But users may not notice it and think that your site is either dead or hosted on a distant other planet. That is just very bad for user acquisition, isn't it? If you want to better understand how this affects user's perceptions as well as your search engine optimization strategy, SEO, Paul Irish has covered this in great details in his incredibly informative talk: Fast enough (check the comments for the slides and the Youtube video). What you need to know is that your PLT will be nice if your initial screen painting is under 14k. That seems like an impossible goal to achieve with an out-of-the-box Meteor app with an average weight of ~50k of compressed initial JS file.
But Meteor is far from being a classic website approach and is definitely not a low end build tool. You can use the raw power of its Isobuild to ask your servers for an injection of your initial screen content directly within the tiny initial HTML loader. It is the key to unlock the 14k barrier.
Performing the injection
This could be a bit scary for the majority of Meteor devs. But once again, Arunoda has you well covered. By using another great masterpiece from Arunoda and Gadi Cohen, this injection process is a no brainer: inject initial. Let us jump in the code.In your app, installing inject initial is the one step classical stance:
meteor add meteorhacks:inject-initialFor the sake of brevity, the codes hereafter are in CoffeeScript.
In your server code, you can perform the initial injection. Hereafter, I'm just putting a little CSS spinner. Nothing fancy.
/server/startup.coffee
Inject.rawHead 'loader-style',Here we have somewhat altered, the DOM structure of our app. Indeed, we have just created a body while the head of your your initial HTML loader wasn't even finished to get build. Is that a big problem? No. Your server will carry on filling the rest of your app in the body section that you have created (the styles, the scripts, ...).
# Force the initial scale for Android and iOS as our spinner may be
# distorted by their default viewport values.
'<meta name="viewport" content="width=device-width,maximum-scale=1,' +
'initial-scale=1,user-scalable=no">' +
# The loading spinner needs some theming.
'<style>' +
'html{background-color: #36342e;}' +
'body{color:#ddd;overflow:hidden;width:100%;}' +
'.spinner {' +
'bottom:0;height:80px;left:0;margin:auto;position:absolute;' +
'top:0;right:0;width:80px;' +
'-webkit-animation: rotation .6s infinite linear;' +
'animation: rotation .6s infinite linear;' +
'border-left:6px solid rgba(255,194,0,.20);' +
'border-right:6px solid rgba(255,194,0,.20);' +
'border-bottom:6px solid rgba(255,194,0,.20);' +
'border-top:6px solid rgba(255,194,0,.9);' +
'border-radius:100%;' +
'}' +
'@-webkit-keyframes rotation {' +
'from {-webkit-transform: rotate(0deg);}' +
'to {-webkit-transform: rotate(359deg);}' +
'}' +
'@-moz-keyframes rotation {' +
'from {-moz-transform: rotate(0deg);}' +
'to {-moz-transform: rotate(359deg);}' +
'}' +
'@-o-keyframes rotation {' +
'from {-o-transform: rotate(0deg);}' +
'to {-o-transform: rotate(359deg);}' +
'}' +
'@keyframes rotation {' +
'from {transform: rotate(0deg);}' +
'to {transform: rotate(359deg);}' +
'}' +
'</style>'
# The loading spinner is a CSS animation.
# /!\ WARNING: The trick is to create a fake body by injecting data
# in the HTML's head as Meteor is requesting JS file in a blocking
# fashion and mobile only allow 1 HTTP request at a time on a GPRS network.
Inject.rawHead 'loader-body2', '<body><div class="spinner"></div></body>'
At this point, you could tell me: "But wait? There is now a title and meta tags in the body of my app. That's just a disgusting code.". You are right. But the browsers are really not impacted by this. I could reply back: "Who care?". But, indeed, I care. Simply because one of the biggest interest of web technology is that all your codes are readable. It is important to let other developers having the possibility to understand how stuff works. It is part of the learning legacy that we owe to the web. So let us put things in the correct order.
Cleaning our loaded codes is done directly on the client side. We do that once everything is loaded. No hurry as it has no impact except a good readability of our DOM structure.
/client/startup.coffee
Meteor.startup ->That's it. Nice and clean.
# Reshape DOM: put back title and meta elements in the head.
# style and script tags can leave in the body tag.
$head = $ 'head'
for tag in ['meta', 'title']
$tags = $ tag
$head.append $tags.clone()
$tags.remove()
Testing it
There are several ways of testing these results and their behavior. On Mac, I use Network link conditionner, a handy tool provided by Apple. It allows you to modify the behavior of you TCP stack and use GPRS, 3G, ... profiles. Very neat when you are testing hybrid or native apps.If you are testing full web apps, I strongly recommend using Chrome DevTools. The mobile emulator as a special feature allowing to change the network throttling.
Some constraints you need to be aware of
When your initial HTML loader and your initial JS file are being loaded, the JS engine and the SVG rendering engine are paused. I've always been annoyed by this browser behavior but we have to live with it. Thus, you can't put JS loaders or SVG animated loaders. You should favor CSS loader and choose the one that will be the less CPU intensive. Here, you should favor CSS3 animated loader which are animated by the GPU as the CPU will be intensively interpreting what it is finishing pumping from you servers.A side note to finish this little article. This technic is not here to bypass the necessary work of making your app as lightweight as possible. It is still a good practice to ensure that your app will avoid consuming the data subscription of your users ;-)
Location:
Paris, France
Subscribe to:
Posts (Atom)