From 134d1c1b95318e39f693adfcd58076a87b88308c Mon Sep 17 00:00:00 2001 From: Adam Hull Date: Sun, 28 Sep 2014 22:28:32 -0700 Subject: [PATCH 1/4] Post about our server side responsive setup --- ...er-side-responsive-express-varnish.html.md | 83 ++++++++++++++++++ .../flow.jpg | Bin 0 -> 18426 bytes 2 files changed, 83 insertions(+) create mode 100644 src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md create mode 100644 src/files/images/posts/server-side-responsive-express-varnish/flow.jpg diff --git a/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md b/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md new file mode 100644 index 0000000..01842a7 --- /dev/null +++ b/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md @@ -0,0 +1,83 @@ +--- +title: Server Side Responsive with Express and Varnish +author: Adam Hull +layout: post +disqus: + shortname: goodeggsbytes + url: "http://bytes.goodeggs.com/post/server-side-responsive-express-varnish" +--- + +Conversations about responsive design often focus on the browser: media queries, grids, and the like, but there's more! A great experience on all manner of consumer-grade doo-dads demands some work on the server. + +For example, shoppers with full-sized computers don't want all their grocery aisles hidden behind a hamburger menu. The markup to generate the desktop navigation is different enough from the mobile hamburger that using media queries would be a stretch (heh, get it?). By trimming the more complicated desktop markup from the mobile response, we save precious page weight for a faster load time. + +Here's how we send different responses to different devices while maximizing cache hits. Let's take a journey along the request-response cycle: + +![Flow Diagram](/images/posts/server-side-responsive-express-varnish/flow.jpg) + + +## Request + +Browsers send requests to a [varnish](https://www.varnish-cache.org/) cache server ([Fastly](https://www.fastly.com/) has worked great). All requests come with a User-Agent header that hints at the shopper's device. + +iPhone 5 sends something like: + + Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3 + +while IE 11 on Windows 8 sends: + + Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko + +which is [a deliberate lie](http://blogs.msdn.com/b/ieinternals/archive/2013/09/21/internet-explorer-11-user-agent-string-ua-string-sniffing-compatibility-with-gecko-webkit.aspx) but gives us enough information to call it a desktop browser. + +Grouping these messy headers into nice buckets of devices: `phone`, `tablet`, or `desktop` in our case, is the job of [varnish-device-detect](https://github.com/varnish/varnish-devicedetect). To get up and running quickly, [connect-device-detect](https://github.com/goodeggs/connect-devicedetect) can do the same grouping within the express server, but grouping at the edge cache yields much better hit rates. Our express server only has to generate one `phone` response, which varnish will serve to iPhones, Androids, or any other devices who's User-Agent string matches our phone regular expressions. + +Varnish sends the device bucket on to our Express server as an `X-UA-Device` header. In Express, we use [connect-device-router](https://github.com/goodeggs/connect-device-router) to switch controllers per device: + +``` js +var express = require('express'), + device = require('connect-device-router'); + +express() + .get('/food', + device('phone', function (req, res, next) { + # ... + res.render('mobileView') + }), + device('desktop', function (req, res, next) { + # ... + res.render('desktopView') + }), + function (req, res, next) { + # default + } + ) +``` + +Matched routes also get a `req.device` string for branching within a template or a shared controller. + +## Response + +Now our controller has generated a response, and we're on our way back out. Device router adds a `Vary: X-UA-Device` header only to matched routes, so routes that serve the same response to all devices will hit the same cache regardless of which device requests them. + +Varnish includes the `Vary` header by default when calculating cache keys, so device router's `Vary: X-UA-Device` triggers separate cached responses per device bucket. + +Our setup has a few customizations on top of varnish-devicedetect to support downstream caching, including adding a `Vary: User-Agent` header, since downstream caches won't have bucketed the device: + +``` +sub vcl_deliver { + ... + set resp.http.vary = resp.http.vary ", User-Agent"; + + # We also remove the Vary: X-UA-Device set upstream by connect-device-router + set resp.http.vary = regsuball(resp.http.vary, "[, ]*?X-UA-Device", ""); + + # And copy over the X-UA-Device bucket for easy auditing in browser + set resp.http.X-UA-Device = req.http.X-UA-Device; + ... +} +``` + +Now browsers can store the reponse locally, and won't need to make another request until their cached response is stale. + +Caching can get a little mind bending. I often found myself wondering why I couldn't just send `Vary: X-UA-Device` all the way back to the browser, I mean we're telling the browser what it's X-UA-Device is in the response, right?. [The answer](http://stackoverflow.com/questions/21056733/can-i-vary-on-a-custom-header) seems obvious in retrospect. What else is confusing? diff --git a/src/files/images/posts/server-side-responsive-express-varnish/flow.jpg b/src/files/images/posts/server-side-responsive-express-varnish/flow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..808754a8074fc55bdd3f82b8a247162339a215ef GIT binary patch literal 18426 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

s^0CKt2^>yv zIexpyGs>VBGa&gilf_-St0q}b+lmVtJ&rg{DyoOubx0-dftZEv@_fTgB5YH%$wk8U z<6ORp$wtkTBCFcjOjui`GG*IsS*bOUoJ;s@HhRsBM6!0D_3_P;g#rpLLp&lvCRO@| zB9XVn<*!o$U3eFj1yomQ%UHfz#(76CS9_vU--*25(Y9>#mXUrihpE-I;Drch2cOwY<~^4Z;I7()JxcQf>zdyHZ_Q zeU+^-+a|N|tUSyYb7>JpCZ=89wAIu3ud|;KiEWt({hYD?9---l0*GY3=*b+Ofkf#G{)zU@u)4%O zC{huev*z{i(>ru7*~MG3*uOE{Xo<}?>SA}#*E-g~bz0^iUu~KpAk_KF;_-P5Sn^Hg zphykabO4R})4<~Ss!IVc6a(henySH36{Q1m5%v!<4xBg6dA+{&j7!bkP!<=MP6-#B zD-cr{Teg%5YLXb-yPM=4YK_11RCc`f$Bkhp)wYzgJ<+pkjpo)-V>l^lW7~Dlui?uN zKZ>^P!@J%m*U3%r0SjcLs6mwZi;Txq9DK0QxQ8dvn62orbae&K^>btyM-5j^VnHxY zC*mX&oj+H!t*_q8m`eYXLVt6ffXb)-R%N4+T$znW%E*PXAH_bigiJF>E2A?kC|NRu%q6eEP6`jhDl z?z_Yse~foYZFV25_#=bY`l)WLA`)3M!Q}+>_h>O(++`&^73@t-saA;lc*!bj5M8`v zI1bRe$96a{V|GQuD>J*ON9>C!yr4^FLIXYrgN|n?2d&q(NKC4XY}ama-qWuiF4t!K znrop?c+X|E$vKh4yk~E2Q?2zT2^xM~^{Nm{4Q;yH4;MIAWznCBLGgIyj=1#KPGJm< zW};e2Q5spICUfvfm39WvGw0}yXAv>rlq5>q^J%#|UfW{0=Gt6N#Q`l-;83QYy}pCt zo2slg!sA)S*)TbYFLuFX`yrHR0zZMrl~jwOY0t zrJ>drUb}(NfL^9X;gOBg`0O&9^t3DdvnGv9&!hayUNzAtuZ3ccEO8gwKc`+=aXary!KZymhIwaZCqW$c zY)uG)pZ-vPO~*{aS(WJxX){UX?)w+kBxr%wq^RgRIgX0V7ADzRY{K|bTZRoH!PEP z5wU;mgXeUtDb;Hug>U*CRI?R*;#*s?9b!L^_eG;j7;uf0+o^}u^ zYkBry36DmqMRvkyvy#L zQm>nOsqtzW+q5?|omOS)>-b1W86J?CY^*&P-yw}&LmDcDp#b=^^A@Z*S?bK*hdc+? zv;x>}e0C^6+t%gHYWjN10~Q{S0;wdU*xb)25nb~fHYTPkLb3krJn&Jw<&QF7ccX?D zsKFTlyuMZMvew~d0+xxF`TrZ+7v=qF)w4TlPduXYQDc`yU6b^ z(X^;ZZZr34G(>*-W}n2GW*9Q}@>SY`jXyLKn9Fbc_VpV%e5lv@SB6LV$UWxmy7j9+ zQZtu%rM0&;A$lO^P4_Fs!|>KgShGQ`Aiy1vWX$kD?57dgE4ttTxu%hgDPwJ*HsO79#ytS)8aRtX<^ca z2{&Xzd{SfR}&$P%(^ z%sG**_K0SO>tz@oSh&Sk!HYOtky?|}`~BjKKA_-g z2;(tYaL8s*dfDE|m757Sli;=f+?Z5jJ1TwR>*m?1#TDyE(>qDtMRRV%0}TYvgj@*p z#*Sr~+wHs(iWDwZ3`5>X~(fVSelo(7^N zRp+ePOo{UHG@7rkdcGun#=k|z@TjvIxemlhJ8VtA8m`T_X8mBW$&0xTF@U!(ij@t{ z5ew{fuF2>FxqL@vDjU+fA6A3=<19W3hOVCa0Db_$806LTOSrQm3Ybg(v@9d8%MoRSecUGQSkOUC)(gkZ_F#NVhM^kHe^3-`V zh;8u5uIRk)eO6xMa^dh7%=H_V(Ue;WTx+pG>tLiG3&zGyqq%tal3j1A?x;^xz-xq+ zmW1r)@CT_r2zb!s{kTnOT_j#{T2|sX5mb>iZ9b#y34N@l(nv)cDUBt@n4oCkI?>D{ z@YZ3XR+qL^@*D31#QBky%t8p9N(eGGtS7X6yWgP3q~!)kvQZ{A63R=I(#g@af6+x4 z=pX67HZ#+trP#ab$d(%UGGaDmB%Hn6)x0aM$*g0ln>KyA{820KjTuaRhIyA~AoX6` zMc7k9r);pt_pSgoD%AOS`pI6{DL861tlgq65OfVXSi)5W>&9XCU3RBB+WKZ*WEu#l z3&I2EUVjKHP8frvUU}eF_elR+H%Ye#c~p0iyymBTma|W*cCa^i9@lgC%{ak5rfpDg zP}Kg4Lw^IJ5JT$E=W(r6D4+_QS_kU-7Z%R&?*b?G$W{={4)e;=9Dt#ucltc*=d&V!4=WbSp*RZfg;UyH7T|Gu8HWUq`YDNx??o=Go zM0p>rHa0dfL2$oFIpy&q+!?JmgC=&;iB27(rZN z3_r(zaP9zgis?oU@4+r`M#23lE;7r?M~M$**7dfXs$`El6q_m>Bj}cKBr!5OQaXWd}^hOx>?&*!J7e zdL~5^@se%^5)-jl$bW|nY6RJY`;r+*uLZ0j!zHdD@omBFsAPfj;^6)z0?@rg8NpAw z0Ux3NTWXNwk0aviObn{i2GvHb8ZKtj{f@t@v#NycDe`m9#f7UbJll^W!mf4beI%uH zI`d^?+FQE*8P*S*^qu}2($&^?)@c){-w^TZeJ!u3-J;~#W-_c;h_{Xrro_p$zsS`FXI|af7Y;!9eB`jgRA_sUl_EhUH4ZXPzk$N&3hc z&^gLz!9S0KBQ<*CU}na?zA1Ua!G_YtUx#o@mWpB8xGOVngr#Xz@q@OiRLWQ0$5=Q; zQt`#l5FAj-tsYlIOkMDWbe#&ztC$JyVAW}6s!t!@hAMmkfE5#%_=ZV*;fd#V@~4Wg zcq$*>zvlJ@D7;^YcU&B~D!LaZ3C$9Xa9n=U&#**iF6c3E&ebp?B}Bb=zw&w3y?~V!kN0cW__IMqe``Km zK&IZ^wT?>YOzRu($1mH>J$7L3t-I}3XDR%ycv;Zxn)1!2=IhP+_4RwxtjApMjpj1G z$iGyuRMMjN9!m@wZhST5PU_m_CqO7VK;_$);x^Z|#<;z_(XH-Ck!X$h8u=do6%X#p zYmn04)=uc;fX;^tIsa{CGvBVy**}C`T$t~b%Mj1b^s_&FHAsp$DwN`m3=#%>eE!{J z_wP>aQr6hlwXw0mOUjPSF-1H)h|Q`{yHZ=f&pgI_hH-|LTPQwDxt0vyFNk8W58+24mFoG$o9|l22q`uSm65%NuxmsLTdv!5CBKLv7s-)J^oOTN<-B z1J7R|GOd~1`Q?)ZyyQh_Pl2g!!1o}oT?IW{6UtFx*N*lz_lhujH9Q88YR-212T9QoKQeVMCx*Z`Wu*j39V_E_yX{~!bj>{e+T>j#l0ek)9t zzBcX2Y(>CdXk^(_OV08g)oKmt?be$6Os~dnXo|hb>UNy5M3TFndvv!s+%5BSc8wqbHPTi^z6t8FR-knt?s*5k=TPcsSBzYA_i{_m&38TyVhf>72K~=-$_00^lW22{OD8rCtTLEd0YQjUMJwG z#)nsntv{&x=nE~7O68NR(*&jDt3?xA4z3g8x3iNaiEN&(-r9--u$Eyb9|7OsmXf(a zwdL{G!COQvPNvm*FelxqU)f%rA-AK9?dl7n@6EIa*r6tMhEnwJ?+ zF(fp?#eH4YaGB>eaDGen^u-gGm&YEZfvp3%4OHn=Q!>-NPJ`n@Z?!J9R|7Mla633vh3bgi;shN53M}ur#mTfm0q&MdY^T5XrfqN1ektDQ) zcn%=U0eNm6Fis*|lsTpFf&ZkjgMYmm3PTdXu|bl$24t=OV5yO$AfB>U{)44PRR3zy zb@(D|H|GLZLgo)r{QttIkxLifmy#@=Q}(sb-Kan2M*(GN+`9VadC-{2-)uD!?hPuY z`Csks4{-XYeCj1h{m-Yy9Ss#zaV;Y`VEOUY11&U2jE*1}|2{1s1EUZXU3x;6`Lq}y zL5$_Th*C`K#W+AXk`rUh2?4r!f9J+PSrsh)ueRbqC5?t%4rhexT1dXCQs_F^IXpM? zVR{nDO^PJnNdldF(>El68~mhc3;flJ=0BCmEZ*H<*gvZTJ7RSW1;kdqjsd=aKaTl( zX~93;_5VNV|NV9v9IiD1|7QgXeP(m+U=@v#+R6{TtZ7!N;)fNNIn19)hyQ1O6QVx- EAD~^8hX4Qo literal 0 HcmV?d00001 From 7a2f91d99036b5406949a868f4b83df00faa1e0c Mon Sep 17 00:00:00 2001 From: Michael Kebbekus Date: Tue, 30 Sep 2014 11:42:48 -0700 Subject: [PATCH 2/4] Update 2014-09-29-server-side-responsive-express-varnish.html.md Great post! I made a few wording changes for clarity. Of course, feel free to revert if you disagree! --- ...4-09-29-server-side-responsive-express-varnish.html.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md b/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md index 01842a7..51c7304 100644 --- a/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md +++ b/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md @@ -7,18 +7,18 @@ disqus: url: "http://bytes.goodeggs.com/post/server-side-responsive-express-varnish" --- -Conversations about responsive design often focus on the browser: media queries, grids, and the like, but there's more! A great experience on all manner of consumer-grade doo-dads demands some work on the server. +Conversations about responsive design often focus on the browser: media queries, grids, and the like, but there's more! Creating a great experience on all sorts of consumer-grade doo-dads demands some work on the server. -For example, shoppers with full-sized computers don't want all their grocery aisles hidden behind a hamburger menu. The markup to generate the desktop navigation is different enough from the mobile hamburger that using media queries would be a stretch (heh, get it?). By trimming the more complicated desktop markup from the mobile response, we save precious page weight for a faster load time. +On Good Eggs, shoppers with full-sized computers don't want all their grocery aisles hidden behind a collapsible menu. The markup to generate the desktop navigation is different enough from the mobile navigation that using media queries would be a stretch (heh, get it?). By trimming the more complicated desktop markup from the mobile response, we save precious page weight for a faster load time. -Here's how we send different responses to different devices while maximizing cache hits. Let's take a journey along the request-response cycle: +Let's take a journey along the request-response cycle to illustrate how we send different responses to different devices while maximizing cache hits: ![Flow Diagram](/images/posts/server-side-responsive-express-varnish/flow.jpg) ## Request -Browsers send requests to a [varnish](https://www.varnish-cache.org/) cache server ([Fastly](https://www.fastly.com/) has worked great). All requests come with a User-Agent header that hints at the shopper's device. +Browsers send requests to a [varnish](https://www.varnish-cache.org/) cache server ([Fastly](https://www.fastly.com/) has worked great for us). All requests come with a User-Agent header that hints at the shopper's device. iPhone 5 sends something like: From 1358ed36f0bd3fd047bd4aaab3ac8a8ba2a8118e Mon Sep 17 00:00:00 2001 From: Michael Kebbekus Date: Tue, 30 Sep 2014 11:59:03 -0700 Subject: [PATCH 3/4] Change title per Alon's suggestion and include in Mobile series per Adam's suggestion. I unfortunately copied and pasted the series navigation as DocPad confounds me. --- .../2014-04-11-good-eggs-goes-mobile.html.md | 3 +-- .../posts/2014-04-25-rivets-for-mobile.html.md | 2 +- .../posts/2014-06-16-mobile-page-load.html.md | 2 +- ...responsive-app-with-node-and-varnish.html.md} | 16 ++++++++++++++-- 4 files changed, 17 insertions(+), 6 deletions(-) rename src/documents/posts/{2014-09-29-server-side-responsive-express-varnish.html.md => 2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md} (85%) diff --git a/src/documents/posts/2014-04-11-good-eggs-goes-mobile.html.md b/src/documents/posts/2014-04-11-good-eggs-goes-mobile.html.md index 2894290..721e557 100644 --- a/src/documents/posts/2014-04-11-good-eggs-goes-mobile.html.md +++ b/src/documents/posts/2014-04-11-good-eggs-goes-mobile.html.md @@ -13,13 +13,12 @@ disqus:

  • [Good Eggs Goes Mobile](/posts/good-eggs-goes-mobile)
  • [Rivets for Mobile Web](/posts/rivets-for-mobile)
  • [Planning Page Load Sequence](/posts/mobile-page-load)
  • -
  • HTTP Caching with Fastly
  • +
  • [Speed with Node and Varnish](/posts/speed-up-your-responsive-app-with-node-and-varnish)
  • Appropriate image sizes with imgix
  • Integration testing over unit testing
  • - In the past 6 months, 25% of our traffic came from mobile devices, and those users faced a daunting, near impossible shopping experience. In response, we launched a new mobile version of [goodeggs.com](https://www.goodeggs.com) two weeks ago with an diff --git a/src/documents/posts/2014-04-25-rivets-for-mobile.html.md b/src/documents/posts/2014-04-25-rivets-for-mobile.html.md index 9f718f0..9b6a6c2 100644 --- a/src/documents/posts/2014-04-25-rivets-for-mobile.html.md +++ b/src/documents/posts/2014-04-25-rivets-for-mobile.html.md @@ -19,7 +19,7 @@ style: |
  • [Good Eggs Goes Mobile](/posts/good-eggs-goes-mobile)
  • [Rivets for Mobile Web](/posts/rivets-for-mobile)
  • [Planning Page Load Sequence](/posts/mobile-page-load)
  • -
  • HTTP Caching with Fastly
  • +
  • [Speed with Node and Varnish](/posts/speed-up-your-responsive-app-with-node-and-varnish)
  • Appropriate image sizes with imgix
  • Integration testing over unit testing
  • diff --git a/src/documents/posts/2014-06-16-mobile-page-load.html.md b/src/documents/posts/2014-06-16-mobile-page-load.html.md index 6c7ea8a..f4c4265 100644 --- a/src/documents/posts/2014-06-16-mobile-page-load.html.md +++ b/src/documents/posts/2014-06-16-mobile-page-load.html.md @@ -28,7 +28,7 @@ style: |
  • [Good Eggs Goes Mobile](/posts/good-eggs-goes-mobile)
  • [Rivets for Mobile Web](/posts/rivets-for-mobile)
  • [Planning Page Load Sequence](/posts/mobile-page-load)
  • -
  • HTTP Caching with Fastly
  • +
  • [Speed with Node and Varnish](/posts/speed-up-your-responsive-app-with-node-and-varnish)
  • Appropriate image sizes with imgix
  • Integration testing over unit testing
  • diff --git a/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md b/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md similarity index 85% rename from src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md rename to src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md index 51c7304..d1aef95 100644 --- a/src/documents/posts/2014-09-29-server-side-responsive-express-varnish.html.md +++ b/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md @@ -1,12 +1,24 @@ --- -title: Server Side Responsive with Express and Varnish +title: Speed up your responsive app with Node and Varnish author: Adam Hull layout: post disqus: shortname: goodeggsbytes - url: "http://bytes.goodeggs.com/post/server-side-responsive-express-varnish" + url: "http://bytes.goodeggs.com/post/speed-up-your-responsive-app-with-node-and-varnish" --- +
    +
    This is the fourth article in a series of posts detailing the launch of our mobile site.
    +
      +
    1. [Good Eggs Goes Mobile](/posts/good-eggs-goes-mobile)
    2. +
    3. [Rivets for Mobile Web](/posts/rivets-for-mobile)
    4. +
    5. [Planning Page Load Sequence](/posts/mobile-page-load)
    6. +
    7. [Speed with Node and Varnish](/posts/speed-up-your-responsive-app-with-node-and-varnish)
    8. +
    9. Appropriate image sizes with imgix
    10. +
    11. Integration testing over unit testing
    12. +
    +
    + Conversations about responsive design often focus on the browser: media queries, grids, and the like, but there's more! Creating a great experience on all sorts of consumer-grade doo-dads demands some work on the server. On Good Eggs, shoppers with full-sized computers don't want all their grocery aisles hidden behind a collapsible menu. The markup to generate the desktop navigation is different enough from the mobile navigation that using media queries would be a stretch (heh, get it?). By trimming the more complicated desktop markup from the mobile response, we save precious page weight for a faster load time. From 16971e14e65212196376c94d6159f884a19bae4c Mon Sep 17 00:00:00 2001 From: Adam Hull Date: Tue, 30 Sep 2014 22:52:24 -0700 Subject: [PATCH 4/4] bytes => bites --- ...9-speed-up-your-responsive-app-with-node-and-varnish.html.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md b/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md index d1aef95..c530d50 100644 --- a/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md +++ b/src/documents/posts/2014-09-29-speed-up-your-responsive-app-with-node-and-varnish.html.md @@ -4,7 +4,7 @@ author: Adam Hull layout: post disqus: shortname: goodeggsbytes - url: "http://bytes.goodeggs.com/post/speed-up-your-responsive-app-with-node-and-varnish" + url: "http://bites.goodeggs.com/post/speed-up-your-responsive-app-with-node-and-varnish" ---