Enough with the JavaScript Already!
Nicholas C. Zakas@slicknet
@slicknet
Complaints: @souders
2004
2005
http://www.adaptivepath.com/ideas/ajax-new-approach-web-applications
2006
2007
Atwood’s LawAny application that can be written in JavaScript, will eventually be written in JavaScript.
http://www.codinghorror.com/blog/2007/07/the-principle-of-least-power.html
2013
“Help, Nicholas! Our JavaScript is killing our site performance!”
- Everyone who contacted me while consulting
> 1 MB*JavaScript loaded during page load
* Un-gzipped
Server HTML CSS JavaScript
Rendering HTML
Constructing URLs
Calculating dependencies
Redirecting
Document structure
Native functionality
Accessibility
Layout
Colors
Visibility
Animation
Handling Events
Ajax
Changing UI
Server HTML CSS JavaScript
Rendering HTML
Constructing URLs
Calculating dependencies
Redirecting
Document structure
Native functionality
Accessibility
Layout
Colors
Visibility
Animation
Handling Events
Ajax
Changing UI
Source: HTTP Archive
256 KB
260 KB 993.96 KB
793.5 KB
1570.4 KB503 KB
196 KB 568.7 KB
Gzipped Un-gzipped
Time Spent During a Project
0%10%20%30%40%50%60%70%80%90%
100%
HTMLCSSJavaScript
Client-Side Rendering
Hogan.js{dust.js}EJS
“It's no longer good enough to build web apps around full page loads and then progressively enhance them to behave more dynamically.”
- throneofjs.com
https://www.facebook.com/help/189391594506832/
“To improve the twitter.com experience for everyone, we've been working to take back control of our front-end performance by moving the rendering to the server.
This has allowed us to drop our initial page load times to 1/5th of what they were previously and reduce
differences in performance across browsers.”
https://blog.twitter.com/2012/improving-performance-twittercom
“Our thesis [was] if we have a JavaScript runtime on the server, we should be able to pull most of this application logic back down to the server in a way that can be
shared with the client. Your great new product can run on both sides of the wire, serving up real HTML on first pageload, but then kicking off a client-side JavaScript app.”
http://nerds.airbnb.com/weve-launched-our-first-nodejs-app-to-product
“…we re-launched our Mobile Web site using this new stack, replacing the Backbone.js + Rails stack that it used previously...It looks exactly the same as the app it replaced, however initial pageload feels drastically quicker because we serve up real HTML
instead of waiting for the client to download JavaScript before rendering. Plus, it is fully crawlable by search engines.”
http://nerds.airbnb.com/weve-launched-our-first-nodejs-app-to-product
The server & browser are better at this than us
Progressive enhancement still works
Unused JavaScript
60-65%JavaScript that was not executed by page load*
* My consulting clients
The 4 JavaScript Load Times
In <head>
Before </body>
After page load
On demand
Prerequisite:
What are the top 2-3 things users do on this page?
aka Prerequisite:
Analytics!
In <head>
https://support.google.com/analytics/answer/1008080?hl=en
“Once you find the code snippet, copy and paste it into your web page, just before the closing </head> tag*. If your website uses templates to generate pages, enter it just
before the closing </head> tag in the file that contains the<head> section.”
Scripts needed by page load
Before </body>
Before </body>
Scripts needed soon after page load
After page load
After page load
In reaction to user
On demand
On demand
http://alexsexton.com/blog/2013/03/deploying-javascript-applications/
http://alexsexton.com/blog/2013/03/deploying-javascript-applications/
JavaScript Libraries(they are big)
42.3 KB 115.0 KB
27.7 KB 90.9 KB
29.0 KB 81.5 KB
85.3 KB25.7 KB
Gzipped Un-gzipped
2.x
1.x
Library Code Component Code
Library Code Component Code
Library Code Component Code
Library Code Component Code
As JS Libraries Develop
0
10
20
30
40
50
60
70
80
90
100
0
2
4
6
8
10
12
14
16
Library CodeComponent CodeNumber of Components
JS Libraries and Economies of Scale
Cost perJavaScriptcomponent
Number of components
Library Code Component Code
Tabs
Tabs?
63.1 KB 120.8 KB
95.3 KB30.2 KB
Gzipped Un-gzipped
1.x
1.9 KB 5.0 KB
How?
Step 1Include HTML on the page
<div data-nui-type="tabview" class="nui-tabview"> <ol class="nui-tabs clearfix"> <li><a href="#">Tab 1</a></li> <li><a href="#">Tab 2</a></li> <li><a href="#">Tab 3</a></li> </ol> <div class="nui-tabpanels"> <div><p>Content 1</p></div> <div><p>Content 2</p></div> <div><p>Content 3</p></div> </div></div>
No JS yet!
Step 2Store UI state on the DOM
<div data-nui-type="tabview" class="nui-tabview"> <ol class="nui-tabs clearfix"> <li class="nui-selected"><a href="#">Tab 1</a></li> <li><a href="#">Tab 2</a></li> <li><a href="#">Tab 3</a></li> </ol> <div class="nui-tabpanels"> <div class="nui-selected"><p>Content 1</p></div> <div><p>Content 2</p></div> <div><p>Content 3</p></div> </div></div>
Selected tab
Selected panel
No JS yet!
Step 3Sprinkle in some JS
<script>nui.init();</script>
One call to initialize all instances
// none of thisvar tabview = new MyLibrary.TabView("#tabs", { selected: 1 });
// none of this$(“#tabs”).tabs();
Just add more
HTML!
<div data-nui-type="tabview" class="nui-tabview" data-nui-selected-index="0"> <ol class="nui-tabs clearfix" role="tablist"> <li class=" nui-selected" data-nui-index="0"><a id="nui0">Tab 1</a></li> <li data-nui-index="1"><a id="nui1">Tab 2</a></li> <li data-nui-index="2"><a id="nui2">Tab 3</a></li> </ol> <div class="nui-tabpanels"> <div class=" nui-selected"><p>Content 1</p></div> <div><p>Content 2</p></div> <div><p>Content 3</p></div> </div></div>
Sure, but I bet there’s no accessibility
Wrong
<div data-nui-type="tabview" class="nui-tabview" data-nui-selected-index="0"> <ol class="nui-tabs clearfix" role="tablist"> <li class=" nui-selected" data-nui-index="0" role="presentation"><a id="nui0" role="tab" tabindex="0">Tab 1</a></li> <li data-nui-index="1" role="presentation"><a id="nui1" role="tab" tabindex="-1">Tab 2</a></li> <li data-nui-index="2" role="presentation"><a id="nui2" role="tab" tabindex="-1">Tab 3</a></li> </ol> <div class="nui-tabpanels"> <div class=" nui-selected" role="tabpanel" aria-labelledby="nui0" tabindex="0"><p>Content 1</p></div> <div role="tabpanel" aria-labelledby="nui1" tabindex="-1" aria-hidden="true"><p>Content 2</p></div> <div role="tabpanel" aria-labelledby="nui2" tabindex="-1" aria-hidden="true"><p>Content 3</p></div> </div></div>
What the JavaScript does1. Look for tabviews via data-nui-type2. Read UI state based on classes3. Annotate DOM with additional information4. Use event delegation to watch for user
interaction5. Swap classes to react to events
https://github.com/nzakas/nui
Conclusion
Awesome!
OK
OK
Bad!
Bytes
Valu
e
Server HTML CSS JavaScript
Rendering HTML
Constructing URLs
Calculating dependencies
Redirecting
Document structure
Native functionality
Accessibility
Layout
Colors
Visibility
Animation
Handling Events
Ajax
Changing UI
The 4 JavaScript Load Times•Primarily analytics•Small seed filesIn <head>•Anything needed by page load•Minimal as possibleBefore </body>
•Anything needed soon afterAfter page load
•Anything needed as a result of user actionOn demand
JS Libraries and Economies of Scale
Cost perJavaScriptcomponent
Number of components
42.3 KB 115.0 KB
27.7 KB 90.9 KB
29.0 KB 81.5 KB
85.3 KB25.7 KB
Gzipped Un-gzipped
2.x
1.x
Thank you
Etcetera• My blog: nczonline.net• Twitter: @slicknet• These Slides: slideshare.net/nzakas