<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Paul Bakaus on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Paul Bakaus</name>
  </author>
  <link href="https://web.dev/authors/pbakaus/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/dmZ5xayLJVUioaNSvtmB.jpeg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Open Web Developer Advocate at Google • Tools, Performance, Animation, UX</subtitle>
  
  
  <entry>
    <title>Icons and browser colors</title>
    <link href="https://web.dev/icons-and-browser-colors/"/>
    <updated>2015-09-21T00:00:00Z</updated>
    <id>https://web.dev/icons-and-browser-colors/</id>
    <content type="html" mode="escaped">&lt;p&gt;Modern browsers make it easy to customize certain components, like icons, the address bar color, and even add things like custom tiles. These simple tweaks can increase engagement and bring users back to your site.&lt;/p&gt;
&lt;h2 id=&quot;provide-great-icons-and-tiles&quot;&gt;Provide great icons and tiles &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#provide-great-icons-and-tiles&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When a user visits your webpage, the browser tries to fetch an icon from the HTML. The icon may show up in many places, including the browser tab, recent app switch, the new (or recently visited) tab page, and more.&lt;/p&gt;
&lt;p&gt;Providing a high quality image will make your site more recognizable, making it
easier for users to find your site.&lt;/p&gt;
&lt;p&gt;To fully support all browsers, you&#39;ll need to add a few tags to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
element of each page.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- icon in the highest resolution we need it for --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sizes&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;192x192&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- reuse same icon for Safari --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;apple-touch-icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ios-icon.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- multiple icons for IE --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msapplication-square310x310logo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon_largetile.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;chrome-and-opera&quot;&gt;Chrome and Opera &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#chrome-and-opera&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Chrome and Opera uses &lt;code&gt;icon.png&lt;/code&gt;, which is scaled to the necessary size by
the device. To prevent automatic scaling, you can also provide additional
sizes by specifying the &lt;code&gt;sizes&lt;/code&gt; attribute.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Icons sizes should be based on 48px, for example 48px, 96px, 144px and 192px. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;safari&quot;&gt;Safari &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#safari&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari also uses the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag with the &lt;code&gt;rel&lt;/code&gt; attribute: &lt;code&gt;apple-touch-icon&lt;/code&gt; to
indicate the home screen icon.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;apple-touch-icon&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;touch-icon-iphone.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A non-transparent PNG that&#39;s 180px or 192px square is ideal for the apple-touch-icon.&lt;/p&gt;
&lt;p&gt;Including multiple versions via the &lt;code&gt;sizes&lt;/code&gt; attribute is not recommended.
Previously, Safari for iOS would consider the &lt;code&gt;-precomposed&lt;/code&gt; keyword to avoid
adding visual effects, but it hasn&#39;t been necessary since iOS 7.&lt;/p&gt;
&lt;h3 id=&quot;internet-explorer-and-windows-phone&quot;&gt;Internet Explorer and Windows Phone &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#internet-explorer-and-windows-phone&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Windows 8&#39;s new home screen experience supports four different layouts for
pinned sites, and requires four icons. You can leave out the relevant meta
tags if you don&#39;t want to support a specific size.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msapplication-square70x70logo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon_smalltile.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msapplication-square150x150logo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon_mediumtile.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msapplication-wide310x150logo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon_widetile.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;tiles-in-internet-explorer&quot;&gt;Tiles in Internet Explorer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#tiles-in-internet-explorer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Microsoft’s &amp;quot;Pinned Sites&amp;quot; and rotating &amp;quot;Live Tiles&amp;quot; go far beyond other
implementations and are beyond the scope of this guide. You can learn more
at MSDN&#39;s
&lt;a href=&quot;https://msdn.microsoft.com/library/ie/dn455115(v=vs.85).aspx&quot; rel=&quot;noopener&quot;&gt;how to create live tiles&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;color-browser-elements&quot;&gt;Color browser elements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#color-browser-elements&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Using different &lt;code&gt;meta&lt;/code&gt; elements, you can customize the browser and
even elements of the platform. Keep in mind that some may only work on certain
platforms or browsers, but they can greatly enhance the experience.&lt;/p&gt;
&lt;p&gt;Chrome, Firefox OS, Safari, Internet Explorer and Opera Coast allow you to define
colors for elements of the browser, and even the platform using meta tags.&lt;/p&gt;
&lt;h3 id=&quot;meta-theme-color-for-chrome-and-opera&quot;&gt;Meta Theme Color for Chrome and Opera &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#meta-theme-color-for-chrome-and-opera&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To specify the theme color for Chrome on Android, use the meta theme color.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- Chrome, Firefox OS and Opera --&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;theme-color&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#4285f4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;figure&gt;
&lt;img alt=&quot;Theme colors styling the address bar in Chrome.&quot; decoding=&quot;async&quot; height=&quot;614&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/TjmJNR9LC84mh8LX2zxE.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;safari-specific-styling&quot;&gt;Safari specific styling &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#safari-specific-styling&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Safari allows you to style the status bar and specify a startup image.&lt;/p&gt;
&lt;h4 id=&quot;specify-a-startup-image&quot;&gt;Specify a startup image &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#specify-a-startup-image&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By default, Safari shows a blank screen during load time and after multiple
loads a screenshot of the previous state of the app. You can prevent this by
telling Safari to show an explicit startup image, by adding a link tag, with
&lt;code&gt;rel=apple-touch-startup-image&lt;/code&gt;. For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;apple-touch-startup-image&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;icon.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The image has to be in the specific size of the target device&#39;s screen or it
won&#39;t be used. Refer to
&lt;a href=&quot;https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/ConfiguringWebApplications/ConfiguringWebApplications.html&quot; rel=&quot;noopener&quot;&gt;Safari Web Content Guidelines&lt;/a&gt;
for further details.&lt;/p&gt;
&lt;p&gt;While Apple&#39;s documentation is sparse on this topic, the developer community
has figured out a way to target all devices by using advanced media queries to
select the appropriate device and then specify the correct image. Here&#39;s a
working solution, courtesy of &lt;a href=&quot;https://gist.github.com/tfausak/2222823&quot; rel=&quot;noopener&quot;&gt;tfausak&#39;s gist&lt;/a&gt;&lt;/p&gt;
&lt;h4 id=&quot;change-the-status-bar-appearance&quot;&gt;Change the status bar appearance &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/icons-and-browser-colors/#change-the-status-bar-appearance&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;You can change the appearance of the default status bar to either &lt;code&gt;black&lt;/code&gt; or
&lt;code&gt;black-translucent&lt;/code&gt;. With &lt;code&gt;black-translucent&lt;/code&gt;, the status bar floats on top
of the full screen content, rather than pushing it down. This gives the layout
more height, but obstructs the top.  Here’s the code required:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;apple-mobile-web-app-status-bar-style&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;black&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;  &lt;figure class=&quot;float-left&quot;&gt;
    &lt;img alt=&quot;Screenshot using black-translucent.&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;258&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 328px) 328px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/bIbzhcWA4st4dZNGhInp.png?auto=format&amp;w=656 656w&quot; width=&quot;328&quot; /&gt;
    &lt;figcaption&gt;Screenshot using &lt;code&gt;black-translucent&lt;/code&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure class=&quot;float-right&quot;&gt;
    &lt;img alt=&quot;Screenshot using black&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;258&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 328px) 328px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/ZHhtEoITFZ1LakJTYruY.png?auto=format&amp;w=656 656w&quot; width=&quot;328&quot; /&gt;
    &lt;figcaption&gt;Screenshot using &lt;code&gt;black&lt;/code&gt;&lt;/figcaption&gt;
  &lt;/figure&gt;
</content>
    <author>
      <name>Paul Bakaus</name>
    </author>
  </entry>
  
  <entry>
    <title>Little Alchemy</title>
    <link href="https://web.dev/little-alchemy/"/>
    <updated>2015-04-08T00:00:00Z</updated>
    <id>https://web.dev/little-alchemy/</id>
    <content type="html" mode="escaped">&lt;figure&gt;
&lt;img alt=&quot;Little Alchemy detail&quot; decoding=&quot;async&quot; height=&quot;313&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 159px) 159px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=159 159w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=181 181w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=207 207w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=236 236w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=269 269w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=306 306w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/UMRTodImzQkE65TkMkeV.png?auto=format&amp;w=318 318w&quot; width=&quot;159&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#summary&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://littlealchemy.com/&quot; rel=&quot;noopener&quot;&gt;Little Alchem&lt;/a&gt;: A fun, mobile-friendly combination
game inspired by its bigger brother Alchemy.&lt;/p&gt;
&lt;h3 id=&quot;what-we-like&quot;&gt;What we like? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#what-we-like&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Little Alchemy is a prime example of using all of the web platform&#39;s latest
abilities to its full advantage. It uses the
&lt;a href=&quot;https://developers.google.com/web/fundamentals/engage-and-retain/simplified-app-installs&quot; rel=&quot;noopener&quot;&gt;web app manifest&lt;/a&gt;
to launch fullscreen when installed and blends in with Android with the help of
&lt;a href=&quot;https://developers.google.com/web/fundamentals/design-and-ux/browser-customization/&quot; rel=&quot;noopener&quot;&gt;theme-color&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The first time load is extremely responsive and shows the preloader right
away. In addition, it can be played entirely offline through its use of
AppCache. Well done.&lt;/p&gt;
&lt;h3 id=&quot;possible-improvements&quot;&gt;Possible Improvements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#possible-improvements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;On Desktop, blocking right clicking is usually considered no-no (but it
allowed me to find the secret cheat code by mistyping the Chrome DevTools
shortcut :)). Not a terribly big deal for a game though.&lt;/p&gt;
&lt;p&gt;UI-wise, a grid might improve the &#39;all-over-the-place&#39; feel, and when
dragging elements on mobile, shifting them slightly to the top so that you
can see what you&#39;re moving below your finger could improve visibility.&lt;/p&gt;
&lt;h2 id=&quot;q-and-a-with-jakub-koziol&quot;&gt;Q &amp;amp; A with Jakub Koziol &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#q-and-a-with-jakub-koziol&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;why-the-web&quot;&gt;Why the web? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#why-the-web&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Instant access, truly cross-platform and the most convenient way of sharing on
top of that. If that doesn’t sound good I don’t know what does.&lt;/p&gt;
&lt;p&gt;Little Alchemy started as an experiment for Chrome Web Store a few years back.
Over time we expanded to other platforms but the web version remains our main
focus. Right now all of our native apps are directly based on the web app. It
cuts a lot of work and streamlines the process of updating the game, which is
incredibly important for a tiny team like ours.&lt;/p&gt;
&lt;h3 id=&quot;what-worked-really-well-during-development&quot;&gt;What worked really well during development? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#what-worked-really-well-during-development&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With the current iteration of Little Alchemy we focused a lot on the mobile
web. During the development we worked with many physical devices and remote
Chrome DevTools helped us to significantly speed up the process.&lt;/p&gt;
&lt;p&gt;We also really enjoyed the work on performance and responsive design. Current
set of tools in Chrome allows for very efficient work on these aspects of the
app.&lt;/p&gt;
&lt;h3 id=&quot;if-you-could-have-any-api-to-improve-your-app,-what-would-it-be&quot;&gt;If you could have any API to improve your app, what would it be? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/little-alchemy/#if-you-could-have-any-api-to-improve-your-app,-what-would-it-be&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Games are usually heavily dependent on images. For example we have a library
of over 500 images that need to be scalable and for the optimal experience
they should be loaded before the player starts the game. It requires different
logic than your typical web app where you can lazy load and use atlases. Having
a way to deal with that in an efficient way would save us a lot of work and
would make for a better experience for our players.&lt;/p&gt;
&lt;p&gt;Also monetization of web games is still problematic. It’s almost impossible to
implement payments without going straight into free to play and there aren’t
many elegant ways to support HTML5 games with ads. It’s an issue that inform
the types and quality of games on the web platform.&lt;/p&gt;
</content>
    <author>
      <name>Paul Bakaus</name>
    </author>
  </entry>
  
  <entry>
    <title>SVGOMG</title>
    <link href="https://web.dev/svgomg/"/>
    <updated>2015-03-24T00:00:00Z</updated>
    <id>https://web.dev/svgomg/</id>
    <content type="html" mode="escaped">&lt;figure&gt;
&lt;img alt=&quot;Svgomg screenshot&quot; decoding=&quot;async&quot; height=&quot;1570&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/JBaM0M3E1sG5xURP28m7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#summary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://jakearchibald.github.io/svgomg/&quot; rel=&quot;noopener&quot;&gt;SVGOMG&lt;/a&gt;: A beautiful, material,
responsive frontend for SVGO.&lt;/p&gt;
&lt;h3 id=&quot;what-we-like&quot;&gt;What we like? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#what-we-like&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Built by our own &lt;a href=&quot;https://jakearchibald.com/&quot; rel=&quot;noopener&quot;&gt;Jake Archibald&lt;/a&gt;, SVGOMG is an
almost perfect example of a fully responsive and capable tool written with web
technologies. It features a beautiful Material Design look, ServiceWorker
ensures that the app loads quickly and is available offline, and the
transitions are smooth on mobile.&lt;/p&gt;
&lt;h3 id=&quot;possible-improvements&quot;&gt;Possible Improvements &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#possible-improvements&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The only real nitpick we&#39;d have to offer is that the initial UX is confusing
due to the main UI missing. Other than that, job well done!&lt;/p&gt;
&lt;h2 id=&quot;q-and-a-with-jake-archibald&quot;&gt;Q &amp;amp; A with Jake Archibald &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#q-and-a-with-jake-archibald&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;why-the-web&quot;&gt;Why the web? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#why-the-web&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Laziness. Total laziness. I&#39;m not an expert in developing Windows native apps,
I&#39;m not an expert in OSX native apps, nor am I an expert in creating native
apps for iOS, Android, Windows Phone or Linux. I can however do the web, and
that one skill set let me build something &lt;em&gt;once&lt;/em&gt; that worked on all those
platforms.&lt;/p&gt;
&lt;h3 id=&quot;what-worked-really-well-during-development&quot;&gt;What worked really well during development? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#what-worked-really-well-during-development&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I&#39;m really happy with the performance of it. I ensure the page renders before
JS is available. In fact, it gets to first render with only 5k of HTML with
some inlined CSS and SVG. The main scripts and CSS are all loaded in the
background. This means the site appears to load in 1.5s even on 3G with an
empty cache, and most of that is DNS and SSL.&lt;/p&gt;
&lt;p&gt;The opening screen is really simple, so doing that in 5k wasn’t a
challenge. It really bothers me that so many sites wait on JS for their
first render, some even require their JS to make further requests before
rendering. This pushes 3G render time towards 10s – as a mobile user I know
I wouldn’t put up with that.&lt;/p&gt;
&lt;p&gt;The main JS is 15k, but doesn’t include the parts that parse and minify the
SVG, that’s loaded as an extra phase in the background. It’s great because
interactivity lands really quickly, and the user doesn’t notice the extra
loading. If the user manages to select an SVG before that script is available,
the loading of that script appears to be part of the processing time.&lt;/p&gt;
&lt;p&gt;I also used ServiceWorker to make the whole thing work offline. Working
offline is a pretty cool feature, but I’m mostly doing it for performance.
Subsequent visits to SVGOMG render almost instantly, whatever connection the
user has. Given the variations in mobile connectivity, that’s really valuable!&lt;/p&gt;
&lt;h3 id=&quot;if-you-could-have-any-api-to-improve-your-app,-what-would-it-be&quot;&gt;If you could have any API to improve your app, what would it be? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/svgomg/#if-you-could-have-any-api-to-improve-your-app,-what-would-it-be&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;I used Babel so I could make use of future JavaScript stuff. It&#39;d be great
to have some of that working natively in the platform. Specifically,
async/await, arrow functions, argument defaults and destructuring.&lt;/p&gt;
&lt;p&gt;I had to use a library to gzip the output to find out its gzipped size.
Using a library for this is kinda annoying as that code is already in the
browser for HTTP stuff, there&#39;s just no API to it. Ideally it should be some
kind of transform stream so I can count the size of the output without having
the whole thing in memory.&lt;/p&gt;
</content>
    <author>
      <name>Paul Bakaus</name>
    </author>
  </entry>
  
  <entry>
    <title>Supercharging your gruntfile</title>
    <link href="https://web.dev/supercharging-your-gruntfile/"/>
    <updated>2014-02-13T00:00:00Z</updated>
    <id>https://web.dev/supercharging-your-gruntfile/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If the Grunt world is new to you, an ideal place to start is Chris Coyier’s excellent article “&lt;a href=&quot;http://24ways.org/2013/grunt-is-not-weird-and-hard/&quot; rel=&quot;noopener&quot;&gt;Grunt for People Who Think Things Like Grunt are Weird and Hard&lt;/a&gt;”. After Chris’ introduction, you will have set up your own Grunt project and have tasted a slice of the power Grunt offers.&lt;/p&gt;
&lt;p&gt;In this article, we won’t focus on what numerous Grunt plugins do to your actual project code, but on the Grunt build process itself. We will give you practical ideas on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to keep your Gruntfile neat and tidy,&lt;/li&gt;
&lt;li&gt;How to dramatically improve your build time,&lt;/li&gt;
&lt;li&gt;And how to be notified when a build happens.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Time for a quick disclaimer: Grunt is just one of many tools you could use to accomplish the task. If Gulp is more your style, great! If after surveying the options out there, you’d still like to build your own toolchain, that’s ok too!  We chose to focus on Grunt for this article due to its strong ecosystem and long-standing user base.&lt;/p&gt;
&lt;h2 id=&quot;organizing-your-gruntfile&quot;&gt;Organizing your Gruntfile &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#organizing-your-gruntfile&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Whether you include a lot of Grunt plugins or have to write a lot of manual tasks in your Gruntfile, it can quickly become very unwieldy and hard to maintain. Fortunately, there are quite a few plugins that focus on exactly that problem: Making your Gruntfile neat and tidy again.&lt;/p&gt;
&lt;h3 id=&quot;the-gruntfile,-before-optimization&quot;&gt;The Gruntfile, before optimization &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#the-gruntfile,-before-optimization&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Here is how our Gruntfile looks like before we’ve done any optimization on it:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initConfig&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;pkg&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readJSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;package.json&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/js/jquery.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/js/intro.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/js/main.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/js/outro.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dist/build.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;uglify&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token string-property property&quot;&gt;&#39;dist/build.min.js&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dist/build.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;imagemin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token literal-property property&quot;&gt;expand&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token literal-property property&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token literal-property property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;**/*.{png,jpg,gif}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token literal-property property&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dist/&#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-uglify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-imagemin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;registerTask&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;default&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;uglify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;imagemin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If now you’re saying “Hey! I was expecting much worse! That is actually maintainable!”, you’re probably right. For the sake of simplicity, we’ve only included three plugins without much customization. Using an actual production Gruntfile building a moderately sized project would require infinite scrolling in this article. So let’s see what we can do!&lt;/p&gt;
&lt;h3 id=&quot;autoload-your-grunt-plugins&quot;&gt;Autoload your Grunt plugins &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#autoload-your-grunt-plugins&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Hint: load-grunt-config includes load-grunt-tasks, so if you don’t want to learn about what it does in detail and skip this block, it won’t hurt my feelings. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;When adding a new Grunt plugin you want to use to your project, you will have to add it both to your &lt;strong&gt;package.json&lt;/strong&gt; file as an npm dependency and then load it within the Gruntfile. For the plugin “&lt;strong&gt;grunt-contrib-concat&lt;/strong&gt;”, that might look like the following:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// tell Grunt to load that plugin&lt;/span&gt;&lt;br /&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you now uninstall the plugin via npm and update your package.json, but forget to update your Gruntfile, your build will break. This is where the nifty plugin &lt;a href=&quot;https://npmjs.org/package/load-grunt-tasks&quot; rel=&quot;noopener&quot;&gt;load-grunt-tasks&lt;/a&gt; comes to help.&lt;/p&gt;
&lt;p&gt;While before, we’ve had to manually load our Grunt plugins, like so:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-uglify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadNpmTasks&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;grunt-contrib-imagemin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With load-grunt-tasks, you can collapse that down to the following one-liner:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load-grunt-tasks&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;After requiring the plugin, it will analyze your package.json file, determine which of the dependencies are Grunt plugins and load them all automatically.&lt;/p&gt;
&lt;h3 id=&quot;splitting-your-grunt-configuration-into-different-files&quot;&gt;Splitting your Grunt configuration into different files &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#splitting-your-grunt-configuration-into-different-files&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;load-grunt-tasks&lt;/strong&gt; shrunk your Gruntfile in code and complexity a little, but as you configure a large application, it will still become a very large file. This is where &lt;a href=&quot;https://npmjs.org/package/load-grunt-config&quot; rel=&quot;noopener&quot;&gt;load-grunt-config&lt;/a&gt; comes into play. &lt;strong&gt;load-grunt-config&lt;/strong&gt; lets you break up your Gruntfile config by task. Moreover, it encapsulates &lt;strong&gt;load-grunt-tasks&lt;/strong&gt; and its functionality!&lt;/p&gt;
&lt;p&gt;Important, however: Splitting your Gruntfile might not always work for every situation. If you have lots of shared configuration between your tasks (i.e. use a lot of the Grunt templating), you should be a little careful.&lt;/p&gt;
&lt;p&gt;With &lt;strong&gt;load-grunt-config&lt;/strong&gt;, your Gruntfile.js will look like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load-grunt-config&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Yes, that’s really it, the whole file! Now where do our task configurations live?&lt;/p&gt;
&lt;p&gt;Create a folder called &lt;strong&gt;grunt/&lt;/strong&gt; in the directory of your Gruntfile. By default, the plugin includes files within that folder that match the name of the task you want to use. Our directory structure should look like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; myproject&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; Gruntfile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; grunt&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; concat&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; uglify&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; imagemin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;js&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Let’s now put the task configuration of each of our tasks directly into the respective files (you’ll see that these are mostly just copy and pastes from the original Gruntfile into a new structure):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;grunt/concat.js&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/js/jquery.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/js/intro.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/js/main.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/js/outro.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dist/build.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;grunt/uglify.js&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string-property property&quot;&gt;&#39;dist/build.min.js&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;dist/build.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;grunt/imagemin.js&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;dist&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;files&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;expand&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;cwd&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;**/*.{png,jpg,gif}&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;dist/&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If JavaScript configuration blocks are not really your thing, &lt;strong&gt;load-grunt-tasks&lt;/strong&gt; even allows you to use YAML or CoffeeScript syntax instead. Let’s write our final required file in YAML – the “&lt;strong&gt;aliases&lt;/strong&gt;” file. This is a special file that registers task aliases, something we had to do as part of the Gruntfile before via the &lt;code&gt;registerTask&lt;/code&gt; function. Here’s ours:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;grunt/aliases.yaml&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;concat&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;uglify&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;imagemin&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And that’s it! Execute the following command in your terminal:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-shell&quot;&gt;&lt;code class=&quot;language-shell&quot;&gt;$ grunt&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If everything worked, this will now look at the “default” task and run everything in order. Now that we stripped down our main Gruntfile to three lines of code we never need to touch and externalized every task configuration, we’re done here. But man, it’s still pretty slow to get everything built. Let’s see what we can do to improve that.&lt;/p&gt;
&lt;h2 id=&quot;minimizing-your-build-time&quot;&gt;Minimizing your build time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#minimizing-your-build-time&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Even though your web app’s runtime and load time performance is much more business critical than the time required to execute a build, a slow build is still problematic. It will render it difficult to execute automatic builds with plugins like &lt;a href=&quot;https://github.com/gruntjs/grunt-contrib-watch&quot; rel=&quot;noopener&quot;&gt;grunt-contrib-watch&lt;/a&gt; or after a Git commit fast enough, and introduces a “penalty” to actually run the build – the faster the build time, the more agile your workflow. If your production build takes longer than 10 minutes to run, you’ll only run the build when you absolutely have to, and you’ll wander off to get coffee while it runs. That’s a productivity killer. We’ve got things to speed up.&lt;/p&gt;
&lt;h3 id=&quot;only-build-files-that-actually-changed-grunt-newer&quot;&gt;Only build files that actually changed: grunt-newer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#only-build-files-that-actually-changed-grunt-newer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After an initial build of your site, it’s likely that you’ll have only touched a few files in the project when you get around to building again. Let’s say that in our example, you changed an image in the &lt;strong&gt;src/img/&lt;/strong&gt; directory – running imagemin to re-optimize images would make sense, but only for that single image – and of course, re-running &lt;strong&gt;concat&lt;/strong&gt; and &lt;strong&gt;uglify&lt;/strong&gt; is just wasting precious CPU cycles.&lt;/p&gt;
&lt;p&gt;Of course, you could always run &lt;code&gt;$ grunt imagemin&lt;/code&gt; from your terminal instead of &lt;code&gt;$ grunt&lt;/code&gt; to only selectively execute a task at hand, but there is a smarter way. It’s called &lt;a href=&quot;https://npmjs.org/package/grunt-newer&quot; rel=&quot;noopener&quot;&gt;grunt-newer&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Grunt-newer has a local cache in which it stores information about what files have actually changed, and only executes your tasks for the files that did, in fact, change. Let’s take a look on how to activate it.&lt;/p&gt;
&lt;p&gt;Remember our &lt;strong&gt;aliases.yaml&lt;/strong&gt; file? Change it from this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;concat&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;uglify&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;imagemin&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;to this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;newer:concat&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;newer:uglify&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;newer:imagemin&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Simply prepending “newer:” to any of your tasks &lt;strong&gt;pipes your source and destination files through the grunt-newer plugin first, which then determines for what files, if any, the task should run&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 id=&quot;run-multiple-tasks-in-parallel-grunt-concurrent&quot;&gt;Run multiple tasks in parallel: grunt-concurrent &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#run-multiple-tasks-in-parallel-grunt-concurrent&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://npmjs.org/package/grunt-concurrent&quot; rel=&quot;noopener&quot;&gt;grunt-concurrent&lt;/a&gt; is a plugin that becomes really useful when you have plenty of tasks that are independent from each other and consume a lot of time. It utilizes the number of CPUs in your device and executes multiple tasks in parallel.&lt;/p&gt;
&lt;p&gt;Best of all, its configuration is super simple. Assuming you use load-grunt-config, create the following new file:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;grunt/concurrent.js&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;concat&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;uglify&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;imagemin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;We just setup to parallel execution tracks with the names “&lt;strong&gt;first&lt;/strong&gt;” and “&lt;strong&gt;second&lt;/strong&gt;”. The &lt;strong&gt;concat&lt;/strong&gt; task needs to run first, and there’s nothing else to run in the meantime in our example. In our second track, we put both &lt;strong&gt;uglify&lt;/strong&gt; and &lt;strong&gt;imagemin&lt;/strong&gt;, since these two are independent from each other, and both take a considerable amount of time.&lt;/p&gt;
&lt;p&gt;This on its own does not do anything yet. We have to change our &lt;strong&gt;default&lt;/strong&gt; task alias to point to the concurrent jobs instead of the direct ones. Here’s the new content of &lt;strong&gt;grunt/aliases.yaml&lt;/strong&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;concurrent:first&#39;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;concurrent:second&#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you now rerun your grunt build, the concurrent plugin will run the concat task first, and then spawn two threads on two different CPU cores to run both imagemin and uglify in parallel. Yay!&lt;/p&gt;
&lt;p&gt;A word of advice though: Chances are that in our basic example, grunt-concurrent will not make your build significantly faster. The reason for this is the overhead created by spawning different instances of Grunt in different threads: In my case, at least +300ms pro spawn.&lt;/p&gt;
&lt;h3 id=&quot;how-much-time-did-it-take-time-grunt&quot;&gt;How much time did it take? time-grunt &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#how-much-time-did-it-take-time-grunt&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we’re optimizing every of our tasks, it would be really helpful to understand how much time every individual task required to execute. Fortunately, there’s a plugin for that as well: &lt;a href=&quot;https://npmjs.org/package/time-grunt&quot; rel=&quot;noopener&quot;&gt;time-grunt&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;time-grunt is not a classical grunt plugin that you load as npm task, but rather a plugin you include directly, similar to load-grunt-config. We’ll add a require for time-grunt to our Gruntfile, just like we did with load-grunt-config. Our Gruntfile should look like this now:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;grunt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// measures the time each task takes&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;time-grunt&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// load grunt config&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load-grunt-config&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;grunt&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And I’m sorry to disappoint, but that’s it – try rerunning Grunt from your Terminal and for every task (and additionally the total build), you should see a nicely formatted info panel on execution time:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Grunt time&quot; decoding=&quot;async&quot; height=&quot;115&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/x1jlIVoSZWnuYfAAUK9k.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;automatic-system-notifications&quot;&gt;Automatic system notifications &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#automatic-system-notifications&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you have a heavily optimized Grunt build that executes swiftly, and provided you auto-build it in some way (i.e. by watching files with grunt-contrib-watch, or after commits), wouldn’t it be great if your system could notify you when your fresh build is ready to consume, or when anything bad happened? Meet &lt;a href=&quot;https://npmjs.org/package/grunt-notify&quot; rel=&quot;noopener&quot;&gt;grunt-notify&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;By default, grunt-notify provides automatic notifications for all Grunt errors and warnings using whatever notification system available on your OS: Growl for OS X or Windows, Mountain Lion’s and Mavericks’ Notification Center, and Notify-send. Amazingly, all you need in order to get this functionality is to install &lt;a href=&quot;https://npmjs.org/package/grunt-notify&quot; rel=&quot;noopener&quot;&gt;the plugin&lt;/a&gt; from npm and load it in your Gruntfile (remember, if you’re using grunt-load-config above, this step is automated!).&lt;/p&gt;
&lt;p&gt;Here is how it will look like, depending on your operating system:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Notify&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 664px) 664px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/T4FyVKpzu4WKF1kBNvXepbi08t52/Ag7FPvabaJFAAST14nOy.png?auto=format&amp;w=1328 1328w&quot; width=&quot;664&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;In addition to errors and warnings, let’s configure it so it runs after our last task finished executing. Assuming you are using grunt-load-config to split up tasks across files, this is the file we’ll need:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;grunt/notify.js&lt;/strong&gt;&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;imagemin&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Build complete&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;token comment&quot;&gt;// optional&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;%= pkg.name %&gt; build finished successfully.&#39;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;//required&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In the first level of our config object, the key has to match the name of the task we want to connect it to. This example will cause the message to appear right after the &lt;strong&gt;imagemin&lt;/strong&gt; task has executed, which is the last one in our build chain.&lt;/p&gt;
&lt;h2 id=&quot;wrapping-it-all-up&quot;&gt;Wrapping it all up &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/supercharging-your-gruntfile/#wrapping-it-all-up&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you’ve followed from the top, you are now the proud owner of a build process that is super tidy and organized, is blazingly fast due to parallelization and selective processing and notifies you when anything goes wrong.&lt;/p&gt;
&lt;p&gt;If you discover another gem that improves Grunt and its plugins further, please do let us know! Until then, happy grunting!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update (2/14/2014): To grab a copy of the full, working example Grunt project, &lt;a href=&quot;https://github.com/html5rocks/www.html5rocks.com/tree/master/content/tutorials/tooling/supercharging-your-gruntfile/static/sample&quot; rel=&quot;noopener&quot;&gt;click here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</content>
    <author>
      <name>Paul Bakaus</name>
    </author>
  </entry>
</feed>
