A place to cache linked articles (think custom and personal wayback machine)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5 年之前
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. <!doctype html><!-- This is a valid HTML5 document. -->
  2. <!-- Screen readers, SEO, extensions and so on. -->
  3. <html lang=fr>
  4. <!-- Has to be within the first 1024 bytes, hence before the <title>
  5. See: https://www.w3.org/TR/2012/CR-html5-20121217/document-metadata.html#charset -->
  6. <meta charset=utf-8>
  7. <!-- Why no `X-UA-Compatible` meta: https://stackoverflow.com/a/6771584 -->
  8. <!-- The viewport meta is quite crowded and we are responsible for that.
  9. See: https://codepen.io/tigt/post/meta-viewport-for-2015 -->
  10. <meta name=viewport content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no">
  11. <!-- Required to make a valid HTML5 document. -->
  12. <title>Speeding Things Up With Service Worker, Resource Hints, and More (archive) — David Larlet</title>
  13. <!-- Generated from https://realfavicongenerator.net/ such a mess. -->
  14. <link rel="apple-touch-icon" sizes="180x180" href="/static/david/icons/apple-touch-icon.png">
  15. <link rel="icon" type="image/png" sizes="32x32" href="/static/david/icons/favicon-32x32.png">
  16. <link rel="icon" type="image/png" sizes="16x16" href="/static/david/icons/favicon-16x16.png">
  17. <link rel="manifest" href="/manifest.json">
  18. <link rel="mask-icon" href="/static/david/icons/safari-pinned-tab.svg" color="#5bbad5">
  19. <link rel="shortcut icon" href="/static/david/icons/favicon.ico">
  20. <meta name="apple-mobile-web-app-title" content="David Larlet">
  21. <meta name="application-name" content="David Larlet">
  22. <meta name="msapplication-TileColor" content="#da532c">
  23. <meta name="msapplication-config" content="/static/david/icons/browserconfig.xml">
  24. <meta name="theme-color" content="#f0f0ea">
  25. <!-- That good ol' feed, subscribe :p. -->
  26. <link rel=alternate type="application/atom+xml" title=Feed href="/david/log/">
  27. <meta name="robots" content="noindex, nofollow">
  28. <meta content="origin-when-cross-origin" name="referrer">
  29. <!-- Canonical URL for SEO purposes -->
  30. <link rel="canonical" href="https://www.aaron-gustafson.com/notebook/speeding-things-up-with-service-worker-resource-hints-and-more/">
  31. <style>
  32. /* http://meyerweb.com/eric/tools/css/reset/ */
  33. html, body, div, span,
  34. h1, h2, h3, h4, h5, h6, p, blockquote, pre,
  35. a, abbr, address, big, cite, code,
  36. del, dfn, em, img, ins,
  37. small, strike, strong, tt, var,
  38. dl, dt, dd, ol, ul, li,
  39. fieldset, form, label, legend,
  40. table, caption, tbody, tfoot, thead, tr, th, td,
  41. article, aside, canvas, details, embed,
  42. figure, figcaption, footer, header, hgroup,
  43. menu, nav, output, ruby, section, summary,
  44. time, mark, audio, video {
  45. margin: 0;
  46. padding: 0;
  47. border: 0;
  48. font-size: 100%;
  49. font: inherit;
  50. vertical-align: baseline;
  51. }
  52. /* HTML5 display-role reset for older browsers */
  53. article, aside, details, figcaption, figure,
  54. footer, header, hgroup, menu, nav, section { display: block; }
  55. body { line-height: 1; }
  56. blockquote, q { quotes: none; }
  57. blockquote:before, blockquote:after,
  58. q:before, q:after {
  59. content: '';
  60. content: none;
  61. }
  62. table {
  63. border-collapse: collapse;
  64. border-spacing: 0;
  65. }
  66. /* http://practicaltypography.com/equity.html */
  67. /* https://calendar.perfplanet.com/2016/no-font-face-bulletproof-syntax/ */
  68. /* https://www.filamentgroup.com/lab/js-web-fonts.html */
  69. @font-face {
  70. font-family: 'EquityTextB';
  71. src: url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff2') format('woff2'),
  72. url('/static/david/css/fonts/Equity-Text-B-Regular-webfont.woff') format('woff');
  73. font-weight: 300;
  74. font-style: normal;
  75. font-display: swap;
  76. }
  77. @font-face {
  78. font-family: 'EquityTextB';
  79. src: url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff2') format('woff2'),
  80. url('/static/david/css/fonts/Equity-Text-B-Italic-webfont.woff') format('woff');
  81. font-weight: 300;
  82. font-style: italic;
  83. font-display: swap;
  84. }
  85. @font-face {
  86. font-family: 'EquityTextB';
  87. src: url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff2') format('woff2'),
  88. url('/static/david/css/fonts/Equity-Text-B-Bold-webfont.woff') format('woff');
  89. font-weight: 700;
  90. font-style: normal;
  91. font-display: swap;
  92. }
  93. @font-face {
  94. font-family: 'ConcourseT3';
  95. src: url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff2') format('woff2'),
  96. url('/static/david/css/fonts/concourse_t3_regular-webfont-20190806.woff') format('woff');
  97. font-weight: 300;
  98. font-style: normal;
  99. font-display: swap;
  100. }
  101. /* http://practice.typekit.com/lesson/caring-about-opentype-features/ */
  102. body {
  103. /* http://www.cssfontstack.com/ Palatino 99% Win 86% Mac */
  104. font-family: "EquityTextB", Palatino, serif;
  105. background-color: #f0f0ea;
  106. color: #07486c;
  107. font-kerning: normal;
  108. -moz-osx-font-smoothing: grayscale;
  109. -webkit-font-smoothing: subpixel-antialiased;
  110. text-rendering: optimizeLegibility;
  111. font-variant-ligatures: common-ligatures contextual;
  112. font-feature-settings: "kern", "liga", "clig", "calt";
  113. }
  114. pre, code, kbd, samp, var, tt {
  115. font-family: 'TriplicateT4c', monospace;
  116. }
  117. em {
  118. font-style: italic;
  119. color: #323a45;
  120. }
  121. strong {
  122. font-weight: bold;
  123. color: black;
  124. }
  125. nav {
  126. background-color: #323a45;
  127. color: #f0f0ea;
  128. display: flex;
  129. justify-content: space-around;
  130. padding: 1rem .5rem;
  131. }
  132. nav:last-child {
  133. border-bottom: 1vh solid #2d7474;
  134. }
  135. nav a {
  136. color: #f0f0ea;
  137. }
  138. nav abbr {
  139. border-bottom: 1px dotted white;
  140. }
  141. h1 {
  142. border-top: 1vh solid #2d7474;
  143. border-bottom: .2vh dotted #2d7474;
  144. background-color: #e3e1e1;
  145. color: #323a45;
  146. text-align: center;
  147. padding: 5rem 0 4rem 0;
  148. width: 100%;
  149. font-family: 'ConcourseT3';
  150. display: flex;
  151. flex-direction: column;
  152. }
  153. h1.single {
  154. padding-bottom: 10rem;
  155. }
  156. h1 span {
  157. position: absolute;
  158. top: 1vh;
  159. left: 20%;
  160. line-height: 0;
  161. }
  162. h1 span a {
  163. line-height: 1.7;
  164. padding: 1rem 1.2rem .6rem 1.2rem;
  165. border-radius: 0 0 6% 6%;
  166. background: #2d7474;
  167. font-size: 1.3rem;
  168. color: white;
  169. text-decoration: none;
  170. }
  171. h2 {
  172. margin: 4rem 0 1rem;
  173. border-top: .2vh solid #2d7474;
  174. padding-top: 1vh;
  175. }
  176. h3 {
  177. text-align: center;
  178. margin: 3rem 0 .75em;
  179. }
  180. hr {
  181. height: .4rem;
  182. width: .4rem;
  183. border-radius: .4rem;
  184. background: #07486c;
  185. margin: 2.5rem auto;
  186. }
  187. time {
  188. display: bloc;
  189. margin-left: 0 !important;
  190. }
  191. ul, ol {
  192. margin: 2rem;
  193. }
  194. ul {
  195. list-style-type: square;
  196. }
  197. a {
  198. text-decoration-skip-ink: auto;
  199. text-decoration-thickness: 0.05em;
  200. text-underline-offset: 0.09em;
  201. }
  202. article {
  203. max-width: 50rem;
  204. display: flex;
  205. flex-direction: column;
  206. margin: 2rem auto;
  207. }
  208. article.single {
  209. border-top: .2vh dotted #2d7474;
  210. margin: -6rem auto 1rem auto;
  211. background: #f0f0ea;
  212. padding: 2rem;
  213. }
  214. article p:last-child {
  215. margin-bottom: 1rem;
  216. }
  217. p {
  218. padding: 0 .5rem;
  219. margin-left: 3rem;
  220. }
  221. p + p,
  222. figure + p {
  223. margin-top: 2rem;
  224. }
  225. blockquote {
  226. background-color: #e3e1e1;
  227. border-left: .5vw solid #2d7474;
  228. display: flex;
  229. flex-direction: column;
  230. align-items: center;
  231. padding: 1rem;
  232. margin: 1.5rem;
  233. }
  234. blockquote cite {
  235. font-style: italic;
  236. }
  237. blockquote p {
  238. margin-left: 0;
  239. }
  240. figure {
  241. border-top: .2vh solid #2d7474;
  242. background-color: #e3e1e1;
  243. text-align: center;
  244. padding: 1.5rem 0;
  245. margin: 1rem 0 0;
  246. font-size: 1.5rem;
  247. width: 100%;
  248. }
  249. figure img {
  250. max-width: 250px;
  251. max-height: 250px;
  252. border: .5vw solid #323a45;
  253. padding: 1px;
  254. }
  255. figcaption {
  256. padding: 1rem;
  257. line-height: 1.4;
  258. }
  259. aside {
  260. display: flex;
  261. flex-direction: column;
  262. background-color: #e3e1e1;
  263. padding: 1rem 0;
  264. border-bottom: .2vh solid #07486c;
  265. }
  266. aside p {
  267. max-width: 50rem;
  268. margin: 0 auto;
  269. }
  270. /* https://fvsch.com/code/css-locks/ */
  271. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  272. font-size: 1rem;
  273. line-height: calc( 1.5em + 0.2 * 1rem );
  274. }
  275. h1 {
  276. font-size: 1.9rem;
  277. line-height: calc( 1.2em + 0.2 * 1rem );
  278. }
  279. h2 {
  280. font-size: 1.6rem;
  281. line-height: calc( 1.3em + 0.2 * 1rem );
  282. }
  283. h3 {
  284. font-size: 1.35rem;
  285. line-height: calc( 1.4em + 0.2 * 1rem );
  286. }
  287. @media (min-width: 20em) {
  288. /* The (100vw - 20rem) / (50 - 20) part
  289. resolves to 0-1rem, depending on the
  290. viewport width (between 20em and 50em). */
  291. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  292. font-size: calc( 1rem + .6 * (100vw - 20rem) / (50 - 20) );
  293. line-height: calc( 1.5em + 0.2 * (100vw - 50rem) / (20 - 50) );
  294. margin-left: 0;
  295. }
  296. h1 {
  297. font-size: calc( 1.9rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  298. line-height: calc( 1.2em + 0.2 * (100vw - 50rem) / (20 - 50) );
  299. }
  300. h2 {
  301. font-size: calc( 1.5rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  302. line-height: calc( 1.3em + 0.2 * (100vw - 50rem) / (20 - 50) );
  303. }
  304. h3 {
  305. font-size: calc( 1.35rem + 1.5 * (100vw - 20rem) / (50 - 20) );
  306. line-height: calc( 1.4em + 0.2 * (100vw - 50rem) / (20 - 50) );
  307. }
  308. }
  309. @media (min-width: 50em) {
  310. /* The right part of the addition *must* be a
  311. rem value. In this example we *could* change
  312. the whole declaration to font-size:2.5rem,
  313. but if our baseline value was not expressed
  314. in rem we would have to use calc. */
  315. p, li, pre, code, kbd, samp, var, tt, time, details, figcaption {
  316. font-size: calc( 1rem + .6 * 1rem );
  317. line-height: 1.5em;
  318. }
  319. p, li, pre, details {
  320. margin-left: 3rem;
  321. }
  322. h1 {
  323. font-size: calc( 1.9rem + 1.5 * 1rem );
  324. line-height: 1.2em;
  325. }
  326. h2 {
  327. font-size: calc( 1.5rem + 1.5 * 1rem );
  328. line-height: 1.3em;
  329. }
  330. h3 {
  331. font-size: calc( 1.35rem + 1.5 * 1rem );
  332. line-height: 1.4em;
  333. }
  334. figure img {
  335. max-width: 500px;
  336. max-height: 500px;
  337. }
  338. }
  339. figure.unsquared {
  340. margin-bottom: 1.5rem;
  341. }
  342. figure.unsquared img {
  343. height: inherit;
  344. }
  345. @media print {
  346. body { font-size: 100%; }
  347. a:after { content: " (" attr(href) ")"; }
  348. a, a:link, a:visited, a:after {
  349. text-decoration: underline;
  350. text-shadow: none !important;
  351. background-image: none !important;
  352. background: white;
  353. color: black;
  354. }
  355. abbr[title] { border-bottom: 0; }
  356. abbr[title]:after { content: " (" attr(title) ")"; }
  357. img { page-break-inside: avoid; }
  358. @page { margin: 2cm .5cm; }
  359. h1, h2, h3 { page-break-after: avoid; }
  360. p3 { orphans: 3; widows: 3; }
  361. img {
  362. max-width: 250px !important;
  363. max-height: 250px !important;
  364. }
  365. nav, aside { display: none; }
  366. }
  367. ul.with_columns {
  368. column-count: 1;
  369. }
  370. @media (min-width: 20em) {
  371. ul.with_columns {
  372. column-count: 2;
  373. }
  374. }
  375. @media (min-width: 50em) {
  376. ul.with_columns {
  377. column-count: 3;
  378. }
  379. }
  380. ul.with_two_columns {
  381. column-count: 1;
  382. }
  383. @media (min-width: 20em) {
  384. ul.with_two_columns {
  385. column-count: 1;
  386. }
  387. }
  388. @media (min-width: 50em) {
  389. ul.with_two_columns {
  390. column-count: 2;
  391. }
  392. }
  393. .gallery {
  394. display: flex;
  395. flex-wrap: wrap;
  396. justify-content: space-around;
  397. }
  398. .gallery figure img {
  399. margin-left: 1rem;
  400. margin-right: 1rem;
  401. }
  402. .gallery figure figcaption {
  403. font-family: 'ConcourseT3'
  404. }
  405. footer {
  406. font-family: 'ConcourseT3';
  407. display: flex;
  408. flex-direction: column;
  409. border-top: 3px solid white;
  410. padding: 4rem 0;
  411. background-color: #07486c;
  412. color: white;
  413. }
  414. footer > * {
  415. max-width: 50rem;
  416. margin: 0 auto;
  417. }
  418. footer a {
  419. color: #f1c40f;
  420. }
  421. footer .avatar {
  422. width: 200px;
  423. height: 200px;
  424. border-radius: 50%;
  425. float: left;
  426. -webkit-shape-outside: circle();
  427. shape-outside: circle();
  428. margin-right: 2rem;
  429. padding: 2px 5px 5px 2px;
  430. background: white;
  431. border-left: 1px solid #f1c40f;
  432. border-top: 1px solid #f1c40f;
  433. border-right: 5px solid #f1c40f;
  434. border-bottom: 5px solid #f1c40f;
  435. }
  436. </style>
  437. <h1>
  438. <span><a id="jumper" href="#jumpto" title="Un peu perdu ?">?</a></span>
  439. Speeding Things Up With Service Worker, Resource Hints, and More (archive)
  440. <time>Pour la pérennité des contenus liés. Non-indexé, retrait sur simple email.</time>
  441. </h1>
  442. <section>
  443. <article>
  444. <h3><a href="https://www.aaron-gustafson.com/notebook/speeding-things-up-with-service-worker-resource-hints-and-more/">Source originale du contenu</a></h3>
  445. <p>User experience encompasses more than just the interface. Download speed, render performance, and the cost of accessing a site are often overlooked areas when it comes to the practice of UX, but they all affect how users experience what we build on the Web.</p>
  446. <p>I’m always looking for ways to improve these aspects of my own site. And, since it’s my own personal playground, I often use it as a test-bed for new technologies, ideas, and techniques. My latest adventure was inspired by a bunch of <a href="https://www.aaron-gustafson.com/notebook/links/">articles and posts I’ve linked to recently</a>, especially</p>
  447. <ul>
  448. <li><a href="https://adactio.com/journal/9775">Jeremy Keith’s “My First Service Worker”</a>,</li>
  449. <li><a href="https://css-tricks.com/serviceworker-for-offline/">Nicolas Bevacqua’s “Making a Simple Site Work Offline with ServiceWorker”</a>,</li>
  450. <li><a href="http://deanhume.com/Home/BlogPost/service-workers--dynamic-responsive-images-using-webp-images/10132/">Dean Hume’s “Service Workers: Dynamic Responsive Images Using Webp Images”</a>, and</li>
  451. <li><a href="https://medium.com/@cramforce/not-so-micro-optimizations-f867c47b832d#.satdv0fap">Malte Ubl’s “Not so micro optimizations”</a></li>
  452. </ul>
  453. <p>After reading these pieces, I decided to see how much I could do to improve the performance of this site, especially on posts with a lot of images and embedded code samples, like <a href="https://www.aaron-gustafson.com/notebook/labeled-with-love/">my recent post on form labels</a>.</p>
  454. <h2 id="using-resource-hints">Using Resource Hints</h2>
  455. <p>To kick things off, I followed Malte’s advice and used <a href="https://w3c.github.io/resource-hints/">Resource Hints</a> to <em>prime the pump</em> for any third-party servers hosting assets I use frequently (e.g. Disqus, Twitter, etc.). I used the code Malte references in <a href="https://github.com/ampproject/amphtml">the AMP Project</a> as my starting point and <a href="https://github.com/aarongustafson/aarongustafson.github.io/blob/source/source/_javascript/main/resource-hints.js">added two new methods (<code>preconnect()</code> and <code>prefetch()</code>) to my global <code>AG</code> object</a>. With that library code in place, I can call those methods as necessary from within my other JavaScript files. Here’s a simplified extract from <a href="https://github.com/aarongustafson/aarongustafson.github.io/blob/source/source/_javascript/post/disqus.js">my Disqus integration script</a>:</p>
  456. <div><link rel="stylesheet" href="https://assets-cdn.github.com/assets/gist/embed-e75a8866f2a8f51e8bbbf8ca746676f1e7cacb08f4b1d9b52ea62524b333cc6d.css" />
  457. <div id="gist28197221" class="gist">
  458. <div class="gist-file">
  459. <div class="gist-data">
  460. <div class="js-gist-file-update-container js-task-list-container file-box">
  461. <div id="file-resource-hints-sample-js" class="file">
  462. <div class="blob-wrapper data type-javascript">
  463. <table class="highlight tab-size js-file-line-container" data-tab-size="8">
  464. <tr>
  465. <td id="file-resource-hints-sample-js-L1" class="blob-num js-line-number" data-line-number="1"></td>
  466. <td id="file-resource-hints-sample-js-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">if</span> ( <span class="pl-s"><span class="pl-pds">&#39;</span>AG<span class="pl-pds">&#39;</span></span> <span class="pl-k">in</span> <span class="pl-c1">window</span> <span class="pl-k">&amp;&amp;</span> <span class="pl-s"><span class="pl-pds">&#39;</span>preconnect<span class="pl-pds">&#39;</span></span> <span class="pl-k">in</span> <span class="pl-c1">window</span>.AG ) {</td>
  467. </tr>
  468. <tr>
  469. <td id="file-resource-hints-sample-js-L2" class="blob-num js-line-number" data-line-number="2"></td>
  470. <td id="file-resource-hints-sample-js-LC2" class="blob-code blob-code-inner js-file-line"> <span class="pl-c1">window</span>.AG.preconnect( <span class="pl-s"><span class="pl-pds">&#39;</span>//disqus.com/<span class="pl-pds">&#39;</span></span> );</td>
  471. </tr>
  472. <tr>
  473. <td id="file-resource-hints-sample-js-L3" class="blob-num js-line-number" data-line-number="3"></td>
  474. <td id="file-resource-hints-sample-js-LC3" class="blob-code blob-code-inner js-file-line"> <span class="pl-c1">window</span>.AG.prefetch( <span class="pl-s"><span class="pl-pds">&#39;</span>//<span class="pl-pds">&#39;</span></span> <span class="pl-k">+</span> disqus_shortname <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span>.disqus.com/count.js<span class="pl-pds">&#39;</span></span> );</td>
  475. </tr>
  476. <tr>
  477. <td id="file-resource-hints-sample-js-L4" class="blob-num js-line-number" data-line-number="4"></td>
  478. <td id="file-resource-hints-sample-js-LC4" class="blob-code blob-code-inner js-file-line">}</td>
  479. </tr>
  480. </table>
  481. </div>
  482. </div>
  483. </div>
  484. <pre><code> &lt;/div&gt;
  485. &lt;div class="gist-meta"&gt;
  486. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea/raw/b6ca32d30643137603def7b4805d7bdcbfe63137/resource-hints-sample.js" style="float:right"&gt;view raw&lt;/a&gt;
  487. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea#file-resource-hints-sample-js"&gt;resource-hints-sample.js&lt;/a&gt;
  488. hosted with &amp;#10084; by &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;
  489. &lt;/div&gt;
  490. &lt;/div&gt;
  491. </code></pre>
  492. </div>
  493. </div>
  494. <p>While a minor addition, the speed improvement in <a href="http://caniuse.com/#search=resource%20hints">supporting browsers</a> was noticeable.<sup id="fnref:1"><a href="#fn:1" class="footnote">1</a></sup></p>
  495. <h2 id="integrating-service-worker">Integrating Service Worker</h2>
  496. <p>With that in the bag, I set about making my first <a href="http://www.w3.org/TR/service-workers/">Service Worker</a>. I started off gently, using Dean’s piece as a guide. I added a WebP conversion bit to <a href="https://github.com/aarongustafson/aarongustafson.github.io/blob/source/tasks/gulp/images.js">my image processing Gulp task</a> to get the files in place and then I created the Service Worker. By default, <a href="https://gist.github.com/deanhume/c04478df744ce833925c#file-client-hints-service-worker-js">Dean’s code</a> converts <em>all</em> JPG and PNG requests to WebP responses, so I set it up to limit the requests to only those files being requested directly from my server. I have no way of knowing if WebP equivalents of every JPG and PNG exist on the open web (probably not), but I know they exist on my server. Here’s the updated code:</p>
  497. <div><link rel="stylesheet" href="https://assets-cdn.github.com/assets/gist/embed-e75a8866f2a8f51e8bbbf8ca746676f1e7cacb08f4b1d9b52ea62524b333cc6d.css" />
  498. <div id="gist28206589" class="gist">
  499. <div class="gist-file">
  500. <div class="gist-data">
  501. <div class="js-gist-file-update-container js-task-list-container file-box">
  502. <div id="file-webp-service-worker-js" class="file">
  503. <div class="blob-wrapper data type-javascript">
  504. <table class="highlight tab-size js-file-line-container" data-tab-size="8">
  505. <tr>
  506. <td id="file-webp-service-worker-js-L1" class="blob-num js-line-number" data-line-number="1"></td>
  507. <td id="file-webp-service-worker-js-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s"><span class="pl-pds">&quot;</span>use strict<span class="pl-pds">&quot;</span></span>;</td>
  508. </tr>
  509. <tr>
  510. <td id="file-webp-service-worker-js-L2" class="blob-num js-line-number" data-line-number="2"></td>
  511. <td id="file-webp-service-worker-js-LC2" class="blob-code blob-code-inner js-file-line">
  512. </td>
  513. </tr>
  514. <tr>
  515. <td id="file-webp-service-worker-js-L3" class="blob-num js-line-number" data-line-number="3"></td>
  516. <td id="file-webp-service-worker-js-LC3" class="blob-code blob-code-inner js-file-line">self.addEventListener(<span class="pl-s"><span class="pl-pds">&#39;</span>fetch<span class="pl-pds">&#39;</span></span>, <span class="pl-k">function</span>(<span class="pl-smi">event</span>) {</td>
  517. </tr>
  518. <tr>
  519. <td id="file-webp-service-worker-js-L4" class="blob-num js-line-number" data-line-number="4"></td>
  520. <td id="file-webp-service-worker-js-LC4" class="blob-code blob-code-inner js-file-line">
  521. </td>
  522. </tr>
  523. <tr>
  524. <td id="file-webp-service-worker-js-L5" class="blob-num js-line-number" data-line-number="5"></td>
  525. <td id="file-webp-service-worker-js-LC5" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">var</span> request <span class="pl-k">=</span> <span class="pl-c1">event</span>.request,</td>
  526. </tr>
  527. <tr>
  528. <td id="file-webp-service-worker-js-L6" class="blob-num js-line-number" data-line-number="6"></td>
  529. <td id="file-webp-service-worker-js-LC6" class="blob-code blob-code-inner js-file-line"> url <span class="pl-k">=</span> request.url,</td>
  530. </tr>
  531. <tr>
  532. <td id="file-webp-service-worker-js-L7" class="blob-num js-line-number" data-line-number="7"></td>
  533. <td id="file-webp-service-worker-js-LC7" class="blob-code blob-code-inner js-file-line"> url_object <span class="pl-k">=</span> <span class="pl-k">new</span> <span class="pl-en">URL</span>( url ),</td>
  534. </tr>
  535. <tr>
  536. <td id="file-webp-service-worker-js-L8" class="blob-num js-line-number" data-line-number="8"></td>
  537. <td id="file-webp-service-worker-js-LC8" class="blob-code blob-code-inner js-file-line"> re_jpg_or_png <span class="pl-k">=</span><span class="pl-sr"> <span class="pl-pds">/</span><span class="pl-cce">\\.</span>(?:jpg<span class="pl-k">|</span>png)<span class="pl-k">$</span><span class="pl-pds">/</span></span>,</td>
  538. </tr>
  539. <tr>
  540. <td id="file-webp-service-worker-js-L9" class="blob-num js-line-number" data-line-number="9"></td>
  541. <td id="file-webp-service-worker-js-LC9" class="blob-code blob-code-inner js-file-line"> supports_webp <span class="pl-k">=</span> <span class="pl-c1">false</span>, <span class="pl-c">// pessimism</span></td>
  542. </tr>
  543. <tr>
  544. <td id="file-webp-service-worker-js-L10" class="blob-num js-line-number" data-line-number="10"></td>
  545. <td id="file-webp-service-worker-js-LC10" class="blob-code blob-code-inner js-file-line"> webp_url;</td>
  546. </tr>
  547. <tr>
  548. <td id="file-webp-service-worker-js-L11" class="blob-num js-line-number" data-line-number="11"></td>
  549. <td id="file-webp-service-worker-js-LC11" class="blob-code blob-code-inner js-file-line">
  550. </td>
  551. </tr>
  552. <tr>
  553. <td id="file-webp-service-worker-js-L12" class="blob-num js-line-number" data-line-number="12"></td>
  554. <td id="file-webp-service-worker-js-LC12" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// Check if the image is a local jpg or png</span></td>
  555. </tr>
  556. <tr>
  557. <td id="file-webp-service-worker-js-L13" class="blob-num js-line-number" data-line-number="13"></td>
  558. <td id="file-webp-service-worker-js-LC13" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">if</span> ( re_jpg_or_png.<span class="pl-c1">test</span>( request.url ) <span class="pl-k">&amp;&amp;</span></td>
  559. </tr>
  560. <tr>
  561. <td id="file-webp-service-worker-js-L14" class="blob-num js-line-number" data-line-number="14"></td>
  562. <td id="file-webp-service-worker-js-LC14" class="blob-code blob-code-inner js-file-line"> url_object.origin <span class="pl-k">==</span> location.origin ) {</td>
  563. </tr>
  564. <tr>
  565. <td id="file-webp-service-worker-js-L15" class="blob-num js-line-number" data-line-number="15"></td>
  566. <td id="file-webp-service-worker-js-LC15" class="blob-code blob-code-inner js-file-line">
  567. </td>
  568. </tr>
  569. <tr>
  570. <td id="file-webp-service-worker-js-L16" class="blob-num js-line-number" data-line-number="16"></td>
  571. <td id="file-webp-service-worker-js-LC16" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// console.log(&#39;WORKER: caught a request for a local PNG or JPG&#39;);</span></td>
  572. </tr>
  573. <tr>
  574. <td id="file-webp-service-worker-js-L17" class="blob-num js-line-number" data-line-number="17"></td>
  575. <td id="file-webp-service-worker-js-LC17" class="blob-code blob-code-inner js-file-line">
  576. </td>
  577. </tr>
  578. <tr>
  579. <td id="file-webp-service-worker-js-L18" class="blob-num js-line-number" data-line-number="18"></td>
  580. <td id="file-webp-service-worker-js-LC18" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// Inspect the accept header for WebP support</span></td>
  581. </tr>
  582. <tr>
  583. <td id="file-webp-service-worker-js-L19" class="blob-num js-line-number" data-line-number="19"></td>
  584. <td id="file-webp-service-worker-js-LC19" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">if</span> ( request.<span class="pl-c1">headers</span>.has(<span class="pl-s"><span class="pl-pds">&#39;</span>accept<span class="pl-pds">&#39;</span></span>) )</td>
  585. </tr>
  586. <tr>
  587. <td id="file-webp-service-worker-js-L20" class="blob-num js-line-number" data-line-number="20"></td>
  588. <td id="file-webp-service-worker-js-LC20" class="blob-code blob-code-inner js-file-line"> {</td>
  589. </tr>
  590. <tr>
  591. <td id="file-webp-service-worker-js-L21" class="blob-num js-line-number" data-line-number="21"></td>
  592. <td id="file-webp-service-worker-js-LC21" class="blob-code blob-code-inner js-file-line"> supports_webp <span class="pl-k">=</span> request.<span class="pl-c1">headers</span>.get(<span class="pl-s"><span class="pl-pds">&#39;</span>accept<span class="pl-pds">&#39;</span></span>).includes(<span class="pl-s"><span class="pl-pds">&#39;</span>webp<span class="pl-pds">&#39;</span></span>);</td>
  593. </tr>
  594. <tr>
  595. <td id="file-webp-service-worker-js-L22" class="blob-num js-line-number" data-line-number="22"></td>
  596. <td id="file-webp-service-worker-js-LC22" class="blob-code blob-code-inner js-file-line"> }</td>
  597. </tr>
  598. <tr>
  599. <td id="file-webp-service-worker-js-L23" class="blob-num js-line-number" data-line-number="23"></td>
  600. <td id="file-webp-service-worker-js-LC23" class="blob-code blob-code-inner js-file-line">
  601. </td>
  602. </tr>
  603. <tr>
  604. <td id="file-webp-service-worker-js-L24" class="blob-num js-line-number" data-line-number="24"></td>
  605. <td id="file-webp-service-worker-js-LC24" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// Browser supports WebP</span></td>
  606. </tr>
  607. <tr>
  608. <td id="file-webp-service-worker-js-L25" class="blob-num js-line-number" data-line-number="25"></td>
  609. <td id="file-webp-service-worker-js-LC25" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">if</span> ( supports_webp )</td>
  610. </tr>
  611. <tr>
  612. <td id="file-webp-service-worker-js-L26" class="blob-num js-line-number" data-line-number="26"></td>
  613. <td id="file-webp-service-worker-js-LC26" class="blob-code blob-code-inner js-file-line"> {</td>
  614. </tr>
  615. <tr>
  616. <td id="file-webp-service-worker-js-L27" class="blob-num js-line-number" data-line-number="27"></td>
  617. <td id="file-webp-service-worker-js-LC27" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// Make the new URL</span></td>
  618. </tr>
  619. <tr>
  620. <td id="file-webp-service-worker-js-L28" class="blob-num js-line-number" data-line-number="28"></td>
  621. <td id="file-webp-service-worker-js-LC28" class="blob-code blob-code-inner js-file-line"> webp_url <span class="pl-k">=</span> url.<span class="pl-c1">substr</span>(<span class="pl-c1">0</span>, url.<span class="pl-c1">lastIndexOf</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>.<span class="pl-pds">&#39;</span></span>)) <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span>.webp<span class="pl-pds">&#39;</span></span>;</td>
  622. </tr>
  623. <tr>
  624. <td id="file-webp-service-worker-js-L29" class="blob-num js-line-number" data-line-number="29"></td>
  625. <td id="file-webp-service-worker-js-LC29" class="blob-code blob-code-inner js-file-line">
  626. </td>
  627. </tr>
  628. <tr>
  629. <td id="file-webp-service-worker-js-L30" class="blob-num js-line-number" data-line-number="30"></td>
  630. <td id="file-webp-service-worker-js-LC30" class="blob-code blob-code-inner js-file-line"> <span class="pl-c1">event</span>.respondWith(</td>
  631. </tr>
  632. <tr>
  633. <td id="file-webp-service-worker-js-L31" class="blob-num js-line-number" data-line-number="31"></td>
  634. <td id="file-webp-service-worker-js-LC31" class="blob-code blob-code-inner js-file-line"> fetch(</td>
  635. </tr>
  636. <tr>
  637. <td id="file-webp-service-worker-js-L32" class="blob-num js-line-number" data-line-number="32"></td>
  638. <td id="file-webp-service-worker-js-LC32" class="blob-code blob-code-inner js-file-line"> webp_url,</td>
  639. </tr>
  640. <tr>
  641. <td id="file-webp-service-worker-js-L33" class="blob-num js-line-number" data-line-number="33"></td>
  642. <td id="file-webp-service-worker-js-LC33" class="blob-code blob-code-inner js-file-line"> { mode<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">&#39;</span>no-cors<span class="pl-pds">&#39;</span></span> }</td>
  643. </tr>
  644. <tr>
  645. <td id="file-webp-service-worker-js-L34" class="blob-num js-line-number" data-line-number="34"></td>
  646. <td id="file-webp-service-worker-js-LC34" class="blob-code blob-code-inner js-file-line"> )</td>
  647. </tr>
  648. <tr>
  649. <td id="file-webp-service-worker-js-L35" class="blob-num js-line-number" data-line-number="35"></td>
  650. <td id="file-webp-service-worker-js-LC35" class="blob-code blob-code-inner js-file-line"> );</td>
  651. </tr>
  652. <tr>
  653. <td id="file-webp-service-worker-js-L36" class="blob-num js-line-number" data-line-number="36"></td>
  654. <td id="file-webp-service-worker-js-LC36" class="blob-code blob-code-inner js-file-line"> }</td>
  655. </tr>
  656. <tr>
  657. <td id="file-webp-service-worker-js-L37" class="blob-num js-line-number" data-line-number="37"></td>
  658. <td id="file-webp-service-worker-js-LC37" class="blob-code blob-code-inner js-file-line"> }</td>
  659. </tr>
  660. <tr>
  661. <td id="file-webp-service-worker-js-L38" class="blob-num js-line-number" data-line-number="38"></td>
  662. <td id="file-webp-service-worker-js-LC38" class="blob-code blob-code-inner js-file-line">});</td>
  663. </tr>
  664. </table>
  665. </div>
  666. </div>
  667. </div>
  668. <pre><code> &lt;/div&gt;
  669. &lt;div class="gist-meta"&gt;
  670. &lt;a href="https://gist.github.com/aarongustafson/ff6aef09a10038e1728a/raw/078af4350bca2900c2d4dc10b3827948bc401c9b/webp-service-worker.js" style="float:right"&gt;view raw&lt;/a&gt;
  671. &lt;a href="https://gist.github.com/aarongustafson/ff6aef09a10038e1728a#file-webp-service-worker-js"&gt;webp-service-worker.js&lt;/a&gt;
  672. hosted with &amp;#10084; by &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;
  673. &lt;/div&gt;
  674. &lt;/div&gt;
  675. </code></pre>
  676. </div>
  677. </div>
  678. <p>When I began tucking to the caching possibilities of Service Workers, following Nicolas’ and Jeremy’s posts, I <a href="https://github.com/aarongustafson/aarongustafson.github.io/blob/source/source/_javascript/serviceworker/fetch-cached.js">opted to tweak Nicholas’ caching setup a bit</a>. I’m still not completely thrilled with it, but it’s a work in progress. I’m sure I will tweak as I get more familiar with the technology.</p>
  679. <p>To keep my Service Worker code modularized (like my other JavaScript code), I opted to <a href="https://github.com/aarongustafson/aarongustafson.github.io/tree/source/source/_javascript/serviceworker">break it up into separate files</a> and am using Gulp to merge them all together and move the combined file into the root of the site. If you’d like to follow a similar path, feel free to adapt this Gulp task (which builds all of my JavaScript):</p>
  680. <div><link rel="stylesheet" href="https://assets-cdn.github.com/assets/gist/embed-e75a8866f2a8f51e8bbbf8ca746676f1e7cacb08f4b1d9b52ea62524b333cc6d.css" />
  681. <div id="gist28197221" class="gist">
  682. <div class="gist-file">
  683. <div class="gist-data">
  684. <div class="js-gist-file-update-container js-task-list-container file-box">
  685. <div id="file-gulp-scripts-js" class="file">
  686. <div class="blob-wrapper data type-javascript">
  687. <table class="highlight tab-size js-file-line-container" data-tab-size="8">
  688. <tr>
  689. <td id="file-gulp-scripts-js-L1" class="blob-num js-line-number" data-line-number="1"></td>
  690. <td id="file-gulp-scripts-js-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-k">var</span> gulp <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp<span class="pl-pds">&#39;</span></span>),</td>
  691. </tr>
  692. <tr>
  693. <td id="file-gulp-scripts-js-L2" class="blob-num js-line-number" data-line-number="2"></td>
  694. <td id="file-gulp-scripts-js-LC2" class="blob-code blob-code-inner js-file-line"> path <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>path<span class="pl-pds">&#39;</span></span>),</td>
  695. </tr>
  696. <tr>
  697. <td id="file-gulp-scripts-js-L3" class="blob-num js-line-number" data-line-number="3"></td>
  698. <td id="file-gulp-scripts-js-LC3" class="blob-code blob-code-inner js-file-line"> folder <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-folders<span class="pl-pds">&#39;</span></span>),</td>
  699. </tr>
  700. <tr>
  701. <td id="file-gulp-scripts-js-L4" class="blob-num js-line-number" data-line-number="4"></td>
  702. <td id="file-gulp-scripts-js-LC4" class="blob-code blob-code-inner js-file-line"> gulpIf <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-if<span class="pl-pds">&#39;</span></span>),</td>
  703. </tr>
  704. <tr>
  705. <td id="file-gulp-scripts-js-L5" class="blob-num js-line-number" data-line-number="5"></td>
  706. <td id="file-gulp-scripts-js-LC5" class="blob-code blob-code-inner js-file-line"> insert <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-insert<span class="pl-pds">&#39;</span></span>),</td>
  707. </tr>
  708. <tr>
  709. <td id="file-gulp-scripts-js-L6" class="blob-num js-line-number" data-line-number="6"></td>
  710. <td id="file-gulp-scripts-js-LC6" class="blob-code blob-code-inner js-file-line"> concat <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-concat<span class="pl-pds">&#39;</span></span>),</td>
  711. </tr>
  712. <tr>
  713. <td id="file-gulp-scripts-js-L7" class="blob-num js-line-number" data-line-number="7"></td>
  714. <td id="file-gulp-scripts-js-LC7" class="blob-code blob-code-inner js-file-line"> uglify <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-uglify<span class="pl-pds">&#39;</span></span>),</td>
  715. </tr>
  716. <tr>
  717. <td id="file-gulp-scripts-js-L8" class="blob-num js-line-number" data-line-number="8"></td>
  718. <td id="file-gulp-scripts-js-LC8" class="blob-code blob-code-inner js-file-line"> notify <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-notify<span class="pl-pds">&#39;</span></span>),</td>
  719. </tr>
  720. <tr>
  721. <td id="file-gulp-scripts-js-L9" class="blob-num js-line-number" data-line-number="9"></td>
  722. <td id="file-gulp-scripts-js-LC9" class="blob-code blob-code-inner js-file-line"> rename <span class="pl-k">=</span> <span class="pl-c1">require</span>(<span class="pl-s"><span class="pl-pds">&#39;</span>gulp-rename<span class="pl-pds">&#39;</span></span>),</td>
  723. </tr>
  724. <tr>
  725. <td id="file-gulp-scripts-js-L10" class="blob-num js-line-number" data-line-number="10"></td>
  726. <td id="file-gulp-scripts-js-LC10" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">//handleErrors = require(&#39;handleErrors&#39;),</span></td>
  727. </tr>
  728. <tr>
  729. <td id="file-gulp-scripts-js-L11" class="blob-num js-line-number" data-line-number="11"></td>
  730. <td id="file-gulp-scripts-js-LC11" class="blob-code blob-code-inner js-file-line"> source_folder <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>source/_javascript<span class="pl-pds">&#39;</span></span>,</td>
  731. </tr>
  732. <tr>
  733. <td id="file-gulp-scripts-js-L12" class="blob-num js-line-number" data-line-number="12"></td>
  734. <td id="file-gulp-scripts-js-LC12" class="blob-code blob-code-inner js-file-line"> destination_root <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>source<span class="pl-pds">&#39;</span></span>,</td>
  735. </tr>
  736. <tr>
  737. <td id="file-gulp-scripts-js-L13" class="blob-num js-line-number" data-line-number="13"></td>
  738. <td id="file-gulp-scripts-js-LC13" class="blob-code blob-code-inner js-file-line"> destination_folder <span class="pl-k">=</span> destination_root <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span>/j<span class="pl-pds">&#39;</span></span>,</td>
  739. </tr>
  740. <tr>
  741. <td id="file-gulp-scripts-js-L14" class="blob-num js-line-number" data-line-number="14"></td>
  742. <td id="file-gulp-scripts-js-LC14" class="blob-code blob-code-inner js-file-line"> public_root <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>public<span class="pl-pds">&#39;</span></span></td>
  743. </tr>
  744. <tr>
  745. <td id="file-gulp-scripts-js-L15" class="blob-num js-line-number" data-line-number="15"></td>
  746. <td id="file-gulp-scripts-js-LC15" class="blob-code blob-code-inner js-file-line"> public_folder <span class="pl-k">=</span> public_root <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span>/j<span class="pl-pds">&#39;</span></span>,</td>
  747. </tr>
  748. <tr>
  749. <td id="file-gulp-scripts-js-L16" class="blob-num js-line-number" data-line-number="16"></td>
  750. <td id="file-gulp-scripts-js-LC16" class="blob-code blob-code-inner js-file-line"> rename_serviceworker <span class="pl-k">=</span> rename({</td>
  751. </tr>
  752. <tr>
  753. <td id="file-gulp-scripts-js-L17" class="blob-num js-line-number" data-line-number="17"></td>
  754. <td id="file-gulp-scripts-js-LC17" class="blob-code blob-code-inner js-file-line"> dirname<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">&quot;</span>../<span class="pl-pds">&quot;</span></span></td>
  755. </tr>
  756. <tr>
  757. <td id="file-gulp-scripts-js-L18" class="blob-num js-line-number" data-line-number="18"></td>
  758. <td id="file-gulp-scripts-js-LC18" class="blob-code blob-code-inner js-file-line"> });</td>
  759. </tr>
  760. <tr>
  761. <td id="file-gulp-scripts-js-L19" class="blob-num js-line-number" data-line-number="19"></td>
  762. <td id="file-gulp-scripts-js-LC19" class="blob-code blob-code-inner js-file-line">
  763. </td>
  764. </tr>
  765. <tr>
  766. <td id="file-gulp-scripts-js-L20" class="blob-num js-line-number" data-line-number="20"></td>
  767. <td id="file-gulp-scripts-js-LC20" class="blob-code blob-code-inner js-file-line">gulp.task(<span class="pl-s"><span class="pl-pds">&#39;</span>scripts<span class="pl-pds">&#39;</span></span>, folder(source_folder, <span class="pl-k">function</span>(<span class="pl-smi">folder</span>){</td>
  768. </tr>
  769. <tr>
  770. <td id="file-gulp-scripts-js-L21" class="blob-num js-line-number" data-line-number="21"></td>
  771. <td id="file-gulp-scripts-js-LC21" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">return</span> gulp.src(path.<span class="pl-c1">join</span>(source_folder, folder, <span class="pl-s"><span class="pl-pds">&#39;</span>*.js<span class="pl-pds">&#39;</span></span>))</td>
  772. </tr>
  773. <tr>
  774. <td id="file-gulp-scripts-js-L22" class="blob-num js-line-number" data-line-number="22"></td>
  775. <td id="file-gulp-scripts-js-LC22" class="blob-code blob-code-inner js-file-line"> .pipe(<span class="pl-c1">concat</span>(folder <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span>.js<span class="pl-pds">&#39;</span></span>))</td>
  776. </tr>
  777. <tr>
  778. <td id="file-gulp-scripts-js-L23" class="blob-num js-line-number" data-line-number="23"></td>
  779. <td id="file-gulp-scripts-js-LC23" class="blob-code blob-code-inner js-file-line"> .pipe(insert.transform(<span class="pl-k">function</span>(<span class="pl-smi">contents</span>, <span class="pl-smi">file</span>){</td>
  780. </tr>
  781. <tr>
  782. <td id="file-gulp-scripts-js-L24" class="blob-num js-line-number" data-line-number="24"></td>
  783. <td id="file-gulp-scripts-js-LC24" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">// insert a build time variable</span></td>
  784. </tr>
  785. <tr>
  786. <td id="file-gulp-scripts-js-L25" class="blob-num js-line-number" data-line-number="25"></td>
  787. <td id="file-gulp-scripts-js-LC25" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">var</span> build_time <span class="pl-k">=</span> (<span class="pl-k">new</span> <span class="pl-en">Date</span>()).<span class="pl-c1">getTime</span>() <span class="pl-k">+</span> <span class="pl-s"><span class="pl-pds">&#39;</span><span class="pl-pds">&#39;</span></span>;</td>
  788. </tr>
  789. <tr>
  790. <td id="file-gulp-scripts-js-L26" class="blob-num js-line-number" data-line-number="26"></td>
  791. <td id="file-gulp-scripts-js-LC26" class="blob-code blob-code-inner js-file-line"> <span class="pl-k">return</span> contents.<span class="pl-c1">replace</span>( <span class="pl-s"><span class="pl-pds">&#39;</span>{{BUILD_TIME}}<span class="pl-pds">&#39;</span></span>, build_time );</td>
  792. </tr>
  793. <tr>
  794. <td id="file-gulp-scripts-js-L27" class="blob-num js-line-number" data-line-number="27"></td>
  795. <td id="file-gulp-scripts-js-LC27" class="blob-code blob-code-inner js-file-line"> }))</td>
  796. </tr>
  797. <tr>
  798. <td id="file-gulp-scripts-js-L28" class="blob-num js-line-number" data-line-number="28"></td>
  799. <td id="file-gulp-scripts-js-LC28" class="blob-code blob-code-inner js-file-line"> .pipe(gulp.dest(destination_folder))</td>
  800. </tr>
  801. <tr>
  802. <td id="file-gulp-scripts-js-L29" class="blob-num js-line-number" data-line-number="29"></td>
  803. <td id="file-gulp-scripts-js-LC29" class="blob-code blob-code-inner js-file-line"> .pipe(gulp.dest(public_folder))</td>
  804. </tr>
  805. <tr>
  806. <td id="file-gulp-scripts-js-L30" class="blob-num js-line-number" data-line-number="30"></td>
  807. <td id="file-gulp-scripts-js-LC30" class="blob-code blob-code-inner js-file-line"> .pipe(rename({suffix<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">&#39;</span>.min<span class="pl-pds">&#39;</span></span>}))</td>
  808. </tr>
  809. <tr>
  810. <td id="file-gulp-scripts-js-L31" class="blob-num js-line-number" data-line-number="31"></td>
  811. <td id="file-gulp-scripts-js-LC31" class="blob-code blob-code-inner js-file-line"> .pipe(uglify())</td>
  812. </tr>
  813. <tr>
  814. <td id="file-gulp-scripts-js-L32" class="blob-num js-line-number" data-line-number="32"></td>
  815. <td id="file-gulp-scripts-js-LC32" class="blob-code blob-code-inner js-file-line"> .pipe(gulpIf(folder<span class="pl-k">==</span><span class="pl-s"><span class="pl-pds">&#39;</span>serviceworker<span class="pl-pds">&#39;</span></span>,rename_serviceworker))</td>
  816. </tr>
  817. <tr>
  818. <td id="file-gulp-scripts-js-L33" class="blob-num js-line-number" data-line-number="33"></td>
  819. <td id="file-gulp-scripts-js-LC33" class="blob-code blob-code-inner js-file-line"> .pipe(gulp.dest(destination_folder))</td>
  820. </tr>
  821. <tr>
  822. <td id="file-gulp-scripts-js-L34" class="blob-num js-line-number" data-line-number="34"></td>
  823. <td id="file-gulp-scripts-js-LC34" class="blob-code blob-code-inner js-file-line"> .pipe(gulp.dest(public_folder))</td>
  824. </tr>
  825. <tr>
  826. <td id="file-gulp-scripts-js-L35" class="blob-num js-line-number" data-line-number="35"></td>
  827. <td id="file-gulp-scripts-js-LC35" class="blob-code blob-code-inner js-file-line"> .pipe(notify({ message<span class="pl-k">:</span> <span class="pl-s"><span class="pl-pds">&#39;</span>Scripts task complete<span class="pl-pds">&#39;</span></span> }));</td>
  828. </tr>
  829. <tr>
  830. <td id="file-gulp-scripts-js-L36" class="blob-num js-line-number" data-line-number="36"></td>
  831. <td id="file-gulp-scripts-js-LC36" class="blob-code blob-code-inner js-file-line"> <span class="pl-c">//.on(&#39;error&#39;, handleErrors);</span></td>
  832. </tr>
  833. <tr>
  834. <td id="file-gulp-scripts-js-L37" class="blob-num js-line-number" data-line-number="37"></td>
  835. <td id="file-gulp-scripts-js-LC37" class="blob-code blob-code-inner js-file-line">}));</td>
  836. </tr>
  837. </table>
  838. </div>
  839. </div>
  840. </div>
  841. <pre><code> &lt;/div&gt;
  842. &lt;div class="gist-meta"&gt;
  843. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea/raw/b6ca32d30643137603def7b4805d7bdcbfe63137/gulp-scripts.js" style="float:right"&gt;view raw&lt;/a&gt;
  844. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea#file-gulp-scripts-js"&gt;gulp-scripts.js&lt;/a&gt;
  845. hosted with &amp;#10084; by &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;
  846. &lt;/div&gt;
  847. &lt;/div&gt;
  848. </code></pre>
  849. </div>
  850. </div>
  851. <p>As most of the walkthroughs recommended that you version your Service Worker if you’re doing any caching, I set mine up to be auto-versioned by inserting a timestamp (lines 23-27, above) into my Service Worker header file (line 3, below):</p>
  852. <div><link rel="stylesheet" href="https://assets-cdn.github.com/assets/gist/embed-e75a8866f2a8f51e8bbbf8ca746676f1e7cacb08f4b1d9b52ea62524b333cc6d.css" />
  853. <div id="gist28197221" class="gist">
  854. <div class="gist-file">
  855. <div class="gist-data">
  856. <div class="js-gist-file-update-container js-task-list-container file-box">
  857. <div id="file-_header-js" class="file">
  858. <div class="blob-wrapper data type-javascript">
  859. <table class="highlight tab-size js-file-line-container" data-tab-size="8">
  860. <tr>
  861. <td id="file-_header-js-L1" class="blob-num js-line-number" data-line-number="1"></td>
  862. <td id="file-_header-js-LC1" class="blob-code blob-code-inner js-file-line"><span class="pl-s"><span class="pl-pds">&#39;</span>use strict<span class="pl-pds">&#39;</span></span>;</td>
  863. </tr>
  864. <tr>
  865. <td id="file-_header-js-L2" class="blob-num js-line-number" data-line-number="2"></td>
  866. <td id="file-_header-js-LC2" class="blob-code blob-code-inner js-file-line">
  867. </td>
  868. </tr>
  869. <tr>
  870. <td id="file-_header-js-L3" class="blob-num js-line-number" data-line-number="3"></td>
  871. <td id="file-_header-js-LC3" class="blob-code blob-code-inner js-file-line"><span class="pl-k">var</span> version <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>v{{BUILD_TIME}}:<span class="pl-pds">&#39;</span></span>,</td>
  872. </tr>
  873. <tr>
  874. <td id="file-_header-js-L4" class="blob-num js-line-number" data-line-number="4"></td>
  875. <td id="file-_header-js-LC4" class="blob-code blob-code-inner js-file-line"> default_avatar <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mm&amp;f=y<span class="pl-pds">&#39;</span></span>,</td>
  876. </tr>
  877. <tr>
  878. <td id="file-_header-js-L5" class="blob-num js-line-number" data-line-number="5"></td>
  879. <td id="file-_header-js-LC5" class="blob-code blob-code-inner js-file-line"> missing_image <span class="pl-k">=</span> <span class="pl-s"><span class="pl-pds">&#39;</span>https://i.imgur.com/oWLuFAa.gif<span class="pl-pds">&#39;</span></span>;</td>
  880. </tr>
  881. </table>
  882. </div>
  883. </div>
  884. </div>
  885. <pre><code> &lt;/div&gt;
  886. &lt;div class="gist-meta"&gt;
  887. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea/raw/b6ca32d30643137603def7b4805d7bdcbfe63137/_header.js" style="float:right"&gt;view raw&lt;/a&gt;
  888. &lt;a href="https://gist.github.com/aarongustafson/7f05709cca9293e4efea#file-_header-js"&gt;_header.js&lt;/a&gt;
  889. hosted with &amp;#10084; by &lt;a href="https://github.com"&gt;GitHub&lt;/a&gt;
  890. &lt;/div&gt;
  891. &lt;/div&gt;
  892. </code></pre>
  893. </div>
  894. </div>
  895. <p>Service Workers are still pretty new (and <a href="http://caniuse.com/#feat=serviceworkers">modestly supported</a>), but it’s definitely interesting to see what’s possible using them. <a href="https://adactio.com/journal/9844">Like Jeremy</a>, I want to do a bit more exploration into caching and how it may actually <em>increase</em> the monetary cost of accessing a website if not used properly. Like any powerful tool, we need to wield it wisely.</p>
  896. <figure><img src="https://media.giphy.com/media/dlmcYrvalMmAw/giphy.gif" alt="Animated GIF of a guy accidentally launching a board into his helper while power sanding." /></figure>
  897. <h2 id="making-gists-static">Making Gists Static</h2>
  898. <p>On particularly code-heavy posts (yes, like this one), I make liberal use of Gists. They’re quite useful, but <a href="https://gist.github.com/BinaryMuse/803483">the Gist plugin for Jekyll</a>, while good, still requests a script from Github in order to load the pretty printed version of the Gist. On some posts, that can mean 5 or more additional network requests, not to mention execution time for the JavaScript. It’s yet another dependency that could prohibit you from quickly getting to the content you’re looking for. Additionally, <a href="https://gds.blog.gov.uk/2013/10/21/how-many-people-are-missing-out-on-javascript-enhancement/">if JavaScript should be available, but isn’t</a>, you get nothing (since the <code>noscript</code> content is only evaluated if JavaScript support isn’t available or if a user turns it off).</p>
  899. <p>With all of this in mind, I decided to revise the plugin and make it capable of downloading the JavaScript code directly. It then extracts the HTML markup that the JavaScript would be writing into the page and just embeds it directly. It also caches the result, which is handy for speeding up the build process.</p>
  900. <p>You can grab <a href="https://gist.github.com/aarongustafson/b98add8f3580f6707cf5">my fork of the Gist Jekyll Plugin as, well, a Gist</a>. It’s also <a href="https://github.com/aarongustafson/aarongustafson.github.io/blob/source/plugins/gist_tag.rb">in the source of this site on Github</a>.</p>
  901. <h2 id="hopefully-a-little-faster">(Hopefully) A Little Faster</h2>
  902. <p>All told, these changes have gotten the render time of this site down significantly across the board.<sup id="fnref:2"><a href="#fn:2" class="footnote">2</a></sup> Even more so on browsers that support Service Workers and Resource Hints. I’ll likely continue tweaking as I go, but I wanted to share my process, code, and thoughts in case any of it might be useful to you in your own work. In the end, it’s all about creating better experiences for our users. How our sites perform is a big part of that.</p>
  903. <div class="footnotes">
  904. <ol>
  905. <li id="fn:1">
  906. <p>Sadly I forgot to run some speed tests prior to rolling out this change and I didn’t feel like rolling back the site, so I don’t have solid numbers for you. That said, it seemed to shave nearly 2 seconds off of the load time on heavy pages like the post I mentioned. <a href="#fnref:1" class="reversefootnote">&#8617;</a></p>
  907. </li>
  908. <li id="fn:2">
  909. <p>Again, I don’t have the numbers, but I am routinely seeing <code>DOMContentLoaded</code> reached between 400-600ms with Service Worker caching in play. <a href="#fnref:2" class="reversefootnote">&#8617;</a></p>
  910. </li>
  911. </ol>
  912. </div>
  913. </article>
  914. </section>
  915. <nav id="jumpto">
  916. <p>
  917. <a href="/david/blog/">Accueil du blog</a> |
  918. <a href="https://www.aaron-gustafson.com/notebook/speeding-things-up-with-service-worker-resource-hints-and-more/">Source originale</a> |
  919. <a href="/david/stream/2019/">Accueil du flux</a>
  920. </p>
  921. </nav>
  922. <footer>
  923. <div>
  924. <img src="/static/david/david-larlet-avatar.jpg" loading="lazy" class="avatar" width="200" height="200">
  925. <p>
  926. Bonjour/Hi!
  927. Je suis <a href="/david/" title="Profil public">David&nbsp;Larlet</a>, je vis actuellement à Montréal et j’alimente cet espace depuis 15 ans. <br>
  928. Si tu as apprécié cette lecture, n’hésite pas à poursuivre ton exploration. Par exemple via les <a href="/david/blog/" title="Expériences bienveillantes">réflexions bimestrielles</a>, la <a href="/david/stream/2019/" title="Pensées (dés)articulées">veille hebdomadaire</a> ou en t’abonnant au <a href="/david/log/" title="S’abonner aux publications via RSS">flux RSS</a> (<a href="/david/blog/2019/flux-rss/" title="Tiens c’est quoi un flux RSS ?">so 2005</a>).
  929. </p>
  930. <p>
  931. Je m’intéresse à la place que je peux avoir dans ce monde. En tant qu’humain, en tant que membre d’une famille et en tant qu’associé d’une coopérative. De temps en temps, je fais aussi des <a href="https://github.com/davidbgk" title="Principalement sur Github mais aussi ailleurs">trucs techniques</a>. Et encore plus rarement, <a href="/david/talks/" title="En ce moment je laisse plutôt la place aux autres">j’en parle</a>.
  932. </p>
  933. <p>
  934. Voici quelques articles choisis :
  935. <a href="/david/blog/2019/faire-equipe/" title="Accéder à l’article complet">Faire équipe</a>,
  936. <a href="/david/blog/2018/bivouac-automnal/" title="Accéder à l’article complet">Bivouac automnal</a>,
  937. <a href="/david/blog/2018/commodite-effondrement/" title="Accéder à l’article complet">Commodité et effondrement</a>,
  938. <a href="/david/blog/2017/donnees-communs/" title="Accéder à l’article complet">Des données aux communs</a>,
  939. <a href="/david/blog/2016/accompagner-enfant/" title="Accéder à l’article complet">Accompagner un enfant</a>,
  940. <a href="/david/blog/2016/senior-developer/" title="Accéder à l’article complet">Senior developer</a>,
  941. <a href="/david/blog/2016/illusion-sociale/" title="Accéder à l’article complet">L’illusion sociale</a>,
  942. <a href="/david/blog/2016/instantane-scopyleft/" title="Accéder à l’article complet">Instantané Scopyleft</a>,
  943. <a href="/david/blog/2016/enseigner-web/" title="Accéder à l’article complet">Enseigner le Web</a>,
  944. <a href="/david/blog/2016/simplicite-defaut/" title="Accéder à l’article complet">Simplicité par défaut</a>,
  945. <a href="/david/blog/2016/minimalisme-esthetique/" title="Accéder à l’article complet">Minimalisme et esthétique</a>,
  946. <a href="/david/blog/2014/un-web-omni-present/" title="Accéder à l’article complet">Un web omni-présent</a>,
  947. <a href="/david/blog/2014/manifeste-developpeur/" title="Accéder à l’article complet">Manifeste de développeur</a>,
  948. <a href="/david/blog/2013/confort-convivialite/" title="Accéder à l’article complet">Confort et convivialité</a>,
  949. <a href="/david/blog/2013/testament-numerique/" title="Accéder à l’article complet">Testament numérique</a>,
  950. et <a href="/david/blog/" title="Accéder aux archives">bien d’autres…</a>
  951. </p>
  952. <p>
  953. On peut <a href="mailto:david%40larlet.fr" title="Envoyer un courriel">échanger par courriel</a>. Si éventuellement tu souhaites que l’on travaille ensemble, tu devrais commencer par consulter le <a href="http://larlet.com">profil dédié à mon activité professionnelle</a> et/ou contacter directement <a href="http://scopyleft.fr/">scopyleft</a>, la <abbr title="Société coopérative et participative">SCOP</abbr> dont je fais partie depuis six ans. Je recommande au préalable de lire <a href="/david/blog/2018/cout-site/" title="Attention ce qui va suivre peut vous choquer">combien coûte un site</a> et pourquoi je suis plutôt favorable à une <a href="/david/pro/devis/" title="Discutons-en !">non-demande de devis</a>.
  954. </p>
  955. <p>
  956. Je ne traque pas ta navigation mais mon
  957. <abbr title="Alwaysdata, 62 rue Tiquetonne 75002 Paris, +33.184162340">hébergeur</abbr>
  958. conserve des logs d’accès.
  959. </p>
  960. </div>
  961. </footer>
  962. <script type="text/javascript">
  963. ;(_ => {
  964. const jumper = document.getElementById('jumper')
  965. jumper.addEventListener('click', e => {
  966. e.preventDefault()
  967. const anchor = e.target.getAttribute('href')
  968. const targetEl = document.getElementById(anchor.substring(1))
  969. targetEl.scrollIntoView({behavior: 'smooth'})
  970. })
  971. })()
  972. </script>