<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Houssein Djirdeh on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Houssein Djirdeh</name>
  </author>
  <link href="https://web.dev/authors/houssein/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/BibySYHD7JweNcHZCCOe.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Houssein Djirdeh.</subtitle>
  
  
  <entry>
    <title>Publish, ship, and install modern JavaScript for faster applications</title>
    <link href="https://web.dev/publish-modern-javascript/"/>
    <updated>2020-12-10T00:00:00Z</updated>
    <id>https://web.dev/publish-modern-javascript/</id>
    <content type="html" mode="escaped">&lt;p&gt;Over 90% of browsers are capable of running modern JavaScript, but the
prevalence of legacy JavaScript remains a large source of performance problems
on the web today.&lt;/p&gt;
&lt;h2 id=&quot;modern-javascript&quot;&gt;Modern JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Modern JavaScript is not characterized as code written in a specific ECMAScript
specification version, but rather in syntax that is supported by all modern
browsers. Modern web browsers like Chrome, Edge, Firefox, and Safari make up
more than &lt;a href=&quot;https://www.caniuse.com/usage-table&quot; rel=&quot;noopener&quot;&gt;90% of the browser market&lt;/a&gt;, and
different browsers that rely on the same underlying rendering engines make up an
additional 5%. This means that 95% of global web traffic comes from browsers
that support the most widely used JavaScript language features from the past 10
years, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Classes (ES2015)&lt;/li&gt;
&lt;li&gt;Arrow functions (ES2015)&lt;/li&gt;
&lt;li&gt;Generators (ES2015)&lt;/li&gt;
&lt;li&gt;Block scoping (ES2015)&lt;/li&gt;
&lt;li&gt;Destructuring (ES2015)&lt;/li&gt;
&lt;li&gt;Rest and spread parameters (ES2015)&lt;/li&gt;
&lt;li&gt;Object shorthand (ES2015)&lt;/li&gt;
&lt;li&gt;Async/await (ES2017)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Features in newer versions of the language specification generally have less
consistent support across modern browsers. For example, many ES2020 and ES2021
features are only supported in 70% of the browser market—still the majority of
browsers, but not enough that it&#39;s safe to rely on those features directly. This
means that although &amp;quot;modern&amp;quot; JavaScript is a moving target, ES2017 has the
widest range of browser compatibility
&lt;a href=&quot;https://dev.to/garylchew/bringing-modern-javascript-to-libraries-432c&quot; rel=&quot;noopener&quot;&gt;while including most of the commonly used modern syntax features&lt;/a&gt;.
In other words, &lt;strong&gt;ES2017 is the closest to modern syntax today&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;legacy-javascript&quot;&gt;Legacy JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#legacy-javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Legacy JavaScript is code that specifically avoids using all the above language
features. Most developers write their source code using modern syntax, but
compile everything to legacy syntax for increased browser support. Compiling
to legacy syntax does increase browser support, however the effect is often
smaller than we realize. In many cases the support increases from around 95%
to 98% while incurring a significant cost:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Legacy JavaScript is typically around 20% larger and slower than
equivalent modern code. Tooling deficiencies and misconfiguration often
widen this gap even further.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Installed libraries account for as much as 90% of typical production
JavaScript code. Library code incurs an even higher legacy JavaScript
overhead due to polyfill and helper duplication that could be avoided
by publishing modern code.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;modern-javascript-on-npm&quot;&gt;Modern JavaScript on npm &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-javascript-on-npm&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Recently, Node.js has standardized an &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field to define
&lt;a href=&quot;https://nodejs.org/api/packages.html#packages_package_entry_points&quot; rel=&quot;noopener&quot;&gt;entry points for a package&lt;/a&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./index.js&quot;&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;Modules referenced by the &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field imply a Node version of at least
12.8, which supports ES2019. This means that any module referenced using the
&lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field can be &lt;em&gt;written in modern JavaScript&lt;/em&gt;. Package consumers must
assume modules with an &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field contain modern code and transpile if
necessary.&lt;/p&gt;
&lt;h3 id=&quot;modern-only&quot;&gt;Modern-only &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-only&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you want to publish a package with modern code and leave it up to the
consumer to handle transpiling it when they use it as a dependency—use only the
&lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./modern.js&quot;&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;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; This approach is &lt;em&gt;not recommended&lt;/em&gt;. In a perfect world, every developer would have already configured their build system to transpile all dependencies (&lt;code&gt;node_modules&lt;/code&gt;) to their required syntax. However, this is not currently the case, and publishing your package using only modern syntax would prevent its usage in applications that would be accessed through legacy browsers. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;modern-with-legacy-fallback&quot;&gt;Modern with legacy fallback &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-with-legacy-fallback&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field along with &lt;code&gt;&amp;quot;main&amp;quot;&lt;/code&gt; in order to publish your package
using modern code but also include an ES5 + CommonJS fallback for legacy
browsers.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./modern.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./legacy.cjs&quot;&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;h3 id=&quot;modern-with-legacy-fallback-and-esm-bundler-optimizations&quot;&gt;Modern with legacy fallback and ESM bundler optimizations &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-with-legacy-fallback-and-esm-bundler-optimizations&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In addition to defining a fallback CommonJS entrypoint, the &lt;code&gt;&amp;quot;module&amp;quot;&lt;/code&gt; field can
be used to point to a similar legacy fallback bundle, but one that uses
JavaScript module syntax (&lt;code&gt;import&lt;/code&gt; and &lt;code&gt;export&lt;/code&gt;).&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;exports&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./modern.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;main&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./legacy.cjs&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./module.js&quot;&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;Many bundlers, such as webpack and Rollup, rely on this field to take advantage
of module features and enable
&lt;a href=&quot;https://web.dev/commonjs-larger-bundles/#how-does-commonjs-affect-your-final-bundle-size&quot;&gt;tree shaking&lt;/a&gt;.
This is still a legacy bundle that does not contain any modern code aside from
&lt;code&gt;import&lt;/code&gt;/&lt;code&gt;export&lt;/code&gt; syntax, so use this approach to ship modern code with a
legacy fallback that is still optimized for bundling.&lt;/p&gt;
&lt;h2 id=&quot;modern-javascript-in-applications&quot;&gt;Modern JavaScript in applications &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#modern-javascript-in-applications&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Third-party dependencies make up the vast majority of typical production
JavaScript code in web applications. While npm dependencies have historically
been published as legacy ES5 syntax, this is no longer a safe assumption and
risks dependency updates breaking browser support in your application.&lt;/p&gt;
&lt;p&gt;With an increasing number of npm packages moving to modern JavaScript, it&#39;s
important to ensure that the build tooling is set up to handle them. There&#39;s a
good chance some of the npm packages you depend on are already using modern
language features. There are a number of options available to use modern code
from npm without breaking your application in older browsers, but the general
idea is to have the build system transpile dependencies to the same syntax
target as your source code.&lt;/p&gt;
&lt;h2 id=&quot;webpack&quot;&gt;webpack &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#webpack&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of webpack 5, it is now possible to configure what syntax webpack will use
when generating code for bundles and modules. This doesn&#39;t transpile your
code or dependencies, it only affects the &amp;quot;glue&amp;quot; code generated by webpack.
To specify the browser support target, add a
&lt;a href=&quot;https://github.com/browserslist/browserslist#readme&quot; rel=&quot;noopener&quot;&gt;browserslist configuration&lt;/a&gt;
to your project, or do it directly in your webpack configuration:&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;target&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;web&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;es2017&#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 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;It is also possible to configure webpack to generate optimized bundles that
omit unnecessary wrapper functions when targeting a modern ES Modules
environment. This also configures webpack to load code-split bundles using
&lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&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;target&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;web&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;es2017&#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;output&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;module&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 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;experiments&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;outputModule&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 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;There are a number of webpack plugins available that make it possible to
compile and ship modern JavaScript while still supporting legacy browsers,
such as Optimize Plugin and BabelEsmPlugin.&lt;/p&gt;
&lt;h3 id=&quot;optimize-plugin&quot;&gt;Optimize Plugin &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#optimize-plugin&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/developit/optimize-plugin&quot; rel=&quot;noopener&quot;&gt;Optimize Plugin&lt;/a&gt; is a webpack
plugin that transforms final bundled code from modern to legacy JavaScript
instead of each individual source file. It&#39;s a self-contained setup that allows
your webpack configuration to assume everything is modern JavaScript with no
special branching for multiple outputs or syntaxes.&lt;/p&gt;
&lt;p&gt;Since Optimize Plugin operates on bundles instead of individual modules, it
processes your application&#39;s code and your dependencies equally. This makes it
safe to use modern JavaScript dependencies from npm, because their code will be
bundled and transpiled to the correct syntax. It can also be faster than
traditional solutions involving two compilation steps, while still generating
separate bundles for modern and legacy browsers. The two sets of bundles are
designed to be loaded using the
&lt;a href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/&quot;&gt;module/nomodule pattern&lt;/a&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 comment&quot;&gt;// webpack.config.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; OptimizePlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;optimize-plugin&#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;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 comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;OptimizePlugin&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;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;code&gt;Optimize Plugin&lt;/code&gt; can be faster and more efficient than custom webpack
configurations, which typically bundle modern and legacy code separately. It
also handles running &lt;a href=&quot;https://babeljs.io/&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; for you, and minifies
bundles using &lt;a href=&quot;https://terser.org/&quot; rel=&quot;noopener&quot;&gt;Terser&lt;/a&gt; with separate optimal settings for
the modern and legacy outputs. Finally, polyfills needed by the generated
legacy bundles are extracted into a dedicated script so they are never
duplicated or unnecessarily loaded in newer browsers.&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/fast-publish-modern-javascript/transpile-before-after.webm&quot; type=&quot;video/webm&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/fast-publish-modern-javascript/transpile-before-after.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
  &lt;figcaption&gt;
    Comparison: transpiling source modules twice versus transpiling generated bundles.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h3 id=&quot;babelesmplugin&quot;&gt;BabelEsmPlugin &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#babelesmplugin&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/prateekbh/babel-esm-plugin&quot; rel=&quot;noopener&quot;&gt;BabelEsmPlugin&lt;/a&gt; is a webpack
plugin that works along with
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;@babel/preset-env&lt;/a&gt;
to generate modern versions of existing bundles to ship less transpiled code to
modern browsers. It is the most popular off-the-shelf solution for
module/nomodule, used by &lt;a href=&quot;https://nextjs.org/&quot; rel=&quot;noopener&quot;&gt;Next.js&lt;/a&gt; and
&lt;a href=&quot;https://preactjs.com/cli/&quot; rel=&quot;noopener&quot;&gt;Preact CLI&lt;/a&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 comment&quot;&gt;// webpack.config.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; BabelEsmPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;babel-esm-plugin&#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;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 comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;module&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;rules&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 comment&quot;&gt;// your existing babel-loader configuration:&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 literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;js&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;exclude&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;use&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;loader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;babel-loader&#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;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;presets&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;@babel/preset-env&#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 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;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;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;plugins&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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BabelEsmPlugin&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;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;code&gt;BabelEsmPlugin&lt;/code&gt; supports a wide array of webpack configurations, because it
runs two largely separate builds of your application. Compiling twice can take a
little bit of extra time for large applications, however this technique allows
&lt;code&gt;BabelEsmPlugin&lt;/code&gt; to integrate seamlessly into existing webpack configurations
and makes it one of the most convenient options available.&lt;/p&gt;
&lt;h3 id=&quot;configure-babel-loader-to-transpile-nodemodules&quot;&gt;Configure babel-loader to transpile node_modules &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#configure-babel-loader-to-transpile-nodemodules&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are using &lt;code&gt;babel-loader&lt;/code&gt; without one of the previous two plugins,
there&#39;s an important step required in order to consume modern JavaScript npm
modules. Defining two separate &lt;code&gt;babel-loader&lt;/code&gt; configurations makes it possible
to automatically compile modern language features found in &lt;code&gt;node_modules&lt;/code&gt; to
ES2017, while still transpiling your own first-party code with the Babel
plugins and presets defined in your project&#39;s configuration. This doesn&#39;t
generate modern and legacy bundles for a module/nomodule setup, but it does
make it possible to install and use npm packages that contain modern JavaScript
without breaking older browsers.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/webpack-plugin-modern-npm&quot; rel=&quot;noopener&quot;&gt;webpack-plugin-modern-npm&lt;/a&gt;
uses this technique to compile npm dependencies that have an &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field
in their &lt;code&gt;package.json&lt;/code&gt;, since these may contain modern syntax:&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;// webpack.config.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ModernNpmPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;webpack-plugin-modern-npm&#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;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;plugins&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 comment&quot;&gt;// auto-transpile modern stuff found in node_modules&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ModernNpmPlugin&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;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;Alternatively, you can implement the technique manually in your webpack
configuration by checking for an &lt;code&gt;&amp;quot;exports&amp;quot;&lt;/code&gt; field in the &lt;code&gt;package.json&lt;/code&gt; of
modules as they are resolved. Omitting caching for brevity, a custom
implementation might 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 comment&quot;&gt;// webpack.config.js&lt;/span&gt;&lt;br /&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;module&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;rules&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 comment&quot;&gt;// Transpile for your own first-party code:&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 literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;js&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&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;loader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;babel-loader&#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;exclude&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// Transpile modern dependencies:&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 literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;js&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-flags&quot;&gt;i&lt;/span&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;include&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;file&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 keyword&quot;&gt;let&lt;/span&gt; dir &lt;span class=&quot;token operator&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;match&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token anchor function&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;token char-set class-name&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token quantifier number&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;/&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;node_modules&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;/&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token group punctuation&quot;&gt;(&lt;/span&gt;@&lt;span class=&quot;token char-set class-name&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token quantifier number&quot;&gt;*?&lt;/span&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;/&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token group punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token quantifier number&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token char-set class-name&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token quantifier number&quot;&gt;*?&lt;/span&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;/&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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 keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; dir &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dir&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&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;exports&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 keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&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;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;use&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;loader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;babel-loader&#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;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;babelrc&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;configFile&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token literal-property property&quot;&gt;presets&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;@babel/preset-env&#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 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;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;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 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;When using this approach, you&#39;ll need to ensure modern syntax is supported by
your minifier. Both &lt;a href=&quot;https://github.com/terser/terser#minify-options&quot; rel=&quot;noopener&quot;&gt;Terser&lt;/a&gt;
and &lt;a href=&quot;https://github.com/mishoo/UglifyJS/tree/harmony#minify-options&quot; rel=&quot;noopener&quot;&gt;uglify-es&lt;/a&gt;
have an option to specify &lt;code&gt;{ecma: 2017}&lt;/code&gt; in order to preserve and in some cases
generate ES2017 syntax during compression and formatting.&lt;/p&gt;
&lt;h2 id=&quot;rollup&quot;&gt;Rollup &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#rollup&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rollup has built-in support for generating multiple sets of bundles as part of
a single build, and generates modern code by default. As a result, Rollup can
be configured to generate modern and legacy bundles with the official plugins
you&#39;re likely already using.&lt;/p&gt;
&lt;h3 id=&quot;rollupplugin-babel&quot;&gt;@rollup/plugin-babel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#rollupplugin-babel&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you use Rollup, the
&lt;a href=&quot;https://github.com/rollup/plugins/tree/master/packages/babel#running-babel-on-the-generated-code&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;getBabelOutputPlugin()&lt;/code&gt; method&lt;/a&gt;
(provided by Rollup&#39;s
&lt;a href=&quot;https://github.com/rollup/plugins/tree/master/packages/babel&quot; rel=&quot;noopener&quot;&gt;official Babel plugin&lt;/a&gt;)
transforms the code in generated bundles rather than individual source modules.
Rollup has built-in support for generating multiple sets of bundles as part of
a single build, each with their own plugins. You can use this to produce
different bundles for modern and legacy by passing each through a different
Babel output plugin configuration:&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;// rollup.config.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;getBabelOutputPlugin&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@rollup/plugin-babel&#39;&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 keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&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;input&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;src/index.js&#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;output&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 comment&quot;&gt;// modern bundles:&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 literal-property property&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;es&#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;plugins&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 function&quot;&gt;getBabelOutputPlugin&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;presets&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;              &lt;span class=&quot;token string&quot;&gt;&#39;@babel/preset-env&#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 literal-property property&quot;&gt;targets&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 literal-property property&quot;&gt;esmodules&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token literal-property property&quot;&gt;bugfixes&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;loose&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 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;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;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;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 comment&quot;&gt;// legacy (ES5) bundles:&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 literal-property property&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;amd&#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;entryFileNames&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;[name].legacy.js&#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;chunkFileNames&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;[name]-[hash].legacy.js&#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;plugins&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 function&quot;&gt;getBabelOutputPlugin&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;presets&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;@babel/preset-env&#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 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;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;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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;additional-build-tools&quot;&gt;Additional build tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/publish-modern-javascript/#additional-build-tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Rollup and webpack are highly-configurable, which generally means each project
must update its configuration enable modern JavaScript syntax in dependencies.
There are also higher-level build tools that favor convention and defaults over
configuration, like &lt;a href=&quot;https://parceljs.org/&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt;, &lt;a href=&quot;https://www.snowpack.dev/&quot; rel=&quot;noopener&quot;&gt;Snowpack&lt;/a&gt;, &lt;a href=&quot;https://github.com/vitejs/vite&quot; rel=&quot;noopener&quot;&gt;Vite&lt;/a&gt; and &lt;a href=&quot;https://github.com/preactjs/wmr&quot; rel=&quot;noopener&quot;&gt;WMR&lt;/a&gt;. Most of these tools
assume npm dependencies may contain modern syntax, and will transpile them to
the appropriate syntax level(s) when building for production.&lt;/p&gt;
&lt;p&gt;In addition to dedicated plugins for webpack and Rollup, modern JavaScript
bundles with legacy fallbacks can be added to any project using
&lt;a href=&quot;https://github.com/theKashey/devolution&quot; rel=&quot;noopener&quot;&gt;devolution&lt;/a&gt;. Devolution is a
standalone tool that transforms the output from a build system to produce legacy
JavaScript variants, allowing bundling and transformations to assume a modern
output target.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Jason Miller</name>
    </author>
  </entry>
  
  <entry>
    <title>Optimize First Input Delay</title>
    <link href="https://web.dev/optimize-fid/"/>
    <updated>2020-05-05T00:00:00Z</updated>
    <id>https://web.dev/optimize-fid/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; FID will be &lt;a href=&quot;https://web.dev/inp-cwv/&quot;&gt;replaced by Interaction to Next Paint (INP)&lt;/a&gt; as a Core Web Vital in March 2024. &lt;/div&gt;&lt;/aside&gt;
&lt;blockquote&gt;
  &lt;p&gt;
    I clicked but nothing happened! Why can&#39;t I interact with this page? 😢
  &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt; (FCP) and &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful
Paint&lt;/a&gt; (LCP) are both metrics that measure the time it takes for content to
visually render (paint) on a page. Although important, paint times do not capture &lt;em&gt;load
responsiveness&lt;/em&gt;: or how quickly a page responds to user interaction.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay&lt;/a&gt; (FID) is a &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt; metric that captures a user&#39;s
first impression of a site&#39;s interactivity and responsiveness. It measures the time from when a user
first interacts with a page to the time when the browser is actually able to respond to that
interaction. FID is a &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#in-the-field&quot;&gt;field metric&lt;/a&gt; and cannot be
simulated in a lab environment. &lt;strong&gt;A real user interaction&lt;/strong&gt; is required in order to measure the
response delay.&lt;/p&gt;
&lt;picture&gt;
  &lt;source srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/eXyvkqRHQZ5iG38Axh1Z.svg&quot; media=&quot;(min-width: 640px)&quot; /&gt;
  &lt;img alt=&quot;Good fid values are 2.5 seconds, poor values are greater than 4.0 seconds and anything in between needs improvement&quot; decoding=&quot;async&quot; height=&quot;96&quot; loading=&quot;lazy&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/Se4TiXIdp8jtLJVScWed.svg&quot; width=&quot;384&quot; /&gt;
&lt;/picture&gt;
&lt;p&gt;To help predict FID in the &lt;a href=&quot;https://web.dev/how-to-measure-speed/#lab-data-vs-field-data&quot;&gt;lab&lt;/a&gt;, we
recommend &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking Time (TBT)&lt;/a&gt;. They measure different things, but
improvements in TBT usually correspond to improvements in FID.&lt;/p&gt;
&lt;p&gt;The main cause of a poor FID is &lt;strong&gt;heavy JavaScript execution&lt;/strong&gt;. Optimizing how JavaScript parses,
compiles, and executes on your web page will directly reduce FID.&lt;/p&gt;
&lt;h2 id=&quot;heavy-javascript-execution&quot;&gt;Heavy JavaScript execution &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#heavy-javascript-execution&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The browser cannot respond to most user input while it&#39;s executing JavaScript on the main thread. In other words, the
browser can&#39;t respond to user interactions while the main thread is busy. To improve this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#long-tasks&quot;&gt;Break up Long Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#optimize-interaction-readiness&quot;&gt;Optimize your page for interaction readiness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#use-a-web-worker&quot;&gt;Use a web worker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/optimize-fid/#reduce-javascript-execution&quot;&gt;Reduce JavaScript execution time&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;long-tasks&quot;&gt;Break up Long Tasks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#long-tasks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;ve already attempted to reduce the amount of JavaScript that loads on a single page, it can
be useful to break down long-running code into &lt;strong&gt;smaller, asynchronous tasks&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/custom-metrics/#long-tasks-api&quot;&gt;&lt;strong&gt;Long Tasks&lt;/strong&gt;&lt;/a&gt; are JavaScript execution periods where users may
find your UI unresponsive. Any piece of code that blocks the main thread for 50 ms or more can be
characterized as a Long Task. Long Tasks are a sign of
potential JavaScript bloat (loading and executing more than a user may need right now).
Splitting up long tasks can reduce input delay on your site.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Long Tasks in Chrome DevTools&quot; decoding=&quot;async&quot; height=&quot;132&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/THLKu0sOPhSghNr0XkP1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Chrome DevTools &lt;a href=&quot;https://developers.google.com/web/updates/2020/03/devtools#long-tasks&quot;&gt;visualizes Long Tasks&lt;/a&gt; in the Performance Panel&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;FID should improve noticeably as you adopt best practices like code-splitting and breaking up your
Long Tasks. While TBT is not a field metric, it&#39;s useful for checking progress towards ultimately
improving both Time To Interactive (TTI) and FID.&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; For more information, take a look at &lt;a href=&quot;https://web.dev/long-tasks-devtools/&quot;&gt;Are long JavaScript tasks delaying your Time to Interactive?&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;optimize-your-page-for-interaction-readiness&quot;&gt;Optimize your page for interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#optimize-your-page-for-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a number of common causes for poor FID and TBT scores in web apps that rely heavily on
JavaScript:&lt;/p&gt;
&lt;h3 id=&quot;first-party-script-execution-can-delay-interaction-readiness&quot;&gt;First-party script execution can delay interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#first-party-script-execution-can-delay-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;JavaScript size bloat, heavy execution times and inefficient chunking can slow down how soon a
page can respond to user input and impact FID, TBT, and TTI. Progressive loading of code and
features can help spread this work out and improve interaction readiness.&lt;/li&gt;
&lt;li&gt;Server-side rendered apps may look like they&#39;re getting pixels painted on the screen
quickly, but beware of user interactions being blocked by large script executions (e.g.
re-hydration to wire up event listeners). This can take several hundred milliseconds, sometimes
even seconds, if route-based code splitting is being used. Consider shifting more logic
server-side or generating more content statically during build time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below are the TBT scores before and after optimizing first-party script loading for an
application. By moving costly script loading (and execution) for a non-essential component off the
critical path, users were able to interact with the page much sooner.&lt;/p&gt;
&lt;img alt=&quot;Improvements in TBT score in Lighthouse after optimizing the first-party script.&quot; decoding=&quot;async&quot; height=&quot;148&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/TEIbBnIAyfzIoQtvXvMk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;data-fetching-can-impact-many-aspects-of-interaction-readiness&quot;&gt;Data-fetching can impact many aspects of interaction readiness &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#data-fetching-can-impact-many-aspects-of-interaction-readiness&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Waiting on a waterfall of cascading fetches (e.g. JavaScript and data fetches for components) can
impact interaction latency. Aim to minimize a reliance on cascading data fetches.&lt;/li&gt;
&lt;li&gt;Large inline datastores can push out HTML parsing time and impact both paint and interaction
metrics. Aim to minimize how much data needs to be post-processed on the client-side.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;third-party-script-execution-can-delay-interaction-latency-too&quot;&gt;Third-party script execution can delay interaction latency too &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#third-party-script-execution-can-delay-interaction-latency-too&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Many sites include third-party tags and analytics which can keep the network busy and
make the main thread periodically unresponsive, impacting interaction latency. Explore
on-demand loading of third-party code (e.g. maybe don&#39;t load those below-the-fold ads until
they&#39;re scrolled closer to the viewport).&lt;/li&gt;
&lt;li&gt;In some cases, third-party scripts can pre-empt first-party ones in terms of priority and
bandwidth on the main thread, also delaying how soon a page is interaction-ready. Attempt to
prioritize loading what you believe offers the greatest value to users first.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-a-web-worker&quot;&gt;Use a web worker &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#use-a-web-worker&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A blocked main thread is one of the main causes of input delay. &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Worker&quot; rel=&quot;noopener&quot;&gt;Web
workers&lt;/a&gt; make it possible to run JavaScript
on a background thread. Moving non-UI operations to a separate worker thread can cut down main
thread blocking time and consequently improve FID.&lt;/p&gt;
&lt;p&gt;Consider using the following libraries to make it easier to use web workers on your site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/GoogleChromeLabs/comlink&quot; rel=&quot;noopener&quot;&gt;Comlink&lt;/a&gt;: A helper library that abstracts
&lt;code&gt;postMessage&lt;/code&gt; and makes it easier to use&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/WebReflection/workway&quot; rel=&quot;noopener&quot;&gt;Workway&lt;/a&gt;: A general purpose web worker exporter&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/developit/workerize&quot; rel=&quot;noopener&quot;&gt;Workerize&lt;/a&gt;: Move a module into a web worker&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; To learn more about how web workers can execute code off the main thread, refer to &lt;a href=&quot;https://web.dev/off-main-thread/&quot;&gt;Use Web Workers to run JavaScript off the browser&#39;s main thread&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;reduce-javascript-execution&quot;&gt;Reduce JavaScript execution time &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#reduce-javascript-execution&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Limiting the amount of JavaScript on your page reduces the amount of time that the browser needs to
spend executing JavaScript code. This speeds up how fast the browser can begin to respond to any
user interactions.&lt;/p&gt;
&lt;p&gt;To reduce the amount of JavaScript executed on your page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Defer unused JavaScript&lt;/li&gt;
&lt;li&gt;Minimize unused polyfills&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;defer-unused-javascript&quot;&gt;Defer unused JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#defer-unused-javascript&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;By default all JavaScript is render-blocking. When the browser encounters a script tag that links to
an external JavaScript file, it must pause what it&#39;s doing and download, parse, compile, and execute
that JavaScript. Therefore you should only load the code that&#39;s needed for the page or
responding to user input.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/coverage/&quot; rel=&quot;noopener&quot;&gt;Coverage&lt;/a&gt; tab in Chrome
DevTools can tell you how much JavaScript is not being used on your web page.&lt;/p&gt;
&lt;img alt=&quot;The Coverage tab.&quot; decoding=&quot;async&quot; height=&quot;559&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/UNEigFiwsGu48rtXMZM4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To cut down on unused JavaScript:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Code-split your bundle into multiple chunks&lt;/li&gt;
&lt;li&gt;Defer any non-critical JavaScript, including third-party scripts, using &lt;code&gt;async&lt;/code&gt; or &lt;code&gt;defer&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Code-splitting&lt;/strong&gt; is the concept of splitting a single large JavaScript bundle into smaller chunks
that can be conditionally loaded (also known as lazy loading).
&lt;a href=&quot;https://caniuse.com/#feat=es6-module-dynamic-import&quot; rel=&quot;noopener&quot;&gt;Most newer browsers support dynamic import syntax&lt;/a&gt;,
which allows for module fetching on demand:&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;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;module.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;span class=&quot;token function&quot;&gt;then&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 parameter&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Do something with the module.&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Dynamically importing JavaScript on certain user interactions (such as changing a route or
displaying a modal) will make sure that code not used for the initial page load is only fetched when
needed.&lt;/p&gt;
&lt;p&gt;Aside from general browser support, dynamic import syntax can be used in many different build
systems.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you use &lt;a href=&quot;https://webpack.js.org/guides/code-splitting/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;,
&lt;a href=&quot;https://medium.com/rollup/rollup-now-has-code-splitting-and-we-need-your-help-46defd901c82&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt;,
or &lt;a href=&quot;https://parceljs.org/code_splitting.html&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt; as a module bundler, take advantage of
their dynamic import support.&lt;/li&gt;
&lt;li&gt;Client-side frameworks, like
&lt;a href=&quot;https://reactjs.org/docs/code-splitting.html#reactlazy&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;,
&lt;a href=&quot;https://angular.io/guide/lazy-loading-ngmodules&quot; rel=&quot;noopener&quot;&gt;Angular&lt;/a&gt;, and
&lt;a href=&quot;https://vuejs.org/v2/guide/components-dynamic-async.html#Async-Components&quot; rel=&quot;noopener&quot;&gt;Vue&lt;/a&gt; provide
abstractions to make it easier to lazy-load at the component-level.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Take a look at &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;Reduce JavaScript payloads with code splitting&lt;/a&gt; to learn more about code-splitting. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Aside from code-splitting, always use &lt;a href=&quot;https://javascript.info/script-async-defer&quot; rel=&quot;noopener&quot;&gt;async or
defer&lt;/a&gt; for scripts that are not necessary for
critical-path or above-the-fold content.&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;…&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;…&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;Unless there is a specific reason not to, all third-party scripts should be loaded with either &lt;code&gt;defer&lt;/code&gt;
or &lt;code&gt;async&lt;/code&gt; by default.&lt;/p&gt;
&lt;h4 id=&quot;minimize-unused-polyfills&quot;&gt;Minimize unused polyfills &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#minimize-unused-polyfills&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;If you author your code using modern JavaScript syntax and reference modern browsers APIs, you will
need to transpile it and include polyfills in order for it to work in older browsers.&lt;/p&gt;
&lt;p&gt;One of the main performance concerns of including polyfills and transpiled code in your site is that
newer browsers shouldn&#39;t have to download it if they do not need it. To cut down on the JavaScript
size of your application, minimize unused polyfills as much as possible and restrict their usage to
environments where they&#39;re needed.&lt;/p&gt;
&lt;p&gt;To optimize polyfill usage on your site:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;If you use &lt;a href=&quot;https://babeljs.io/docs/en/index.html&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; as a transpiler, use
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt;&lt;/a&gt; to only include the polyfills
needed for the browsers you plan on targeting. For Babel 7.9, enable the
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#bugfixes&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;bugfixes&lt;/code&gt;&lt;/a&gt; option to further cut down
on any unneeded polyfills&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use the module/nomodule pattern to deliver two separate bundles (&lt;code&gt;@babel/preset-env&lt;/code&gt; also
supports this via &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#targetsesmodules&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;target.esmodules&lt;/code&gt;&lt;/a&gt;)&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;modern.js&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;legacy.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;Many newer ECMAScript features compiled with Babel are already supported in environments
that support JavaScript modules. So by doing this, you simplify the process of making sure that
only transpiled code is used for browsers that actually need it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;a href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/&quot;&gt;Serve modern code to modern browsers for faster page loads&lt;/a&gt; guide goes into more detail about this topic. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;developer-tools&quot;&gt;Developer tools &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/optimize-fid/#developer-tools&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A number of tools are available to measure and debug FID:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/overview/&quot; rel=&quot;noopener&quot;&gt;Lighthouse 6.0&lt;/a&gt; does not include
support for FID since it is a field metric. However, &lt;a href=&quot;https://web.dev/tbt/&quot;&gt;Total Blocking
Time&lt;/a&gt; (TBT) can be used as a proxy. Optimizations that improve TBT should
also improve FID in the field.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse 6.0.&quot; decoding=&quot;async&quot; height=&quot;309&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/FRM9kHWmsDv9dddGMgwu.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/crux/&quot; rel=&quot;noopener&quot;&gt;Chrome User Experience Report&lt;/a&gt;
provides real-world FID values aggregated at the origin-level&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;With thanks to Philip Walton, Kayce Basques, Ilya Grigorik, and Annie Sullivan for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Addy Osmani</name>
    </author>
  </entry>
  
  <entry>
    <title>Improved Next.js and Gatsby page load performance with granular chunking</title>
    <link href="https://web.dev/granular-chunking-nextjs/"/>
    <updated>2020-04-29T00:00:00Z</updated>
    <id>https://web.dev/granular-chunking-nextjs/</id>
    <content type="html" mode="escaped">&lt;p&gt;Chrome is &lt;a href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/&quot;&gt;collaborating&lt;/a&gt; with tooling and
frameworks in the JavaScript open-source ecosystem. A number of newer optimizations were recently
added to improve the loading performance of &lt;a href=&quot;https://nextjs.org/&quot; rel=&quot;noopener&quot;&gt;Next.js&lt;/a&gt; and
&lt;a href=&quot;https://www.gatsbyjs.org/&quot; rel=&quot;noopener&quot;&gt;Gatsby&lt;/a&gt;. This article covers an improved granular chunking strategy
that is now shipped by default in both frameworks.&lt;/p&gt;
&lt;h2 id=&quot;introduction&quot;&gt;Introduction &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#introduction&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Like many web frameworks, Next.js and Gatsby use &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; as their core
bundler. webpack v3 introduced
&lt;a href=&quot;https://webpack.js.org/plugins/commons-chunk-plugin/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;CommonsChunkPlugin&lt;/code&gt;&lt;/a&gt; to make it possible to
output modules shared between different entry points in a single (or few) &amp;quot;commons&amp;quot; chunk (or
chunks). Shared code can be downloaded separately and stored in the browser cache early on which can
result in a better loading performance.&lt;/p&gt;
&lt;p&gt;This pattern became popular with many single-page application frameworks adopting an entrypoint and
bundle configuration that looked like this:&lt;/p&gt;
&lt;img alt=&quot;Common entrypoint and bundle configuration&quot; decoding=&quot;async&quot; height=&quot;569&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/r4QB67AXzmPMgxcxgbQF.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Although practical, the concept of bundling all shared module code into a single chunk has its
limitations. Modules not shared in every entry point can be downloaded for routes that do not use it
resulting in more code being downloaded than necessary. For example, when &lt;code&gt;page1&lt;/code&gt; loads
the &lt;code&gt;common&lt;/code&gt; chunk, it loads the code for &lt;code&gt;moduleC&lt;/code&gt; even though &lt;code&gt;page1&lt;/code&gt; doesn&#39;t use &lt;code&gt;moduleC&lt;/code&gt;.
For this reason, along with a few others, webpack v4 removed the plugin in favor of a new
one: &lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;SplitChunksPlugin&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;improved-chunking&quot;&gt;Improved Chunking &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#improved-chunking&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The default settings for &lt;code&gt;SplitChunksPlugin&lt;/code&gt;  works well for most users. Multiple split chunks are
created depending on a number of &lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/#defaults&quot; rel=&quot;noopener&quot;&gt;conditions&lt;/a&gt;
to prevent fetching duplicated code across multiple routes.&lt;/p&gt;
&lt;p&gt;However, many web frameworks that use this plugin still follow a &amp;quot;single-commons&amp;quot; approach to chunk
splitting. Next.js, for example, would generate a &lt;code&gt;commons&lt;/code&gt; bundle that contained any module that is
used in more than 50% of pages and all framework dependencies (&lt;code&gt;react&lt;/code&gt;, &lt;code&gt;react-dom&lt;/code&gt;, and so on).&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; splitChunksConfigs &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  …&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;prod&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;all&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;cacheGroups&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;vendors&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;commons&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;commons&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;all&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;minChunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; totalPages &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; totalPages &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;react&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;commons&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;all&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;node_modules&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token group punctuation&quot;&gt;(&lt;/span&gt;react&lt;span class=&quot;token alternation keyword&quot;&gt;|&lt;/span&gt;react-dom&lt;span class=&quot;token alternation keyword&quot;&gt;|&lt;/span&gt;scheduler&lt;span class=&quot;token alternation keyword&quot;&gt;|&lt;/span&gt;use-subscription&lt;span class=&quot;token group punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Although including framework-dependent code into a shared chunk means that it can be downloaded and
cached for any entrypoint, the usage-based heuristic of including common modules used in more than
&lt;em&gt;half of pages&lt;/em&gt; isn&#39;t very effective. Modifying this ratio would only result in one of two outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you reduce the ratio, more unnecessary code gets downloaded.&lt;/li&gt;
&lt;li&gt;If you increase the ratio, more code gets duplicated across multiple routes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve this problem, Next.js adopted a &lt;a href=&quot;https://github.com/zeit/next.js/pull/7696&quot; rel=&quot;noopener&quot;&gt;different
configuration&lt;/a&gt; for&lt;code&gt;SplitChunksPlugin&lt;/code&gt; that reduces
unnecessary code for any route.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any sufficiently large third-party module (greater than 160 KB) is split into its own individual
chunk&lt;/li&gt;
&lt;li&gt;A separate &lt;code&gt;frameworks&lt;/code&gt; chunk is created for framework dependencies (&lt;code&gt;react&lt;/code&gt;, &lt;code&gt;react-dom&lt;/code&gt;, and
so on)&lt;/li&gt;
&lt;li&gt;As many shared chunks as needed are created (up to 25)&lt;/li&gt;
&lt;li&gt;The minimum size for a chunk to be generated is changed to 20 KB&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This granular chunking strategy provides the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Page load times are improved&lt;/strong&gt;. Emitting multiple shared chunks, instead of a single one,
minimizes the amount of unneeded (or duplicate) code for any entrypoint.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Improved caching during navigations&lt;/strong&gt;. Splitting large libraries and framework dependencies
into separate chunks reduces the possibility of cache invalidation since both are unlikely to
change until an upgrade is made.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can see the entire configuration that Next.js adopted in &lt;a href=&quot;https://github.com/vercel/next.js/blob/e125d905a0dd93d247c6122d349c2c90268f0713/packages/next/build/webpack-config.ts#L352-L429&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;webpack-config.ts&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;more-http-requests&quot;&gt;More HTTP requests &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#more-http-requests&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;SplitChunksPlugin&lt;/code&gt; defined the basis for granular chunking, and applying this approach to a
framework like Next.js was not an entirely new concept. Many frameworks, however, still continued to
use a single heuristic and &amp;quot;commons&amp;quot; bundle strategy for a few reasons. This includes the concern that
many more HTTP requests can negatively affect site performance.&lt;/p&gt;
&lt;p&gt;Browsers can only open a limited number of TCP connections to a single origin (6 for Chrome), so
minimizing the number of chunks outputted by a bundler can ensure that the total number of requests
stays under this threshold. However, this only holds true for HTTP/1.1. Multiplexing in HTTP/2
allows for multiple requests to be streamed in parallel using a single connection over a single
origin. In other words, we generally do not need to worry about limiting the number of chunks
emitted by our bundler.&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; It is important to note that different browsers take &lt;a href=&quot;https://calendar.perfplanet.com/2018/http2-prioritization/&quot;&gt;different approaches&lt;/a&gt; to prioritize specific resources when many are requested over the same TCP connection. Some servers and CDNs also handle prioritization differently (see &lt;a href=&quot;https://github.com/andydavies/http2-prioritization-issues#cdns--cloud-hosting-services&quot;&gt;&amp;quot;Tracking HTTP/2 Prioritization Issues&amp;quot;&lt;/a&gt;). &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://caniuse.com/#feat=http2&quot; rel=&quot;noopener&quot;&gt;All major browsers&lt;/a&gt; support HTTP/2. The Chrome and Next.js teams
wanted to see if increasing the number of requests by splitting Next.js&#39;s single &amp;quot;commons&amp;quot; bundle
into multiple shared chunks would affect loading performance in any way. They began by measuring the
performance of a single site while modifying the maximum number of parallel requests using the
&lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/#splitchunksmaxinitialrequests&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;maxInitialRequests&lt;/code&gt;&lt;/a&gt;
property.&lt;/p&gt;
&lt;img alt=&quot;Page load performance with increased number of requests&quot; decoding=&quot;async&quot; height=&quot;495&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Psq42HGvyk1hiaCdEJxc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In an average of three runs of multiple trials on a single web page, the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Window/load_event&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;load&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://github.com/WPO-Foundation/webpagetest-docs/blob/main/src/getting-started.md#start-render&quot; rel=&quot;noopener&quot;&gt;start-render&lt;/a&gt;
and &lt;a href=&quot;https://web.dev/fcp&quot;&gt;First Contentful Paint&lt;/a&gt; times all remained about the same when varying the max initial
request count (from 5 to 15). Interestingly enough, we noticed a slight performance overhead only
after splitting aggressively to hundreds of requests.&lt;/p&gt;
&lt;img alt=&quot;Page load performance with hundreds of requests&quot; decoding=&quot;async&quot; height=&quot;495&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Ykz3Zm35JUVmtqX1U6cI.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This showed that staying under a reliable threshold (20~25 requests) struck the right balance
between loading performance and caching efficiency. After some baseline testing, 25 was selected as
the &lt;code&gt;maxInitialRequest&lt;/code&gt; count.&lt;/p&gt;
&lt;p&gt;Modifying the maximum number of requests that happen in parallel resulted in more than a single
shared bundle, and separating them appropriately for each entry point significantly reduced the
amount of unneeded code for the same page.&lt;/p&gt;
&lt;img alt=&quot;JavaScript payload reductions with increased chunking&quot; decoding=&quot;async&quot; height=&quot;495&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/z2yOSP2fpfu51OEpyTGS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This experiment was only about modifying the number of requests to see if there would be any
negative effect on page load performance. The results suggest that setting &lt;code&gt;maxInitialRequests&lt;/code&gt; to
&lt;code&gt;25&lt;/code&gt; on the test page was optimal because it reduced the JavaScript payload size without slowing
down the page. The total amount of JavaScript that was needed to hydrate the page still remained
about the same, which explains why page load performance didn&#39;t necessarily improve with the reduced
amount of code.&lt;/p&gt;
&lt;p&gt;webpack uses 30 KB as a default minimum size for a chunk to be generated. However, coupling a
&lt;code&gt;maxInitialRequests&lt;/code&gt; value of 25 with a 20 KB minimum size instead resulted in better caching.&lt;/p&gt;
&lt;h2 id=&quot;size-reductions-with-granular-chunks&quot;&gt;Size reductions with granular chunks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#size-reductions-with-granular-chunks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many frameworks, including Next.js, rely on client-side routing (handled by JavaScript) to inject
newer script tags for every route transition. But how do they predetermine these dynamic chunks at build time?&lt;/p&gt;
&lt;p&gt;Next.js uses a server-side build manifest file to determine which outputted chunks are used by
different entry points. To provide this information to the client as well, an abridged client-side
build manifest file was created to map all the dependencies for every entry point.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Returns a promise for the dependencies for a particular route&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;getDependencies&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;route&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;promisedBuildManifest&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token parameter&quot;&gt;man&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;man&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;route&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; man&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;route&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 function&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;/_next/&lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;url&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&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;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 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;figure&gt;
  &lt;img alt=&quot;Output of multiple shared chunks in a Next.js application.&quot; decoding=&quot;async&quot; height=&quot;488&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3XG4VlLQEQ724fvhynvM.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;This newer granular chunking strategy was first rolled out in Next.js behind a flag, where it was tested on a
number of early adopters. Many saw significant reductions to the total JavaScript used for their
entire site:&lt;/p&gt;
&lt;div&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Website&lt;/th&gt;
        &lt;th&gt;Total JS Change&lt;/th&gt;
        &lt;th&gt;% Difference&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.barnebys.com/&quot;&gt;https://www.barnebys.com/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-238 KB&lt;/td&gt;
        &lt;td&gt;-23%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://sumup.com/&quot;&gt;https://sumup.com/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-220 KB&lt;/td&gt;
        &lt;td&gt;-30%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.hashicorp.com/&quot;&gt;https://www.hashicorp.com/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-11 MB&lt;/td&gt;
        &lt;td&gt;-71%&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
    &lt;caption&gt;JavaScript size reductions - across all routes (compressed)&lt;/caption&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The final version was shipped by default in &lt;a href=&quot;https://nextjs.org/blog/next-9-2&quot; rel=&quot;noopener&quot;&gt;version 9.2&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;gatsby&quot;&gt;Gatsby &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#gatsby&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gatsbyjs.org/&quot; rel=&quot;noopener&quot;&gt;Gatsby&lt;/a&gt; used to follow the same approach of using a usage-based
heuristic for defining common modules:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;optimization &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  …&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;splitChunks&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;name&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;cacheGroups&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;vendors&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;commons&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;commons&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token comment&quot;&gt;// if a chunk is used more than half the components count,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token comment&quot;&gt;// we can assume it&#39;s pretty global&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;minChunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; componentsCount &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; componentsCount &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;react&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;commons&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;chunks&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;node_modules&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token group punctuation&quot;&gt;(&lt;/span&gt;react&lt;span class=&quot;token alternation keyword&quot;&gt;|&lt;/span&gt;react-dom&lt;span class=&quot;token alternation keyword&quot;&gt;|&lt;/span&gt;scheduler&lt;span class=&quot;token group punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token char-class&quot;&gt;&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\\&lt;/span&gt;/&lt;span class=&quot;token char-class-punctuation punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By optimizing their webpack configuration to adopt a similar granular chunking strategy, they also
noticed sizeable JavaScript reductions in many large sites:&lt;/p&gt;
&lt;div&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;Website&lt;/th&gt;
        &lt;th&gt;Total JS Change&lt;/th&gt;
        &lt;th&gt;% Difference&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.gatsbyjs.org/&quot;&gt;https://www.gatsbyjs.org/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-680 KB&lt;/td&gt;
        &lt;td&gt;-22%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://www.thirdandgrove.com/&quot;&gt;https://www.thirdandgrove.com/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-390 KB&lt;/td&gt;
        &lt;td&gt;-25%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://ghost.org/&quot;&gt;https://ghost.org/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-1.1 MB&lt;/td&gt;
        &lt;td&gt;-35%&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;a href=&quot;https://reactjs.org/&quot;&gt;https://reactjs.org/&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;-80 Kb&lt;/td&gt;
        &lt;td&gt;-8%&lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
    &lt;caption&gt;JavaScript size reductions - across all routes (compressed)&lt;/caption&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;Take a look at the &lt;a href=&quot;https://github.com/gatsbyjs/gatsby/pull/22253&quot; rel=&quot;noopener&quot;&gt;PR&lt;/a&gt; to understand how they
implemented this logic into their webpack configuration, which is shipped by default in v2.20.7.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/granular-chunking-nextjs/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The concept of shipping granular chunks is not specific to Next.js, Gatsby or even webpack. Everyone
should consider improving their application&#39;s chunking strategy if it follows a large &amp;quot;commons&amp;quot;
bundle approach, regardless of the framework or module bundler used.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you would like to see the same chunking optimizations applied to a vanilla React application,
take a look at this &lt;a href=&quot;https://glitch.com/edit/#!/webpack-granular-split-chunks?path=webpack.config.js&quot; rel=&quot;noopener&quot;&gt;sample React
app&lt;/a&gt;. It uses a
simplified version of the granular chunking strategy and can help you start applying the same
sort of logic to your site.&lt;/li&gt;
&lt;li&gt;For Rollup, chunks are created granularly by default. Take a look at
&lt;a href=&quot;https://rollupjs.org/guide/en/#manualchunks&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;manualChunks&lt;/code&gt;&lt;/a&gt; if you would like to manually
configure the behavior.&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Resolving Glitch issues</title>
    <link href="https://web.dev/handbook/resolving-glitch-issues/"/>
    <updated>2020-04-27T00:00:00Z</updated>
    <id>https://web.dev/handbook/resolving-glitch-issues/</id>
    <content type="html" mode="escaped">&lt;p&gt;web.dev uses Glitch to embed web-based sample apps and development environments in its posts and
codelabs. See the &lt;a href=&quot;https://web.dev/handbook/markup-sample-app&quot;&gt;Sample apps&lt;/a&gt; post for information about how to set
up a Glitch.&lt;/p&gt;
&lt;p&gt;This post will show you how to resolve some common Glitch issues.&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; Subscribing to Glitch and paying for Boosted Apps will automatically increase memory and disk space as well as improve your rate limits. That&#39;s an always an option if you run into any of the disk/memory issues mentioned in this post. &lt;a href=&quot;https://glitch.happyfox.com/kb/article/73-boosted-apps-what-s-that/&quot;&gt;Learn more&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;project-is-suspended&quot;&gt;Project is suspended &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/handbook/resolving-glitch-issues/#project-is-suspended&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you see a &amp;quot;Project has been suspended&amp;quot; message when opening a new project, contact support via
their public forum or by emailing &lt;code&gt;support@glitch.com&lt;/code&gt;. You should receive a reply soon with steps
you can take to fix your project.&lt;/p&gt;
&lt;img alt=&quot;Suspended-project&quot; decoding=&quot;async&quot; height=&quot;453&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/FZdKu2XfMTu9XNWaljfJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;exceeding-disk-usage&quot;&gt;Exceeding disk usage &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/handbook/resolving-glitch-issues/#exceeding-disk-usage&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you see an App Status warning with exceeded disk limits, you&#39;ll need to clear up some space
before you can edit and use the project.&lt;/p&gt;
&lt;img alt=&quot;Disk limit exceeded&quot; decoding=&quot;async&quot; height=&quot;429&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/iszxjOlALJHJnvo10kMl.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;Remove any unnecessary dependencies from &lt;code&gt;package.json&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;In the terminal, run &lt;code&gt;git gc&lt;/code&gt; and &lt;code&gt;git prune&lt;/code&gt; to remove unneeded files&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;du -hd1&lt;/code&gt; to to see which directories are taking up disk space&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Directories disk usage&quot; decoding=&quot;async&quot; height=&quot;433&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 363px) 363px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/tsPeskkc1It3QeYkCJ5I.png?auto=format&amp;w=726 726w&quot; width=&quot;363&quot; /&gt;
&lt;p&gt;If an unneeded directory is bloating up on every build and taking up disk space:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Remove it (&lt;code&gt;rm -rf directory_name&lt;/code&gt;)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider adding a &lt;code&gt;prestart&lt;/code&gt; script in &lt;code&gt;package.json&lt;/code&gt; to ensure it gets deleted on every build&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&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 property&quot;&gt;&quot;prestart&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;rimraf directory_name&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;...&quot;&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;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the &lt;code&gt;.git&lt;/code&gt; directory is taking up disk space:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run &lt;code&gt;git log --name-only --format=&amp;quot;&amp;quot; | cat | sort | uniq -c | sort -nbr&lt;/code&gt; to see which files are
being committed to history (note: this will still include files previously committed even if they
are now in &lt;code&gt;.gitignore&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Committed files&quot; decoding=&quot;async&quot; height=&quot;89&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 713px) 713px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/kghTObtD4BjdUV950To5.png?auto=format&amp;w=1426 1426w&quot; width=&quot;713&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;If you see any directories committed many times that shouldn&#39;t be, add them to &lt;code&gt;.gitignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If you don&#39;t need &lt;code&gt;.git&lt;/code&gt; history, remove the &lt;code&gt;.git&lt;/code&gt; folder (&lt;code&gt;rm -rf .git&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Prevent layout shifting and flashes of invisible text (FOIT) by preloading optional fonts</title>
    <link href="https://web.dev/preload-optional-fonts/"/>
    <updated>2020-03-18T00:00:00Z</updated>
    <id>https://web.dev/preload-optional-fonts/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; In Chrome 83, new font loading improvements have been made to completely eliminate layout shifting and flash of invisible text (FOIT) when optional fonts are preloaded. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;By optimizing rendering cycles, Chrome 83 eliminates layout shifting when preloading optional fonts.
Combining &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; with &lt;code&gt;font-display: optional&lt;/code&gt; is the most effective way to
guarantee no layout jank when rendering custom fonts.&lt;/p&gt;
&lt;h2 id=&quot;compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-optional-fonts/#compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Check out MDN&#39;s data for up-to-date cross-browser support information:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Preloading_content#Browser_compatibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display#Browser_compatibility&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;font-display&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;font-rendering&quot;&gt;Font rendering &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-optional-fonts/#font-rendering&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Layout shifting, or re-layout, occurs when a resource on a web page changes dynamically, resulting in
a &amp;quot;shift&amp;quot; of content. Fetching and rendering web fonts can directly cause layout shifts in one of
two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A fallback font is swapped with a new font (&amp;quot;flash of unstyled text&amp;quot;)&lt;/li&gt;
&lt;li&gt;&amp;quot;Invisible&amp;quot; text is shown until a new font is rendered into the page (&amp;quot;flash of invisible text&amp;quot;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The CSS &lt;a href=&quot;https://font-display.glitch.me/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;font-display&lt;/code&gt;&lt;/a&gt; property provides a way to modify
rendering behavior of custom fonts through a range of different supported values (&lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;block&lt;/code&gt;,
&lt;code&gt;swap&lt;/code&gt;, &lt;code&gt;fallback&lt;/code&gt;, and &lt;code&gt;optional&lt;/code&gt;). Choosing which value to use depends on the preferred behavior
for asynchronously loaded fonts. However, every one of these supported values can trigger re-layout
in one of the two ways listed above, until now!&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; The &lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift&lt;/a&gt; metric makes it possible to measure the layout instability on a web page. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;optional-fonts&quot;&gt;Optional fonts &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-optional-fonts/#optional-fonts&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;font-display&lt;/code&gt; property uses a timeline of three periods to handle fonts that need to be
downloaded before they can be rendered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Block:&lt;/strong&gt; Render &amp;quot;invisible&amp;quot; text, but switch to the web font as soon as it finishes loading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Swap:&lt;/strong&gt; Render text using a fallback system font, but switch to the web font as soon as it
finishes loading.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fail:&lt;/strong&gt; Render text using a fallback system font.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Previously, fonts designated with &lt;code&gt;font-display: optional&lt;/code&gt; had a 100ms block period and no swap
period. This means that &amp;quot;invisible&amp;quot; text is displayed very briefly before switching to a fallback
font. If the font is not downloaded within 100ms, then the fallback font is used and no swapping
occurs.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing previous optional font behavior when font fails to load&quot; decoding=&quot;async&quot; height=&quot;340&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/WHLORYEu864QRRveFQUz.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Previous &lt;code&gt;font-display: optional&lt;/code&gt; behavior in Chrome when font is downloaded &lt;b&gt;after&lt;/b&gt; the 100ms block period&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;However, in the case that the font is downloaded before the 100ms block period completes, the custom
font is rendered and used on the page.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing previous optional font behavior when font loads in time&quot; decoding=&quot;async&quot; height=&quot;318&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/mordYRjmCCDtlMcNXEOU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Previous &lt;code&gt;font-display: optional&lt;/code&gt; behavior in Chrome when font is downloaded &lt;b&gt;before&lt;/b&gt; the 100ms block period&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Chrome re-renders the page &lt;strong&gt;twice&lt;/strong&gt; in both instances, regardless of whether the fallback font
is used or if the custom font finishes loading in time. This causes a slight flicker of invisible
text and, in cases when a new font is rendered, layout jank that moves some of the page&#39;s content.
This occurs even if the font is stored in the browser&#39;s disk cache and can load well before the
block period is complete.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=1040632&quot; rel=&quot;noopener&quot;&gt;Optimizations&lt;/a&gt; have landed in Chrome 83 to entirely remove the first render cycle for optional fonts
that are preloaded with &lt;a href=&quot;https://web.dev/codelab-preload-web-fonts/&quot;&gt;&lt;code&gt;&amp;lt;link rel=&amp;quot;preload&#39;&amp;gt;&lt;/code&gt;&lt;/a&gt;.
Instead, rendering is blocked until the custom font has finished loading or a certain period of time
has passed. This timeout period is currently set at 100ms, but may possibly change in the near
future to optimize performance.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing new preloaded optional font behavior when font fails to load&quot; decoding=&quot;async&quot; height=&quot;353&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/zLldiq9J3duBTaeRN88e.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;New &lt;code&gt;font-display: optional&lt;/code&gt; behavior in Chrome when fonts are preloaded and font is downloaded &lt;b&gt;after&lt;/b&gt; the 100ms block period (no flash of invisible text)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Diagram showing new preloaded optional font behavior when font loads in time&quot; decoding=&quot;async&quot; height=&quot;346&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/OEHClGFMFspaWjb3xXLY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;New &lt;code&gt;font-display: optional&lt;/code&gt; behavior in Chrome when fonts are preloaded and font is downloaded &lt;b&gt;before&lt;/b&gt; the 100ms block period (no flash of invisible text)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Preloading optional fonts in Chrome removes the possibility of layout jank and flash of unstyled
text. This matches the required behavior as specified in &lt;a href=&quot;https://drafts.csswg.org/css-fonts-4/#valdef-font-face-font-display-optional&quot; rel=&quot;noopener&quot;&gt;CSS Fonts Module Level
4&lt;/a&gt; where optional
fonts should never cause re-layout and user agents can instead delay rendering for a suitable period
of time.&lt;/p&gt;
&lt;p&gt;Although it is not necessary to preload an optional font, it greatly improves the chance for it to
load before the first render cycle, especially if it is not yet stored in the browser&#39;s
cache.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-optional-fonts/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Chrome team is interested to hear your experiences preloading optional fonts with these new optimizations in
place! File an &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/entry&quot; rel=&quot;noopener&quot;&gt;issue&lt;/a&gt; if you experience any
problems or would like to drop any feature suggestions.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Advancing the web framework ecosystem</title>
    <link href="https://web.dev/advancing-framework-ecosystem-cds-2019/"/>
    <updated>2020-01-08T00:00:00Z</updated>
    <id>https://web.dev/advancing-framework-ecosystem-cds-2019/</id>
    <content type="html" mode="escaped">&lt;p&gt;Chrome is an active contributor to the web framework ecosystem and our talk at Chrome Dev Summit
2019 covers what we&#39;ve worked on in the past year.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;QDljY2I1Pfw&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;Read on for an extended recap of the talk with additional details and resources.&lt;/p&gt;
&lt;h2 id=&quot;how-do-we-make-the-web-better&quot;&gt;How do we make the web better? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#how-do-we-make-the-web-better&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal of everyone on the Chrome team is to make the web better. We work on improving browser APIs
and V8--the core JavaScript and WebAssembly engine that powers Chrome--so that developers are
equipped with features that help them build great web pages. We also try to improve websites that
are already in production today by contributing to open-source tooling in many ways.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://almanac.httparchive.org/en/2019/javascript#open-source-libraries-and-frameworks&quot; rel=&quot;noopener&quot;&gt;Most web
developers&lt;/a&gt;
rely on open source tools whenever possible and they prefer not to build entirely custom
infrastructure. Client-side JavaScript frameworks and UI libraries make up a growing portion of
open-source usage. Data on the three most popular client-side frameworks and libraries,
&lt;a href=&quot;https://reactjs.org/&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;, &lt;a href=&quot;https://angular.io/&quot; rel=&quot;noopener&quot;&gt;Angular&lt;/a&gt;, and &lt;a href=&quot;https://vuejs.org/&quot; rel=&quot;noopener&quot;&gt;Vue&lt;/a&gt;, shows
that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;72% of participants in the
&lt;a href=&quot;https://hacks.mozilla.org/2019/12/presenting-the-mdn-web-developer-needs-assessment-web-dna-report/&quot; rel=&quot;noopener&quot;&gt;MDN&#39;s First Annual Web Developer &amp;amp; Designer Survey&lt;/a&gt;
use at least one of these frameworks and libraries.&lt;/li&gt;
&lt;li&gt;Over
&lt;a href=&quot;https://bigquery.cloud.google.com/savedquery/1086077897885:24ffb259f2a04a7f9955e44f6e0298e9&quot; rel=&quot;noopener&quot;&gt;320,000 sites&lt;/a&gt; in
the top 5 million URLs analyzed by HTTP Archive use at least one of these frameworks and libraries.&lt;/li&gt;
&lt;li&gt;When grouped by time spent, 30 of the top 100 URLs use at least one of these frameworks and
libraries. (Research was done on internal data.)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that &lt;strong&gt;better open-source tooling can directly result in a better web&lt;/strong&gt; and that&#39;s why
Chrome engineers have started working directly with external framework and library authors.&lt;/p&gt;
&lt;h2 id=&quot;contributions-to-web-frameworks&quot;&gt;Contributions to web frameworks &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#contributions-to-web-frameworks&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Frameworks commonly used to build and structure web pages fall into two categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;UI frameworks&lt;/strong&gt; (or libraries), such as Preact, React, or Vue, which provide control
over an application&#39;s view layer (through a component model for example).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web frameworks&lt;/strong&gt;, such as Next.js, Nuxt.js, and Gatsby, which provide an end-to-end system
with opinionated features built-in, such as server-side rendering. These frameworks usually
leverage a UI framework or library for the view layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;A spectrum of UI frameworks and libraries versus Web frameworks&quot; decoding=&quot;async&quot; height=&quot;455&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/OI4rF5fAQJ5PYP2f6AA6.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Developers can choose not to use frameworks but by piecing together a view layer library, router,
styling system, server renderer and so forth, they often end up creating their own type of a
framework. Although opinionated, web frameworks take care of many of these concerns by default.&lt;/p&gt;
&lt;p&gt;The rest of this post highlights many improvements that have recently landed in different frameworks
and tools, including contributions from the Chrome team.&lt;/p&gt;
&lt;h2 id=&quot;angular&quot;&gt;Angular &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#angular&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The Angular team has shipped a number of improvements to version 8 of the framework:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/guide/deployment#differential-builds&quot; rel=&quot;noopener&quot;&gt;Differential loading&lt;/a&gt; by
default to minimize unneeded polyfills for newer browsers.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Graph showing bundle size reduction of angular.io with and without differential builds&quot; decoding=&quot;async&quot; height=&quot;463&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/kPQFf4eoaz1wcUZULmbZ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;Bundle size reduction for angular.io with differential builds (from &lt;a href=&quot;https://blog.angular.io/version-8-of-angular-smaller-bundles-cli-apis-and-alignment-with-the-ecosystem-af0261112a27&quot;&gt;Version 8 of Angular&lt;/a&gt;)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;Support for standard dynamic import syntax for lazy-loading routes.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/guide/web-worker&quot; rel=&quot;noopener&quot;&gt;Web worker support&lt;/a&gt; to run operations in a background thread separate from the main thread.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=jnp_ny4SOQE&amp;amp;feature=youtu.be&amp;amp;t=1320&quot; rel=&quot;noopener&quot;&gt;Ivy&lt;/a&gt;, Angular&#39;s new
rendering engine which provides better re-compilation performance and a reduction in bundle
sizes, is available in &lt;a href=&quot;https://angular.io/guide/ivy#opting-into-angular-ivy&quot; rel=&quot;noopener&quot;&gt;preview mode&lt;/a&gt; for
existing projects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can learn more about these improvements in
&lt;a href=&quot;https://blog.angular.io/version-8-of-angular-smaller-bundles-cli-apis-and-alignment-with-the-ecosystem-af0261112a27&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Version 8 of Angular&amp;quot;&lt;/a&gt;
and the Chrome team looks forward to working with them closely in the next year as more features
land.&lt;/p&gt;
&lt;h2 id=&quot;nextjs&quot;&gt;Next.js &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#nextjs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nextjs.org/&quot; rel=&quot;noopener&quot;&gt;Next.js&lt;/a&gt; is a web framework that uses React as a view layer. In addition to a
UI component model that many developers expect from a client-side framework, Next.js provides a
number of built-in default features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routing with default code-splitting&lt;/li&gt;
&lt;li&gt;Compilation and bundling (using &lt;a href=&quot;https://babeljs.io/&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; and
&lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Server-side rendering&lt;/li&gt;
&lt;li&gt;Mechanisms to fetch data at a per-page level&lt;/li&gt;
&lt;li&gt;Encapsulated styling (with &lt;a href=&quot;https://github.com/zeit/styled-jsx&quot; rel=&quot;noopener&quot;&gt;styled-jsx&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next.js optimizes for reduced bundle sizes, and the Chrome team helped identify areas where we could
help further improve performance. You can learn more about each of them by viewing their requests
for comments (RFCs) and pull requests (PRs):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;An improved webpack chunking strategy that emits more granular bundles, reducing the
amount of duplicate code fetched through multiple routes
(&lt;a href=&quot;https://github.com/zeit/next.js/issues/7631&quot; rel=&quot;noopener&quot;&gt;RFC&lt;/a&gt;,
&lt;a href=&quot;https://github.com/zeit/next.js/pull/7696&quot; rel=&quot;noopener&quot;&gt;PR&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Differential loading with the
&lt;a href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/#use-lessscript-type%22module%22greater&quot;&gt;module/nomodule pattern&lt;/a&gt;
which can reduce the total amount of JavaScript in Next.js apps by up to 20% with no code
changes (&lt;a href=&quot;https://github.com/zeit/next.js/issues/7563&quot; rel=&quot;noopener&quot;&gt;RFC&lt;/a&gt;,
&lt;a href=&quot;https://github.com/zeit/next.js/pull/7704&quot; rel=&quot;noopener&quot;&gt;PR&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Improved performance metric tracking which utilizes the User Timing API
(&lt;a href=&quot;https://github.com/zeit/next.js/pull/8069&quot; rel=&quot;noopener&quot;&gt;PR&lt;/a&gt;).&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Homepage of Barnebys.com&quot; decoding=&quot;async&quot; height=&quot;543&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/5QA6KNYCwQ4aLdowLGNS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;&lt;a href=&quot;https://www.barnebys.com/&quot;&gt;Barnebys.com&lt;/a&gt;, a large search engine for antiques and collectibles, saw a 23% reduction in total JavaScript after enabling granular chunking&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;We are also exploring other features to improve both the user and developer experience of using
Next.js, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enabling concurrent mode to unlock progressive or partial hydration of components.&lt;/li&gt;
&lt;li&gt;A webpack based conformance system that analyzes all source files and generated assets to
surface better errors and warnings (&lt;a href=&quot;https://github.com/zeit/next.js/issues/9310&quot; rel=&quot;noopener&quot;&gt;RFC&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Example of a conformance build error in Next.js&quot; decoding=&quot;async&quot; height=&quot;367&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/LoKCHqIIpGkQIUjxZlre.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;An example of a conformance build error in Next.js (prototype)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;nuxtjs&quot;&gt;Nuxt.js &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#nuxtjs&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxtjs.org/&quot; rel=&quot;noopener&quot;&gt;Nuxt.js&lt;/a&gt; is a web framework that combines Vue.js with different libraries to
provide an opinionated setup. Similar to Next.js, it includes many features out-of-the-box:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routing with default code-splitting&lt;/li&gt;
&lt;li&gt;Compilation and bundling (using &lt;a href=&quot;https://babeljs.io/&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; and
&lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Server-side rendering&lt;/li&gt;
&lt;li&gt;Asynchronous data fetching for every page&lt;/li&gt;
&lt;li&gt;Default data store (&lt;a href=&quot;https://vuex.vuejs.org/guide/&quot; rel=&quot;noopener&quot;&gt;Vuex&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Along with working directly on improving the performance of different tools, we&#39;ve expanded the
&lt;a href=&quot;https://opencollective.com/chrome&quot; rel=&quot;noopener&quot;&gt;framework fund&lt;/a&gt; to provide monetary support to more open-source
frameworks and libraries. With our &lt;a href=&quot;https://github.com/nuxt/nuxt.js/issues/6467#issuecomment-538192059&quot; rel=&quot;noopener&quot;&gt;recent
support&lt;/a&gt; to Nuxt.js, a few
features are slated to land in the near future including smarter server-rendering and image
optimizations.&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; The framework fund accelerates the efforts of different frameworks and libraries with the goal to improve their performance. If you are working on an open-source tool and need support, &lt;a href=&quot;https://bit.ly/chrome-framework-fund&quot;&gt;please apply&lt;/a&gt;! &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;babel&quot;&gt;Babel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#babel&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;We&#39;ve also made progress on improving the performance of an important underlying tool in almost all
of the mentioned frameworks--&lt;a href=&quot;https://babeljs.io/&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Babel compiles code that contains newer syntax into code that different browsers can understand.
It&#39;s become common to use &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;@babel/preset-env&lt;/a&gt; to target
modern browsers where different browser targets can be specified to provide enough polyfilling
required for all the chosen environments. One way to specify the targets is to use &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt; to target all browsers that &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#targetsesmodules&quot; rel=&quot;noopener&quot;&gt;support ES
Modules&lt;/a&gt;.&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; To learn more about how to leverage ES modules to minimize polyfill code shipped to browsers that do not need them, check out &lt;a href=&quot;https://web.dev/serve-modern-code-to-modern-browsers&quot;&gt;Serve modern code to modern browsers for faster page loads&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;To optimize for this case, we launched a brand new preset;
&lt;a href=&quot;http://github.com/babel/preset-modules&quot; rel=&quot;noopener&quot;&gt;@babel/preset-modules&lt;/a&gt;. Instead of converting modern syntax
to older syntax to avoid browser bugs, &lt;code&gt;preset-modules&lt;/code&gt; fixes each specific bug by transforming to the
closest possible non-broken modern syntax. This results in modern code that can be delivered &lt;em&gt;nearly
unmodified&lt;/em&gt; to most browsers.&lt;/p&gt;
&lt;img alt=&quot;A new babel preset to provide better polyfilling for browsers&quot; decoding=&quot;async&quot; height=&quot;453&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/8qG6cuXyjKvE89du82Ki.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Developers who already use &lt;code&gt;preset-env&lt;/code&gt; will also benefit from these optimizations without having to
do anything, as they&#39;ll soon be incorporated into &lt;code&gt;preset-env&lt;/code&gt; too.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What&#39;s next? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/advancing-framework-ecosystem-cds-2019/#whats-next&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Working closely with open-source frameworks and libraries to provide better experiences helps the
Chrome team realize what is fundamentally important to users and developers alike.&lt;/p&gt;
&lt;p&gt;If you work on a web framework, UI library, or any form of web tooling (bundler, compiler, linter),
&lt;a href=&quot;http://bit.ly/chrome-framework-fund&quot; rel=&quot;noopener&quot;&gt;apply for the framework fund&lt;/a&gt;!&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>How AMP can guarantee fastness in your Next.js app</title>
    <link href="https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/"/>
    <updated>2019-11-08T00:00:00Z</updated>
    <id>https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://amp.dev/&quot; rel=&quot;noopener&quot;&gt;AMP&lt;/a&gt; is a web component framework that guarantees
fast page loads. &lt;a href=&quot;https://web.dev/performance-as-a-default-with-nextjs&quot;&gt;Next.js&lt;/a&gt; has built-in support for AMP.&lt;/p&gt;
&lt;h2 id=&quot;what-will-you-learn&quot;&gt;What will you learn? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#what-will-you-learn&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This guide first briefly describes &lt;a href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#overview&quot;&gt;how AMP guarantees fast page loads&lt;/a&gt;, then
explains &lt;a href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#strategies&quot;&gt;the different ways you can support AMP in a Next.js app&lt;/a&gt;,
then helps you &lt;a href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#guidance&quot;&gt;decide which approach is best for you&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The intended audience for this guide is a web developer who has decided to use Next.js but is
unsure of whether to support AMP.&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; This guide was not written for web developers who have decided to use AMP but are unsure of what framework to use. We will note briefly however that Next.js could be a good choice because it supports &lt;a href=&quot;https://amp.dev/documentation/guides-and-tutorials/optimize-and-measure/server-side-rendering/&quot;&gt;AMP server-side rendering&lt;/a&gt; and makes it easy to serve AMP content without introducing a lot of complexity into your codebase. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;overview&quot;&gt;How AMP guarantees fast page loads &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#overview&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AMP has two main strategies for guaranteeing fastness:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;AMP HTML&lt;/strong&gt;: A restricted form of HTML that makes certain optimizations mandatory and prohibits
architectural patterns that lead to slowness. See &lt;a href=&quot;https://amp.dev/about/how-amp-works/&quot; rel=&quot;noopener&quot;&gt;How AMP works&lt;/a&gt; for a high-level
overview of the optimizations and restrictions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AMP Cache&lt;/strong&gt;: A content cache used by some search engines, such as Google and Bing, that uses
&lt;a href=&quot;https://developers.googleblog.com/2019/08/the-speed-benefit-of-amp-prerendering.html&quot; rel=&quot;noopener&quot;&gt;prerendering&lt;/a&gt; to speed up page loads. See &lt;a href=&quot;https://blog.amp.dev/2017/01/13/why-amp-caches-exist/&quot; rel=&quot;noopener&quot;&gt;Why AMP Caches exist&lt;/a&gt; to learn more about the
benefits and tradeoffs of the caches and &lt;a href=&quot;https://amp.dev/documentation/guides-and-tutorials/learn/amp-caches-and-cors/how_amp_pages_are_cached/#how-does-my-amp-page-get-cached?&quot; rel=&quot;noopener&quot;&gt;How does my AMP page get cached?&lt;/a&gt; to understand
how your AMP pages get into the caches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;strategies&quot;&gt;How you can use AMP in Next.js &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#strategies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two ways to use AMP in Next.js:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;Hybrid AMP&lt;/strong&gt; approach lets you create an accompanying AMP version of any
Next.js page.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;AMP-only&lt;/strong&gt; approach lets you make AMP the only option for a page.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although Next.js is usually thought of as a React framework, it&#39;s important to understand that
when you use Next.js to serve AMP pages, you can no longer run React components client-side because
React components are not valid AMP components. In other words, Next.js is no longer a React
framework but rather a server-side templating engine for generating AMP pages.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Check out &lt;a href=&quot;https://web.dev/how-to-use-amp-in-nextjs&quot;&gt;How to use AMP in Next.js&lt;/a&gt; to try out the two approaches yourself. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;guidance&quot;&gt;How to decide whether to use the Hybrid AMP or AMP-only approach &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#guidance&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you&#39;re serious about load performance, an AMP-only page could be a good way to make sure
that your page gets fast and stays fast. But here&#39;s the catch: in order to guarantee fastness,
AMP prohibits certain architectural patterns and HTML elements that often lead to slow pages.
For example, AMP doesn&#39;t allow custom synchronous JavaScript because
&lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/render-blocking-resources/&quot; rel=&quot;noopener&quot;&gt;render-blocking resources&lt;/a&gt; are a common cause of slow page loads.&lt;/p&gt;
&lt;p&gt;In order to understand whether an AMP-only approach is right for you, you need to figure out
whether all of your frontend code can be represented in AMP HTML:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Read &lt;a href=&quot;https://amp.dev/about/how-amp-works/&quot; rel=&quot;noopener&quot;&gt;How AMP works&lt;/a&gt; to understand AMP&#39;s high-level
architectural restrictions and mandatory optimizations.&lt;/li&gt;
&lt;li&gt;Read &lt;a href=&quot;https://amp.dev/documentation/guides-and-tutorials/learn/spec/amphtml/#html-tags&quot; rel=&quot;noopener&quot;&gt;HTML Tags&lt;/a&gt; to see what HTML tags AMP allows and prohibits,
browse the &lt;a href=&quot;https://amp.dev/documentation/components/&quot; rel=&quot;noopener&quot;&gt;AMP component catalogue&lt;/a&gt; to see the
custom components that the AMP community has built to solve common use cases, and check
out &lt;a href=&quot;https://amp.dev/documentation/components/amp-script/&quot; rel=&quot;noopener&quot;&gt;amp-script&lt;/a&gt; to learn how to use custom JavaScript to implement features that AMP
doesn&#39;t currently support.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if an AMP-only approach won&#39;t work for your page, it might still be a good idea to
use AMP whenever possible, because of the guaranteed fastness of AMP HTML and the AMP Caches.
The Hybrid AMP approach in Next.js provides a way to conditionally serve AMP pages. However,
it also creates a higher maintenance cost because it requires you to maintain
two versions of each page.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;AMP guarantees that your site gets fast and stays fast by enforcing patterns that lead to
fastness and prohibiting patterns that lead to slowness. AMP HTML and AMP Caches are the two
main ways that AMP guarantees fastness. But before adopting AMP you should make sure that it
can support all of your site&#39;s requirements.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>How to use AMP in Next.js</title>
    <link href="https://web.dev/how-to-use-amp-in-nextjs/"/>
    <updated>2019-11-08T00:00:00Z</updated>
    <id>https://web.dev/how-to-use-amp-in-nextjs/</id>
    <content type="html" mode="escaped">&lt;h2 id=&quot;what-will-you-learn&quot;&gt;What will you learn? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-to-use-amp-in-nextjs/#what-will-you-learn&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This codelab lets you try out the two ways that you can use AMP in a Next.js app.
Check out &lt;a href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app&quot;&gt;How AMP can guarantee fastness in your Next.js app&lt;/a&gt; to learn why you
might want to add AMP support to your Next.js app.&lt;/p&gt;
&lt;h3 id=&quot;hybrid&quot;&gt;How to create Hybrid AMP pages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-to-use-amp-in-nextjs/#hybrid&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;a href=&quot;https://web.dev/how-to-use-amp-in-nextjs/#amponly&quot;&gt;AMP-only approach&lt;/a&gt; is the recommended path for using AMP with Next.js. The Hybrid AMP approach described in this section has a higher maintenance cost than the AMP-only approach because it requires you to maintain two versions of each page. You should only use the Hybrid approach if you&#39;re certain that the AMP-only approach won&#39;t work. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;strong&gt;Hybrid AMP&lt;/strong&gt; approach creates an accompanying AMP version of any Next.js page. In the past
the Hybrid approach was frequently used when there was an experience on the main version of your
page that AMP couldn&#39;t support. The main version had the full experience while the AMP page had
a slightly degraded experience. With the introduction of &lt;a href=&quot;https://amp.dev/documentation/components/amp-script/&quot; rel=&quot;noopener&quot;&gt;amp-script&lt;/a&gt; there&#39;s less of a need
for the Hybrid approach, but we&#39;ll cover it here just in case you still need it.&lt;/p&gt;
&lt;p&gt;There are multiple ways to configure how Next.js renders and serves pages. Using a &lt;code&gt;config&lt;/code&gt;
object allows you to modify these on a per-page basis. In order to serve a specific page as
an AMP page, you need to export the &lt;code&gt;amp&lt;/code&gt; property in the object:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &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 literal-property property&quot;&gt;amp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hybrid&#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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Home&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;This is the home page&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Remix to Edit&lt;/strong&gt; to make the project editable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;?amp=1&lt;/code&gt; to the end of the URL. The page looks the same, but if you look in the
Console you&#39;ll see that the AMP version of the page is being rendered.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The live page and a message in the Chrome DevTools Console stating that the page is powered by AMP.&quot; decoding=&quot;async&quot; height=&quot;376&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ybkMSvzPYUoIpgU4eA1E.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Since the page only has a single &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; tag, there&#39;s no visible difference between the
main page and its AMP version.&lt;/p&gt;
&lt;h4 id=&quot;how-to-conditionally-serve-amp-components&quot;&gt;How to conditionally serve AMP components &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-to-use-amp-in-nextjs/#how-to-conditionally-serve-amp-components&quot;&gt;#&lt;/a&gt;&lt;/h4&gt;
&lt;p&gt;AMP pages need to have their own set of valid components in place of many HTML elements. It&#39;s
important to make sure that the AMP components are conditionally served only for the AMP page.
Next.js provides a &lt;a href=&quot;https://reactjs.org/docs/hooks-overview.html&quot; rel=&quot;noopener&quot;&gt;hook&lt;/a&gt; called &lt;code&gt;useAmp&lt;/code&gt; to allow you to conditionally serve different elements
depending on which version of the page was requested.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;To view the source, press &lt;strong&gt;View Source&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit &lt;code&gt;pages/index.js&lt;/code&gt; so that it renders a different paragraph element to the page depending on whether
the main version or the AMP version was requested:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useAmp &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;next/amp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &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 literal-property property&quot;&gt;amp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hybrid&#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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Home&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token function&quot;&gt;useAmp&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 operator&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;This is the &lt;/span&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;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;AMP&lt;/span&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;strong&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt; version of the home page&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&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;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;This is the main version of the home page&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Load the main version of the page:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of the main version of the page.&quot; decoding=&quot;async&quot; height=&quot;637&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/iXgDaiqLkqLY8kYoKSl7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add &lt;code&gt;?amp=1&lt;/code&gt; to the end of the URL again to load the AMP version of the page:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot of the AMP version of the page that is displaying different text than the main version.&quot; decoding=&quot;async&quot; height=&quot;637&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/kWIKm1ADltg2B2444bLR.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Try rendering AMP&#39;s replacement of the image tag, &lt;code&gt;amp-img&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; useAmp &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;next/amp&#39;&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 keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &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 literal-property property&quot;&gt;amp&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;hybrid&#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;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; imgSrc &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://placekitten.com/1000/1000&#39;&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Image&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;span class=&quot;token operator&quot;&gt;=&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;useAmp&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 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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;amp-img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;A cute kitten&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;imgSrc&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;width&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;1000&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;height&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;1000&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;layout&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;responsive&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;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;amp-img&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 punctuation&quot;&gt;)&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;A cute kitten&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;imgSrc&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;width&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;1000&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;height&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;1000&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;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;img&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 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;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Home&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;Image&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;div&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 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 keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;layout=&amp;quot;responsive&amp;quot;&lt;/code&gt; automatically renders a fully responsive image with an aspect ratio
specified by width and height. Check out &lt;a href=&quot;https://amp.dev/documentation/guides-and-tutorials/develop/style_and_layout/control_layout/&quot; rel=&quot;noopener&quot;&gt;Layout &amp;amp; media queries&lt;/a&gt; to learn more about
the supported layouts of AMP elements, and &lt;a href=&quot;https://amp.dev/documentation/examples/components/amp-img/&quot; rel=&quot;noopener&quot;&gt;amp-img&lt;/a&gt; to learn more about that element&#39;s
optimizations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;View the main version of the page again.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot showing that the image in the main version of the page overflows the viewport.&quot; decoding=&quot;async&quot; height=&quot;637&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/307bH0fcWyCUBhK47CUg.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;View the AMP version of the page again.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A screenshot showing that the image in the AMP version of the page has been automatically resized to fit the viewport.&quot; decoding=&quot;async&quot; height=&quot;637&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/rTuu0WR9Rj6o07eLFFb4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;amponly&quot;&gt;How to create AMP-only pages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/how-to-use-amp-in-nextjs/#amponly&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Next.js also supports AMP-only pages. With this approach, a single AMP page is served and rendered
to users and search engines at all times.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;To render an AMP-only page, change the value of the &lt;code&gt;amp&lt;/code&gt; property in the config object to &lt;code&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; config &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 literal-property property&quot;&gt;amp&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Home&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;This is an AMP-only page&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; Home&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Performance as a default with Next.js</title>
    <link href="https://web.dev/performance-as-a-default-with-nextjs/"/>
    <updated>2019-11-08T00:00:00Z</updated>
    <id>https://web.dev/performance-as-a-default-with-nextjs/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://nextjs.org/&quot; rel=&quot;noopener&quot;&gt;Next.js&lt;/a&gt; is an opinionated &lt;a href=&quot;https://reactjs.org/&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt;
framework with a number of performance optimizations baked in. The main idea
behind the framework is to ensure applications start and remain as performant
as possible by having these capabilities included by default.&lt;/p&gt;
&lt;p&gt;This introduction will briefly cover many features provided by the framework
at a high level. The other guides in this collection will explore the features
in more detail.&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; Chrome is collaborating with Next.js to improve the framework for any developer looking to build a fast, server-rendered React application. A number of newer optimizations were recently added such as &lt;a href=&quot;https://github.com/zeit/next.js/issues/7563&quot;&gt;module/nomodule support&lt;/a&gt; and an &lt;a href=&quot;https://github.com/zeit/next.js/issues/7631&quot;&gt;improved granular chunking strategy&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;what-will-you-learn&quot;&gt;What will you learn? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-as-a-default-with-nextjs/#what-will-you-learn&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although Next.js provides a number of performance optimizations by default, these guides
aim to explain them in more detail and show you how you can use them to build a fast and
performant experience.&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; This collection assumes that you have a basic knowledge of React. If not, check out &lt;a href=&quot;https://reactjs.org/docs/getting-started.html&quot;&gt;React&#39;s Getting Started page&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;There are many optimizations that can be added to React sites in general that would also
work for applications built with Next.js. These will not be covered since the focus is
on what Next.js specifically provides. To learn more about general React
optimizations, check out our &lt;a href=&quot;https://web.dev/react&quot;&gt;React collection&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-is-nextjs-different-from-react&quot;&gt;How is Next.js different from React? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-as-a-default-with-nextjs/#how-is-nextjs-different-from-react&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;React is a library that makes it easier to build user interfaces using a component-based
approach. Although powerful, React is specifically a UI library. Many developers include
additional tooling such as a module bundler (&lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; for example)
and a transpiler (&lt;a href=&quot;https://babeljs.io/&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; for example) to have a complete build toolchain.&lt;/p&gt;
&lt;p&gt;In the &lt;a href=&quot;https://web.dev/react&quot;&gt;React collection&lt;/a&gt;, we took the approach of using &lt;a href=&quot;https://create-react-app.dev/&quot; rel=&quot;noopener&quot;&gt;Create React App&lt;/a&gt;
(CRA) to spin up React apps quickly. CRA takes the hassle out of setting up a React application
by providing a complete build toolchain with a single command.&lt;/p&gt;
&lt;p&gt;Although there are a few default optimizations baked into CRA, the tool aims to provide a
simple and straightforward setup. The choice is given to developers to decide whether
to &lt;a href=&quot;https://create-react-app.dev/docs/available-scripts#npm-run-eject&quot; rel=&quot;noopener&quot;&gt;eject&lt;/a&gt; and
modify the configurations themselves.&lt;/p&gt;
&lt;p&gt;Next.js, which can also be used to create a new React application, takes a different approach.
It immediately provides a number of common optimizations that many developers would like to have
but find difficult to set up, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Server-side rendering&lt;/li&gt;
&lt;li&gt;Automatic code-splitting&lt;/li&gt;
&lt;li&gt;Route prefetching&lt;/li&gt;
&lt;li&gt;File-system routing&lt;/li&gt;
&lt;li&gt;CSS-in-JS styling (&lt;a href=&quot;https://github.com/zeit/styled-jsx&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;styled-jsx&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;setting-up&quot;&gt;Setting up &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-as-a-default-with-nextjs/#setting-up&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To create a new Next.js application, run the following command:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-next-app new-app&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b&quot;&gt;npx&lt;/a&gt; is a package runner that is installed automatically with npm 5.2.0 or later. It simplifies quite a few processes involved with managing packages including running CLI commands (like &lt;code&gt;create-next-app&lt;/code&gt;) without having to install them globally on your machine. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Then navigate to the directory and start the development server:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; new-app&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run dev&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; You can also add Next.js to an existing React application. Check out &lt;a href=&quot;https://nextjs.org/docs#manual-setup&quot;&gt;Manual Setup&lt;/a&gt; to learn how. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The following embed shows the directory structure of a new Next.js app.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Remix to Edit&lt;/strong&gt; to make the project editable.&lt;/li&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/new-next-app?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=index.html&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;new-next-app on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Notice that a &lt;code&gt;pages/&lt;/code&gt; directory is created with a single file: &lt;code&gt;index.jsx&lt;/code&gt;. Next.js follows
a file-system routing approach, where every page within this directory is served as a separate
route. Creating a new file in this directory, such as &lt;code&gt;about.js&lt;/code&gt;, will automatically create a
new route (&lt;code&gt;/about&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Components can also be created and used like any other React application. A &lt;code&gt;components/&lt;/code&gt;
directory has already been created with a single component, &lt;code&gt;nav.js&lt;/code&gt;, which is already
imported in &lt;code&gt;index.js&lt;/code&gt;. By default, every import used in Next.js is only fetched when that
page is loaded, providing the benefits of &lt;strong&gt;automated code-splitting&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Moreover, every initial page load in Next.js is &lt;strong&gt;server-side rendered&lt;/strong&gt;. If you open
the Network panel in DevTools, you can see the initial request for the document returns
a fully server-rendered page.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The Preview tab of the Network panel shows that Next.js returns visually complete HTML when a page is requested.&quot; decoding=&quot;async&quot; height=&quot;529&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/bq2tjbZwvpwqQhFsHp0Q.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    The Preview tab of the Network panel shows that Next.js returns visually complete
    HTML when a page is requested.
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Check out &lt;a href=&quot;https://web.dev/rendering-on-the-web/#server-rendering&quot;&gt;Server Rendering&lt;/a&gt; to learn how server-side rendering often results in a better experience for users. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;These are only a few of the many features provided by Next.js automatically. Many
are customizable and can be modified for different use cases.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What&#39;s next? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/performance-as-a-default-with-nextjs/#whats-next&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Pun intended 😛&lt;/p&gt;
&lt;p&gt;Every other guide in this collection will explore a specific Next.js feature in detail:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/route-prefetching-in-nextjs/&quot;&gt;Route prefetching&lt;/a&gt; to speed up page navigations&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/how-amp-can-guarantee-fastness-in-your-nextjs-app&quot;&gt;Serving hybrid and AMP-only pages&lt;/a&gt; for faster loading from search engines&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/code-splitting-with-dynamic-imports-in-nextjs/&quot;&gt;Code-splitting components with dynamic imports&lt;/a&gt;
to reduce JavaScript footprints&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Browser-level image lazy loading for the web</title>
    <link href="https://web.dev/browser-level-image-lazy-loading/"/>
    <updated>2019-08-06T00:00:00Z</updated>
    <id>https://web.dev/browser-level-image-lazy-loading/</id>
    <content type="html" mode="escaped">&lt;p&gt;Browser-level support for lazy loading images is now supported on the web! This video shows a &lt;a href=&quot;https://mathiasbynens.be/demo/img-loading-lazy&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; of the feature:&lt;/p&gt;
&lt;figure&gt;
  &lt;video controls=&quot;&quot; autoplay=&quot;&quot; loop=&quot;&quot; muted=&quot;&quot;&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/native-lazy-loading/lazyload.webm&quot; type=&quot;video/webm&quot; /&gt;
    &lt;source src=&quot;https://storage.googleapis.com/web-dev-assets/native-lazy-loading/lazyload.mp4&quot; type=&quot;video/mp4&quot; /&gt;
  &lt;/video&gt;
&lt;/figure&gt;
&lt;p&gt;You can use the &lt;code&gt;loading&lt;/code&gt; attribute to lazy-load images without the need to write custom lazy loading code or use a separate JavaScript library. Let&#39;s dive into the details.&lt;/p&gt;
&lt;h2 id=&quot;browser-compatibility&quot;&gt;Browser compatibility &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#browser-compatibility&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 77, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      77
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 75, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      75
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      79
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Safari 15.4, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      15.4
    &lt;/span&gt;
    &lt;/li&gt;
  &lt;/ul&gt;
  &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/Performance/Lazy_loading#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Browsers that do not support the &lt;code&gt;loading&lt;/code&gt; attribute simply ignore it without side effects.&lt;/p&gt;
&lt;h2 id=&quot;why-browser-level-lazy-loading&quot;&gt;Why browser-level lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#why-browser-level-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;According to the &lt;a href=&quot;https://httparchive.org/reports/page-weight&quot; rel=&quot;noopener&quot;&gt;HTTP Archive&lt;/a&gt;, images are the most requested asset type for most websites and usually take up more bandwidth than any other resource. At the 90th percentile, sites send over 5 MB of images on desktop and mobile. That&#39;s a lot of &lt;a href=&quot;https://en.wikipedia.org/wiki/Cats_and_the_Internet&quot; rel=&quot;noopener&quot;&gt;cat pictures&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously, there were two ways to defer the loading of off-screen images:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Using the &lt;a href=&quot;https://developer.chrome.com/blog/intersectionobserver/&quot; rel=&quot;noopener&quot;&gt;Intersection Observer API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Using &lt;code&gt;scroll&lt;/code&gt;, &lt;code&gt;resize&lt;/code&gt;, or &lt;code&gt;orientationchange&lt;/code&gt; &lt;a href=&quot;https://web.dev/lazy-loading-images/&quot;&gt;event handlers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Either option can let developers include lazy loading functionality, and many developers have built third-party libraries to provide abstractions that are even easier to use. With lazy loading supported directly by the browser, however, there&#39;s no need for an external library. Browser-level lazymloading also ensures that deferred loading of images still works even if JavaScript is disabled on the client.&lt;/p&gt;
&lt;h2 id=&quot;the-loading-attribute&quot;&gt;The &lt;code&gt;loading&lt;/code&gt; attribute &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#the-loading-attribute&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Chrome loads images at different priorities depending on where they&#39;re located with respect to the device viewport. Images below the viewport are loaded with a lower priority, but they&#39;re still fetched as the page loads.&lt;/p&gt;
&lt;p&gt;You can use the &lt;code&gt;loading&lt;/code&gt; attribute to completely defer the loading of offscreen images that are reached by scrolling:&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;Here are the supported values for the &lt;code&gt;loading&lt;/code&gt; attribute:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;lazy&lt;/code&gt;: Defer loading of the resource until it reaches a &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;calculated distance&lt;/a&gt; from the viewport.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;eager&lt;/code&gt;: Default loading behavior of the browser, which is the same as not including the attribute and means the image is loaded regardless of where it&#39;s located on the page. While this is the default, it can be useful to explicitly set this if your tooling automatically adds &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; if there is no explicit value, or if your linter complains if it is not explicitly set.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Images that are highly likely to be in-viewport, and in particular &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;LCP&lt;/a&gt; images, &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;should not be lazy-loaded&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;relationship-between-the-loading-attribute-and-fetch-priority&quot;&gt;Relationship between the &lt;code&gt;loading&lt;/code&gt; attribute and fetch priority &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#relationship-between-the-loading-attribute-and-fetch-priority&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;eager&lt;/code&gt; value is simply an instruction to load the image as usual, without delaying the load further if it is off-screen. It does not imply that the image is loaded any quicker than another image without the &lt;code&gt;loading=&amp;quot;eager&amp;quot;&lt;/code&gt; attribute.&lt;/p&gt;
&lt;p&gt;Browsers prioritize resources based on various heuristics, and the &lt;code&gt;loading&lt;/code&gt; attribute just states &lt;em&gt;when&lt;/em&gt; the image resource is queued, not &lt;em&gt;how&lt;/em&gt; it is prioritized in that queue. &lt;code&gt;eager&lt;/code&gt; just implies the usual eager queueing browsers use by default.&lt;/p&gt;
&lt;p&gt;If you want to increase the fetch priority of an important image (for example the LCP image), then &lt;a href=&quot;https://web.dev/fetch-priority/&quot;&gt;Fetch Priority&lt;/a&gt; should be used with &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Note that an image with &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; and &lt;code&gt;fetchpriority=&amp;quot;high&amp;quot;&lt;/code&gt; will still be delayed while it is off-screen, and then fetched with a high priority when it is nearly within the viewport. It would likely be fetched with a high priority in this case anyway, so this combination should not really be needed nor used.&lt;/p&gt;
&lt;h3 id=&quot;distance-from-viewport-thresholds&quot;&gt;Distance-from-viewport thresholds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All images that are above the fold—that is, immediately viewable without scrolling—load normally. Those that are far below the device viewport are only fetched when the user scrolls near them.&lt;/p&gt;
&lt;p&gt;Chromium&#39;s implementation of lazy loading tries to ensure that offscreen images are loaded early enough so that they have finished loading once the user scrolls near to them. By fetching nearby images well before they become visible in the viewport, we maximize the chance they are already loaded by the time they become visible.&lt;/p&gt;
&lt;p&gt;Compared to JavaScript lazy loading libraries, the thresholds for fetching images that scroll into view may be considered conservative.&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; Experiments conducted using Chrome on Android suggest that on 4G, 97.5% of below-the-fold images that are lazy-loaded were fully loaded within 10ms of becoming visible. Even on slow 2G networks, 92.6% of below-the-fold images were fully loaded within 10ms. This means browser-level lazy loading offers a stable experience regarding the visibility of elements that are scrolled into view. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The distance threshold is not fixed and varies depending on several factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The type of image resource being fetched&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://googlechrome.github.io/samples/network-information/&quot; rel=&quot;noopener&quot;&gt;effective connection type&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find the default values for the different effective connection types in the &lt;a href=&quot;https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/frame/settings.json5;l=963-995&quot; rel=&quot;noopener&quot;&gt;Chromium source&lt;/a&gt;. These numbers, and even the approach of fetching only when a certain distance from the viewport is reached, may change in the future as the Chrome team improves heuristics to determine when to begin loading.&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; You can experiment with these different thresholds by &lt;a href=&quot;https://developer.chrome.com/docs/devtools/network/#throttle&quot;&gt;throttling the network&lt;/a&gt; in DevTools. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;improved-data-savings-and-distance-from-viewport-thresholds&quot;&gt;Improved data-savings and distance-from-viewport thresholds &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#improved-data-savings-and-distance-from-viewport-thresholds&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As of July 2020, Chrome has made significant improvements to align the image lazy loading distance-from-viewport thresholds to better meet developer expectations.&lt;/p&gt;
&lt;p&gt;On fast connections (4G), we reduced Chrome&#39;s distance-from-viewport thresholds from &lt;code&gt;3000px&lt;/code&gt; to &lt;code&gt;1250px&lt;/code&gt; and on slower connections (3G or lower), changed the threshold from &lt;code&gt;4000px&lt;/code&gt; to &lt;code&gt;2500px&lt;/code&gt;. This change achieves two things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;img loading=lazy&amp;gt;&lt;/code&gt; behaves closer to the experience offered by JavaScript lazy loading libraries.&lt;/li&gt;
&lt;li&gt;The new distance-from-viewport thresholds still allow us to guarantee images have probably loaded by the time a user has scrolled to them.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can find a comparison between the old vs. new distance-from-viewport thresholds for one of our demos on a fast connection (4G) below:&lt;/p&gt;
&lt;p&gt;Old thresholds. vs new thresholds:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The new and improved thresholds for image lazy loading, reducing the distance-from-viewport thresholds for fast connections from 3000px down to 1250px&quot; decoding=&quot;async&quot; height=&quot;460&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xSZMqpbioBRwRTnenK8f.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;and the new thresholds vs. LazySizes (a popular JS lazy loading library):&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;The new  distance-from-viewport thresholds in Chrome loading 90KB of images compared to LazySizes loading in 70KB under the same network conditions&quot; decoding=&quot;async&quot; height=&quot;355&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/oHMFvflk9aesT7r0iJbx.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;We are committed to working with the web standards community to explore better alignment in how distance-from-viewport thresholds are approached across different browsers.&lt;/p&gt;
&lt;h3 id=&quot;images-should-include-dimension-attributes&quot;&gt;Images should include dimension attributes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#images-should-include-dimension-attributes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;While the browser loads an image, it does not immediately know the image&#39;s dimensions, unless these are explicitly specified. To enable the browser to reserve sufficient space on a page for images, it is recommended that all &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags include both &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes. Without dimensions specified, &lt;a href=&quot;https://web.dev/cls/&quot;&gt;layout shifts&lt;/a&gt; can occur, which are more noticeable on pages that take some time to load.&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;Alternatively, specify their values directly in an inline style:&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;image.png&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token special-attr&quot;&gt;&lt;span class=&quot;token attr-name&quot;&gt;style&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;&lt;span class=&quot;token value css language-css&quot;&gt;&lt;span class=&quot;token property&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;200px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&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 best practice of setting dimensions applies to &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags regardless of whether or not they are being loaded lazily. With lazy loading, this can become more relevant. Setting &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; on images in modern browsers also allows browsers to infer their intrinsic size.&lt;/p&gt;
&lt;p&gt;In most scenarios images still lazy-load if dimensions are not included, but there are a few edge cases you should be aware of. Without &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; specified, image dimensions are 0×0 pixels at first. If you have a gallery of such images, the browser may conclude that all of them fit inside the viewport at the start, as each takes up practically no space and no image is pushed offscreen. In this case the browser determines that all of them are visible to the user and decides to load everything.&lt;/p&gt;
&lt;p&gt;Also, &lt;a href=&quot;https://www.youtube.com/watch?v=4-d_SoCHeWE&quot; rel=&quot;noopener&quot;&gt;specifying image dimensions decreases the chances of layout shifts happening&lt;/a&gt;. If you are unable to include dimensions for your images, lazy loading them can be a trade-off between saving network resources and potentially being more at risk of layout shift.&lt;/p&gt;
&lt;p&gt;While lazy loading in Chromium is implemented in a way such that images are likely to be loaded once they are visible, there is still a small chance that they might not be loaded yet. In this case, missing &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes on such images increase their impact on Cumulative Layout Shift.&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; Take a look at this &lt;a href=&quot;https://mathiasbynens.be/demo/img-loading-lazy&quot;&gt;demo&lt;/a&gt; to see how the &lt;code&gt;loading&lt;/code&gt; attribute works with 100 pictures. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Images that are defined using the &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt; element can also be lazy-loaded:&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;picture&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;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;media&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;(min-width: 800px)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;srcset&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;large.jpg 1x, larger.jpg 2x&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;photo.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&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;picture&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;Although a browser will decide which image to load from any of the &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; elements, the &lt;code&gt;loading&lt;/code&gt; attribute only needs to be included to the fallback &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;h2 id=&quot;avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;Avoid lazy loading images that are in the first visible viewport &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You should avoid setting &lt;code&gt;loading=lazy&lt;/code&gt; for any images that are in the first visible viewport. This is particularly relevant for LCP images. See the article &lt;a href=&quot;https://web.dev/lcp-lazy-loading/&quot;&gt;The performance effects of too much lazy-loading&lt;/a&gt; for more information.&lt;/p&gt;
&lt;p&gt;It is recommended to only add &lt;code&gt;loading=lazy&lt;/code&gt; to images which are positioned below the fold, if possible. Images that are eagerly loaded can be fetched right away, while images which are loaded lazily the browser currently needs to wait until it knows where the image is positioned on the page, which relies on the &lt;code&gt;IntersectionObserver&lt;/code&gt; to be available.&lt;/p&gt;
&lt;p&gt;Generally, any images within the viewport should be loaded eagerly using the browser&#39;s defaults. You do not need to specify &lt;code&gt;loading=eager&lt;/code&gt; for this to be the case for in-viewport images.&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;!-- visible in the viewport --&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-1.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-2.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-3.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;!-- offscreen images --&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-4.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-5.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;product-6.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;...&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;width&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;200&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;height&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;200&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;h2 id=&quot;graceful-degradation&quot;&gt;Graceful degradation &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#graceful-degradation&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Browsers that do not support the &lt;code&gt;loading&lt;/code&gt; attribute will ignore its presence. While these browsers will of course not get the benefits of lazy loading, including the attribute has no negative impact on them.&lt;/p&gt;
&lt;h2 id=&quot;faq&quot;&gt;FAQ &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#faq&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;are-there-plans-to-automatically-lazy-load-images-in-chrome&quot;&gt;Are there plans to automatically lazy-load images in Chrome? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#are-there-plans-to-automatically-lazy-load-images-in-chrome&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Previously, Chromium automatically lazy-loaded any images that were well suited to being deferred if &lt;a href=&quot;https://blog.chromium.org/2019/04/data-saver-is-now-lite-mode.html&quot; rel=&quot;noopener&quot;&gt;Lite mode&lt;/a&gt; was enabled on Chrome for Android and the &lt;code&gt;loading&lt;/code&gt; attribute was either not provided or set as &lt;code&gt;loading=&amp;quot;auto&amp;quot;&lt;/code&gt;. However, &lt;a href=&quot;https://support.google.com/chrome/thread/151853370/sunsetting-chrome-lite-mode-in-m100-and-older?hl=en&quot; rel=&quot;noopener&quot;&gt;Lite mode has been deprecated&lt;/a&gt; (as was the non-standard &lt;code&gt;loading=&amp;quot;auto&amp;quot;&lt;/code&gt;) and there are currently no plans to provide automatically lazy-load of images in Chrome.&lt;/p&gt;
&lt;h3 id=&quot;can-i-change-how-close-an-image-needs-to-be-before-a-load-is-triggered&quot;&gt;Can I change how close an image needs to be before a load is triggered? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#can-i-change-how-close-an-image-needs-to-be-before-a-load-is-triggered&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;These values are hardcoded and can&#39;t be changed through the API. However, they may change in the
future as browsers experiment with different threshold distances and variables.&lt;/p&gt;
&lt;h3 id=&quot;can-css-background-images-take-advantage-of-the-loading-attribute&quot;&gt;Can CSS background images take advantage of the &lt;code&gt;loading&lt;/code&gt; attribute? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#can-css-background-images-take-advantage-of-the-loading-attribute&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No, it can currently only be used with &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;
&lt;h3 id=&quot;is-there-a-downside-to-lazy-loading-images-that-are-within-the-device-viewport&quot;&gt;Is there a downside to lazy loading images that are within the device viewport? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#is-there-a-downside-to-lazy-loading-images-that-are-within-the-device-viewport&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is safer to avoid putting &lt;code&gt;loading=lazy&lt;/code&gt; on above-the-fold images, as Chrome won&#39;t preload &lt;code&gt;loading=lazy&lt;/code&gt; images in the &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;preload scanner&lt;/a&gt; and will also delay fetching such images until all layout is complete. See &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#avoid-lazy-loading-images-that-are-in-the-first-visible-viewport&quot;&gt;Avoid lazy-loading images that are in the first visible viewport&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&quot;how-does-the-loading-attribute-work-with-images-that-are-in-the-viewport-but-not-immediately-visible-for-example-behind-a-carousel,-or-hidden-by-css-for-certain-screen-sizes&quot;&gt;How does the &lt;code&gt;loading&lt;/code&gt; attribute work with images that are in the viewport but not immediately visible (for example: behind a carousel, or hidden by CSS for certain screen sizes)? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-does-the-loading-attribute-work-with-images-that-are-in-the-viewport-but-not-immediately-visible-for-example-behind-a-carousel,-or-hidden-by-css-for-certain-screen-sizes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Using &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; &lt;em&gt;may&lt;/em&gt; prevent them being loaded when they are not visible but within the &lt;a href=&quot;https://web.dev/browser-level-image-lazy-loading/#distance-from-viewport-thresholds&quot;&gt;calculated-distance&lt;/a&gt;. For example, Chrome, Safari and Firefox do not load images using &lt;code&gt;display: none;&lt;/code&gt; styling—either on the image element or on a parent element. However, other techniques to hide images—such as using &lt;code&gt;opacity:0&lt;/code&gt; styling—will still result in the images being loaded. Always test your implementation thoroughly to ensure it&#39;s acting as intended.&lt;/p&gt;
&lt;h3 id=&quot;what-if-im-already-using-a-third-party-library-or-a-script-to-lazy-load-images&quot;&gt;What if I&#39;m already using a third-party library or a script to lazy-load images? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#what-if-im-already-using-a-third-party-library-or-a-script-to-lazy-load-images&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;With full support of native lazy loading now available in modern browsers, you may wish to reconsider if you still need a third-party library or script to lazy-load images.&lt;/p&gt;
&lt;p&gt;One reason to continue to use a third-party library along with &lt;code&gt;loading=&amp;quot;lazy&amp;quot;&lt;/code&gt; is to provide a polyfill for browsers that do not support the attribute, or to have more control over when lazy loading is triggered.&lt;/p&gt;
&lt;h3 id=&quot;how-do-i-handle-browsers-that-dont-support-lazy-loading&quot;&gt;How do I handle browsers that don&#39;t support lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-do-i-handle-browsers-that-dont-support-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Create a polyfill or use a third-party library to lazy-load images on your site. The &lt;code&gt;loading&lt;/code&gt;
property can be used to detect if the feature is supported in the browser:&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;loading&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLImageElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&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 comment&quot;&gt;// supported in browser&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// fetch polyfill/third-party library&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;For example, &lt;a href=&quot;https://github.com/aFarkas/lazysizes&quot; rel=&quot;noopener&quot;&gt;lazysizes&lt;/a&gt; is a popular JavaScript lazy loading library. You can detect support for the &lt;code&gt;loading&lt;/code&gt; attribute to load lazysizes as a fallback library only when &lt;code&gt;loading&lt;/code&gt; isn&#39;t supported. This works as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Replace &lt;code&gt;&amp;lt;img src&amp;gt;&lt;/code&gt; with &lt;code&gt;&amp;lt;img data-src&amp;gt;&lt;/code&gt; to avoid an eager load in unsupported browsers. If the &lt;code&gt;loading&lt;/code&gt; attribute is supported, swap &lt;code&gt;data-src&lt;/code&gt; for &lt;code&gt;src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;loading&lt;/code&gt; is not supported, load a fallback (lazysizes) and initiate it. As per lazysizes docs, you use the &lt;code&gt;lazyload&lt;/code&gt; class as a way to indicate to lazysizes which images to lazy-load.&lt;/li&gt;
&lt;/ul&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;!-- Let&#39;s load this in-viewport image normally --&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;hero.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&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;!-- Let&#39;s lazy-load the rest of these images --&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-src&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;unicorn.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;lazyload&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-src&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;cats.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;lazyload&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;img&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-src&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;dogs.jpg&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;alt&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;…&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loading&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;lazy&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&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;lazyload&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 tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;loading&#39;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HTMLImageElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&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 keyword&quot;&gt;const&lt;/span&gt; images &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;img[loading=&quot;lazy&quot;]&#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;    images&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;img&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; img&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dataset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Dynamically import the LazySizes library&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; script &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#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;    script&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&#39;https://cdnjs.cloudflare.com/ajax/libs/lazysizes/5.1.2/lazysizes.min.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;script&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&gt;&lt;/span&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;script&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;Here&#39;s a &lt;a href=&quot;https://lazy-loading.firebaseapp.com/lazy_loading_lib.html&quot; rel=&quot;noopener&quot;&gt;demo&lt;/a&gt; of this pattern. Try it out in an older browser to see the fallback in action.&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; The lazysizes library also provides a &lt;a href=&quot;https://github.com/aFarkas/lazysizes/tree/gh-pages/plugins/native-loading&quot;&gt;loading plugin&lt;/a&gt; that uses browser-level lazy loading when available but falls back to the library&#39;s custom functionality when needed. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;is-lazy-loading-for-iframes-also-supported-in-browsers&quot;&gt;Is lazy loading for iframes also supported in browsers? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#is-lazy-loading-for-iframes-also-supported-in-browsers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;div class=&quot;wdi-browser-compat&quot;&gt;
  &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt;
  &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt;
    &lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 77, Supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
      77
    &lt;/span&gt;
    &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
    &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt;
      &lt;span class=&quot;visually-hidden&quot;&gt;Firefox, Not supported&lt;/span&gt;
    &lt;/span&gt;
    &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;
&lt;p&gt;&lt;/p&gt;&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Edge 79, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
79
&lt;/span&gt;
&lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt;
&lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt;
&lt;span class=&quot;visually-hidden&quot;&gt;Safari 16.4, Supported&lt;/span&gt;
&lt;/span&gt;
&lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt;
16.4
&lt;/span&gt;
&lt;/li&gt;&lt;p&gt;&lt;/p&gt;
  &lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;iframe loading=lazy&amp;gt;&lt;/code&gt; has also been standardized and is already implemented in Chromium and Safari. This allows you to lazy-load iframes using the &lt;code&gt;loading&lt;/code&gt; attribute. See &lt;a href=&quot;https://web.dev/iframe-lazy-loading/&quot;&gt;this dedicated article about iframe lazy-loading&lt;/a&gt; for more information.&lt;/p&gt;
&lt;h3 id=&quot;how-does-browser-level-lazy-loading-affect-advertisements-on-a-web-page&quot;&gt;How does browser-level lazy loading affect advertisements on a web page? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-does-browser-level-lazy-loading-affect-advertisements-on-a-web-page&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All ads displayed to the user in the form of an image or iframe lazy-load just like any other image or iframe.&lt;/p&gt;
&lt;h3 id=&quot;how-are-images-handled-when-a-web-page-is-printed&quot;&gt;How are images handled when a web page is printed? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#how-are-images-handled-when-a-web-page-is-printed&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;All images and iframes are immediately loaded if the page is printed. See &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=875403&quot; rel=&quot;noopener&quot;&gt;issue #875403&lt;/a&gt; for details.&lt;/p&gt;
&lt;h3 id=&quot;does-lighthouse-recognize-browser-level-lazy-loading&quot;&gt;Does Lighthouse recognize browser-level lazy loading? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#does-lighthouse-recognize-browser-level-lazy-loading&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/lighthouse-whats-new-6.0/&quot;&gt;Lighthouse 6.0&lt;/a&gt; and above factor in approaches for offscreen image lazy loading that may use different thresholds, allowing them to pass the &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/offscreen-images/&quot; rel=&quot;noopener&quot;&gt;Defer offscreen images&lt;/a&gt; audit.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/browser-level-image-lazy-loading/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Baking in support for lazy loading images can make it significantly easier for you to improve the performance of your web pages.&lt;/p&gt;
&lt;p&gt;Are you noticing any unusual behavior with this feature enabled in Chrome? &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/entry?summary=%5BLazyLoad%5D:&amp;amp;comment=Application%20Version%20%28from%20%22Chrome%20Settings%20%3E%20About%20Chrome%22%29:%20%0DAndroid%20Build%20Number%20%28from%20%22Android%20Settings%20%3E%20About%20Phone/Tablet%22%29:%20%0DDevice:%20%0D%0DSteps%20to%20reproduce:%20%0D%0DObserved%20behavior:%20%0D%0DExpected%20behavior:%20%0D%0DFrequency:%20%0D%3Cnumber%20of%20times%20you%20were%20able%20to%20reproduce%3E%20%0D%0DAdditional%20comments:%20%0D&amp;amp;labels=Pri-2&amp;amp;components=Blink%3ELoader%3ELazyLoad%2C&quot; rel=&quot;noopener&quot;&gt;File a bug&lt;/a&gt;!&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Addy Osmani</name>
    </author><author>
      <name>Mathias Bynens</name>
    </author><author>
      <name>Barry Pollard</name>
    </author>
  </entry>
  
  <entry>
    <title>Add a web app manifest with Create React App</title>
    <link href="https://web.dev/add-manifest-react/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/add-manifest-react/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you don&#39;t know how web app manifest files work, refer to the &lt;a href=&quot;https://web.dev/add-manifest&quot;&gt;Add a web app manifest&lt;/a&gt; guide first. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Create React App (CRA) includes a web app manifest by default. Modifying this
file will allow you to change how your application is displayed when installed
on the user&#39;s device.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A progressive web app icon on a mobile phone&amp;#x27;s home screen&quot; decoding=&quot;async&quot; height=&quot;640&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 317px) 317px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/yra3Y2jPf2tS5ELxJdAK.png?auto=format&amp;w=634 634w&quot; width=&quot;317&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/add-manifest-react/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Web app manifest files provide the capability to change how an installed
application will look like on the user&#39;s desktop or mobile device. By modifying
properties in the JSON file, you can modify a number of details in your
application, including its:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name&lt;/li&gt;
&lt;li&gt;Description&lt;/li&gt;
&lt;li&gt;App icon&lt;/li&gt;
&lt;li&gt;Theme color&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Manifest&quot; rel=&quot;noopener&quot;&gt;MDN documentation&lt;/a&gt;
covers all the properties that can be changed in detail.&lt;/p&gt;
&lt;h2 id=&quot;modify-the-default-manifest&quot;&gt;Modify the default manifest &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/add-manifest-react/#modify-the-default-manifest&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In CRA, a default manifest file, &lt;code&gt;/public/manifest.json&lt;/code&gt; is included automatically when a new app is created:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;short_name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;React App&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Create React App Sample&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;icons&quot;&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;favicon.ico&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;sizes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;64x64 32x32 24x24 16x16&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image/x-icon&quot;&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 property&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;logo192.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;sizes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;192x192&quot;&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 property&quot;&gt;&quot;src&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;logo512.png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;image/png&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;sizes&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;512x512&quot;&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 property&quot;&gt;&quot;start_url&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;display&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;standalone&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;theme_color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#000000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;background_color&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;#ffffff&quot;&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;This allows anybody to install the application on their device and see some
default details of the application. The HTML file, &lt;code&gt;public/index.html&lt;/code&gt;, also
includes a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element to load the manifest.&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;manifest&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;%PUBLIC_URL%/manifest.json&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;Here is an example of an application built with CRA that has a modified manifest
file:&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/cra-web-app-manifest-defaut?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=public%2Fmanifest.json&amp;previewSize=0&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;cra-web-app-manifest-defaut on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;To find out if all the properties are working correctly in this example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Application&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Application&lt;/strong&gt; panel, click the &lt;strong&gt;Manifest&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;DevTool&amp;#x27;s Manifest tab shows the properties from the app manifest file.&quot; decoding=&quot;async&quot; height=&quot;695&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/IpK9fr3O0zEX1GJXq9mw.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/add-manifest-react/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you&#39;re building a site that you think does not need to be installed on a
device, remove the manifest and the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element in the HTML file that
points to it.&lt;/li&gt;
&lt;li&gt;If you would like users to install the application on their device, modify
the manifest file (or create one if you are not using CRA) with any
properties that you like. The
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/Manifest&quot; rel=&quot;noopener&quot;&gt;MDN documentation&lt;/a&gt;
explains all the required and optional attributes.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Accessibility auditing with react-axe and eslint-plugin-jsx-a11y</title>
    <link href="https://web.dev/accessibility-auditing-react/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/accessibility-auditing-react/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you would like to learn about the basic concepts behind accessibility in web pages, refer to the &lt;a href=&quot;https://web.dev/what-is-accessibility&quot;&gt;What is accessibility&lt;/a&gt; guide first. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dequelabs/react-axe&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-axe&lt;/code&gt;&lt;/a&gt; is a library that audits a
React application and logs any accessibility issues to the Chrome DevTools
console. It uses the open-source &lt;a href=&quot;https://github.com/dequelabs/axe-core&quot; rel=&quot;noopener&quot;&gt;axe&lt;/a&gt;
testing library to flag any issues and their severity.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/evcohen/eslint-plugin-jsx-a11y&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt;&lt;/a&gt; is
an ESLint plugin that identifies and enforces a number of accessibility rules
directly in your JSX. Using this in combination with a tool that tests the final
rendered DOM, such as &lt;code&gt;react-axe&lt;/code&gt;, can help you find and fix any accessibility
concerns on your site.&lt;/p&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/accessibility-auditing-react/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It is crucial to build websites that provide every user, regardless of their
impairment or restriction, the capability to access its content. Using auditing
libraries such as &lt;code&gt;react-axe&lt;/code&gt; and &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; during the
development of your React application will automatically expose any
accessibility issues as they pop up.&lt;/p&gt;
&lt;h2 id=&quot;use-eslint-plugin-jsx-a11y&quot;&gt;Use eslint-plugin-jsx-a11y &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/accessibility-auditing-react/#use-eslint-plugin-jsx-a11y&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;React already supports writing accessible HTML elements within JSX syntax. For
example, you only need to use the &lt;code&gt;htmlFor&lt;/code&gt; attribute instead of &lt;code&gt;for&lt;/code&gt; to link a
label to a specific form element within a React component.&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;input&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&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;promo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;checkbox&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;label&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;htmlFor&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;promo&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;Receive promotional offers?&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;label&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
&lt;a href=&quot;https://reactjs.org/docs/accessibility.html&quot; rel=&quot;noopener&quot;&gt;React accessibility documentation&lt;/a&gt;
covers all the nuances of handling accessibility concerns within a React
component. To make it easier to spot these issues during development, Create
React App (CRA) includes the &lt;strong&gt;&lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt;&lt;/strong&gt; plugin for ESLint by
default.&lt;/p&gt;
&lt;p&gt;To enable pre-configured linting provided by CRA:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the appropriate &lt;a href=&quot;https://eslint.org/docs/user-guide/integrations#editors&quot; rel=&quot;noopener&quot;&gt;ESLint plugin&lt;/a&gt; for your code editor&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;.eslintrc.json&lt;/code&gt; file to your project&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-app&quot;&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;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; You can find more details about configuring your editor to support out-of-box linting in the &lt;a href=&quot;https://facebook.github.io/create-react-app/docs/setting-up-your-editor&quot;&gt;CRA documentation&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Some common accessibility issues will now show up.&lt;/p&gt;
&lt;img alt=&quot;Image accessibility warning in linter&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/n8Da1iOU3XCpu7avccaS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To check for even more accessibility rules, modify the file to automatically
include all the recommended rules by the plugin:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&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;&quot;react-app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plugin:jsx-a11y/recommended&quot;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;If you would like an even stricter subset of rules, switch to strict mode:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&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;&quot;react-app&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;plugin:jsx-a11y/strict&quot;&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img alt=&quot;Label accessibility error in linter&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/LVsEpuH55MeHaY7RIpl3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The project
&lt;a href=&quot;https://github.com/evcohen/eslint-plugin-jsx-a11y#difference-between-recommended-and-strict-mode&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt;
provides information on the differences between recommended and strict mode.&lt;/p&gt;
&lt;h2 id=&quot;use-react-axe&quot;&gt;Use react-axe &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/accessibility-auditing-react/#use-react-axe&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; can help you easily pinpoint any accessibility issues
in your JSX, but it does not test any of the final HTML output. &lt;strong&gt;&lt;code&gt;react-axe&lt;/code&gt;&lt;/strong&gt;
is a library that does exactly this by providing a React wrapper around the
&lt;a href=&quot;https://github.com/dequelabs/axe-core&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;axe-core&lt;/code&gt;&lt;/a&gt; testing tool by Deque Labs.&lt;/p&gt;
&lt;p&gt;Install the library as a development dependency to begin:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev react-axe&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;You now only need to initialize the module in &lt;code&gt;index.js&lt;/code&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;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;NODE_ENV&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;production&#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 keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;react-axe&#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 function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;axe&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    axe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&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;    ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#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;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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A
&lt;a href=&quot;https://v8.dev/features/dynamic-import&quot; rel=&quot;noopener&quot;&gt;dynamic import&lt;/a&gt;
is used here to only load the library when it is not in production mode before
rendering and booting up the root &lt;code&gt;App&lt;/code&gt; component. This ensures that it is not
unnecessarily included in the final production bundle.&lt;/p&gt;
&lt;p&gt;Now when you run the application during development, issues are surfaced
directly to the Chrome DevTools console.&lt;/p&gt;
&lt;img alt=&quot;React Axe in Chrome DevTools&quot; decoding=&quot;async&quot; height=&quot;430&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/7kiPTpXD47VBf83n6mqz.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;A severity level is also assigned for each violation. These levels are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minor&lt;/li&gt;
&lt;li&gt;Moderate&lt;/li&gt;
&lt;li&gt;Serious&lt;/li&gt;
&lt;li&gt;Critical&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you would like to include accessibility testing in your unit testing workflow, take a look at the &lt;a href=&quot;https://github.com/dequelabs/axe-core/tree/develop/doc/examples/jest_react&quot;&gt;Jest and axe integration example&lt;/a&gt; to understand how. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/accessibility-auditing-react/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;If you are building a site with React, include accessibility auditing into
your workflow early to catch problems as you build your components.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;eslint-plugin-jsx-a11y&lt;/code&gt; to add accessibility checks into your linting
workflow. CRA already comes with it included, but switch to either the
recommended or strict mode.&lt;/li&gt;
&lt;li&gt;In addition to local development testing, include &lt;code&gt;react-axe&lt;/code&gt; into your
application to catch any issues on the final rendered DOM. Do not include it
into your production bundle.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Code splitting with React.lazy and Suspense</title>
    <link href="https://web.dev/code-splitting-suspense/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/code-splitting-suspense/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you don&#39;t yet understand the basic idea behind code splitting, refer to &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;Reduce JavaScript payloads with code splitting&lt;/a&gt; guide first. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The &lt;strong&gt;&lt;code&gt;React.lazy&lt;/code&gt;&lt;/strong&gt; method makes it easy to code-split a React application on a
component level using dynamic imports.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lazy &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&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 keyword&quot;&gt;const&lt;/span&gt; AvatarComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./AvatarComponent&#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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DetailsComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;AvatarComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;div&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/code-splitting-suspense/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A large React application will usually consist of many components, utility
methods, and third-party libraries. If an effort isn&#39;t made to try to load
different parts of an application only when they&#39;re needed, a single, large
bundle of JavaScript will be shipped to your users as soon as they load the
first page. This can affect page performance significantly.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;React.lazy&lt;/code&gt; function provides a built-in way to separate components in an
application into separate chunks of JavaScript with very little legwork. You can
then take care of loading states when you couple it with the &lt;code&gt;Suspense&lt;/code&gt;
component.&lt;/p&gt;
&lt;h2 id=&quot;suspense&quot;&gt;Suspense &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/code-splitting-suspense/#suspense&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The problem with shipping a large JavaScript payload to users is the length of
time it would take for the page to finish loading, especially on weaker devices
and network connections. This is why code splitting and lazy loading is
extremely useful.&lt;/p&gt;
&lt;p&gt;However, there will always be a slight delay that users have to experience when
a code-split component is being fetched over the network, so it&#39;s important to
display a useful loading state. Using &lt;code&gt;React.lazy&lt;/code&gt; with the &lt;strong&gt;&lt;code&gt;Suspense&lt;/code&gt;&lt;/strong&gt;
component helps solve this problem.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&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 keyword&quot;&gt;const&lt;/span&gt; AvatarComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./AvatarComponent&#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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renderLoader&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Loading&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DetailsComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fallback&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderLoader&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;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;AvatarComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;&lt;code&gt;Suspense&lt;/code&gt; accepts a &lt;code&gt;fallback&lt;/code&gt; component which allows you to display any React
component as a loading state. The following example shows how this works.
The avatar is only rendered when the button is clicked, where a request is
then made to retrieve the code necessary for the suspended &lt;code&gt;AvatarComponent&lt;/code&gt;.
In the meantime, the fallback loading component is shown.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-lazy-suspense?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2Findex.css&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-lazy-suspense on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;In here, the code that makes up &lt;code&gt;AvatarComponent&lt;/code&gt; is small which is
why the loading spinner only shows for a short amount of time. Larger
components can take much longer to load, especially on
weak network connections.&lt;/p&gt;
&lt;p&gt;To better demonstrate how this works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Throttling&lt;/strong&gt; dropdown, which is set to &lt;strong&gt;No throttling&lt;/strong&gt; by default. Select &lt;strong&gt;Fast 3G&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Click Me&lt;/strong&gt; button in the app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The loading indicator will show for longer now. Notice how all the code that
makes up the &lt;code&gt;AvatarComponent&lt;/code&gt; is fetched as a separate chunk.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;DevTools network panel showing one chunk.js file being downloaded&quot; decoding=&quot;async&quot; height=&quot;478&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/ga9IsnuJoJdnUfE6sGee.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; React does not currently support Suspense when components are being server-side rendered. If you are rendering on the server, consider using another library such as &lt;a href=&quot;https://www.smooth-code.com/open-source/loadable-components/docs/server-side-rendering/&quot;&gt;&lt;code&gt;loadable-components&lt;/code&gt;&lt;/a&gt; which is recommended in the React docs. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;suspending-multiple-components&quot;&gt;Suspending multiple components &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/code-splitting-suspense/#suspending-multiple-components&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Another feature of &lt;code&gt;Suspense&lt;/code&gt; is that it allows you to suspend multiple
components from loading, &lt;strong&gt;even if they are all lazy loaded&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&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 keyword&quot;&gt;const&lt;/span&gt; AvatarComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./AvatarComponent&#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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; InfoComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./InfoComponent&#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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MoreInfoComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./MoreInfoComponent&#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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renderLoader&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;Loading&lt;/span&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;p&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DetailsComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;fallback&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;renderLoader&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;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;AvatarComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;InfoComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;MoreInfoComponent&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;Suspense&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This is an extremely useful way to delay rendering of multiple components while
only showing a single loading state. Once all the components have finished
fetching, the user gets to see them all displayed at the same time.&lt;/p&gt;
&lt;p&gt;You can see this with the following embed:&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-lazy-suspense-multiple?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2Findex.css&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-lazy-suspense-multiple on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Loading indicator showing a little too quickly? Try simulating a throttled connection in DevTools again. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Without this, it&#39;s easy to run into the problem of &lt;em&gt;staggered loading&lt;/em&gt;, or
different parts of a UI loading one after the other with each having their own
loading indicator. This can make the user experience feel more jarring.&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; Although using Suspense to split components is already possible and makes it easy to trim down bundle sizes, the React team is continuing to work on more features that would extend this even further. The &lt;a href=&quot;https://reactjs.org/blog/2018/11/27/react-16-roadmap.html&quot;&gt;React 16.x roadmap&lt;/a&gt; explains this in more detail. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;handle-loading-failures&quot;&gt;Handle loading failures &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/code-splitting-suspense/#handle-loading-failures&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;Suspense&lt;/code&gt; allows you to display a temporary loading state while network
requests are made under the hood. But what if those network requests fail for
some reason? You might be offline, or perhaps your web app is attempting to
lazy-load a &lt;a href=&quot;https://web.dev/http-cache/#long-lived-caching-for-versioned-urls&quot;&gt;versioned URL&lt;/a&gt;
that is out of date, and no longer available following a server redeployment.&lt;/p&gt;
&lt;p&gt;React has a standard pattern for gracefully handling these types of loading
failures: using an error boundary. As described &lt;a href=&quot;https://reactjs.org/docs/error-boundaries.html&quot; rel=&quot;noopener&quot;&gt;in the documentation&lt;/a&gt;,
any React component can serve as an error boundary if it implements either (or
both) of the lifecycle methods &lt;code&gt;static getDerivedStateFromError()&lt;/code&gt; or
&lt;code&gt;componentDidCatch()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To detect and handle lazy loading failures, you can wrap your &lt;code&gt;Suspense&lt;/code&gt;
component with a parent components that serves as an error boundary. Inside the
error boundary&#39;s &lt;code&gt;render()&lt;/code&gt; method, you can render the children as-is if there&#39;s
no error, or render a custom error message if something goes wrong:&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;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; lazy&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Suspense &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&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 keyword&quot;&gt;const&lt;/span&gt; AvatarComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./AvatarComponent&#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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; InfoComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./InfoComponent&#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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MoreInfoComponent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lazy&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./MoreInfoComponent&#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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;renderLoader&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Loading&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&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 keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ErrorBoundary&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&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;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&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 keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &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 literal-property property&quot;&gt;hasError&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;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;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getDerivedStateFromError&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;error&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token literal-property property&quot;&gt;hasError&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;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;br /&gt;  &lt;span class=&quot;token function&quot;&gt;render&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;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hasError&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 keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Loading failed&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt; Please reload&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&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;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;props&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;children&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;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;DetailsComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ErrorBoundary&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Suspense fallback&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 function&quot;&gt;renderLoader&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;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;AvatarComponent &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;InfoComponent &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;MoreInfoComponent &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;Suspense&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;ErrorBoundary&lt;span class=&quot;token operator&quot;&gt;&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;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/code-splitting-suspense/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are unsure where to begin applying code splitting to your React
application, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Begin at the route level. Routes are the simplest way to identify points of
your application that can be split. The
&lt;a href=&quot;https://reactjs.org/docs/code-splitting.html#route-based-code-splitting&quot; rel=&quot;noopener&quot;&gt;React docs&lt;/a&gt;
show how &lt;code&gt;Suspense&lt;/code&gt; can be used along with
&lt;a href=&quot;https://github.com/ReactTraining/react-router&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-router&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Identify any large components on a page on your site that only render on
certain user interactions (like clicking a button). Splitting these
components will minimize your JavaScript payloads.&lt;/li&gt;
&lt;li&gt;Consider splitting anything else that is offscreen and not critical for the
user.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Jeff Posnick</name>
    </author>
  </entry>
  
  <entry>
    <title>Get started: optimize your React app</title>
    <link href="https://web.dev/get-started-optimize-react/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/get-started-optimize-react/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://reactjs.org/&quot; rel=&quot;noopener&quot;&gt;React&lt;/a&gt; is an open-source library that makes building UIs
easier. This learning path will cover different APIs and tools within the
ecosystem that you should consider using to improve the performance and
usability of your application.&lt;/p&gt;
&lt;p&gt;This guide will show you how to get up and running with a React application.
Every other guide in this section will cover topics to optimize the speed or
accessibility of a React app.&lt;/p&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/get-started-optimize-react/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There&#39;s a lot of content that explains how to build fast and reliable
applications, but not many that show how to build fast and reliable &lt;strong&gt;React&lt;/strong&gt;
applications. These guides cover all this from the perspective of a React
app where only libraries, APIs, and features specific to
the React ecosystem are mentioned.&lt;/p&gt;
&lt;h2 id=&quot;what-will-you-learn&quot;&gt;What will you learn? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/get-started-optimize-react/#what-will-you-learn&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The tutorials in this learning path do &lt;em&gt;not&lt;/em&gt; focus on:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to use React&lt;/li&gt;
&lt;li&gt;How React works under the hood&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although both of these concepts will be touched on when needed, all the guides
and codelabs in this section will instead focus on how to build fast and
accessible React sites. For this reason, &lt;a href=&quot;https://reactjs.org/docs/getting-started.html&quot; rel=&quot;noopener&quot;&gt;a basic knowledge of React is
required&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;create-react-app&quot;&gt;Create React App &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/get-started-optimize-react/#create-react-app&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/create-react-app/&quot; rel=&quot;noopener&quot;&gt;Create React App&lt;/a&gt; (CRA) is the
easiest way to get started building React applications. It provides a default
setup with a number of core features baked in, including a build system
containing a module bundler (webpack) and a transpiler (Babel).&lt;/p&gt;
&lt;p&gt;On a command-line shell, you only need to run the following to create a new
application:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;npx create-react-app app-name&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;npx&lt;/code&gt; is a package runner that is installed automatically with &lt;code&gt;npm&lt;/code&gt; 5.2.0 or later. It simplifies quite a few processes involved with managing packages—including running CLI commands like &lt;code&gt;create-react-app&lt;/code&gt;—without having to install them globally on your machine.  Take a look at &lt;a href=&quot;https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b&quot;&gt;Introducing npx: an npm package runner&lt;/a&gt; if you would like to learn more. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Once the command finishes executing, you can navigate to and run the application
with the following commands:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; new-app&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; start&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The following embed shows the directory structure and the actual web page of a newly
bootstrapped CRA application.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/new-create-react-app?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2FApp.js&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;new-create-react-app on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Although CRA makes it simple to get started building a React application, there are many different ways to begin building sites with React. The &lt;a href=&quot;https://github.com/facebook/create-react-app#popular-alternatives&quot;&gt;&amp;quot;Popular Alternatives&amp;quot;&lt;/a&gt; in the README covers different use-cases and options. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;There are multiple configuration files and build scripts that CRA uses to set up
a webpack and Babel build process that includes a base
&lt;a href=&quot;https://jestjs.io/&quot; rel=&quot;noopener&quot;&gt;Jest&lt;/a&gt; setup for testing. To make things simpler for the
user, these files are hidden and cannot be accessed until you eject from CRA. It
is always best to avoid ejecting whenever possible, since this means taking on all
of these configuration files as your own source code, which can become difficult
to manage.&lt;/p&gt;
&lt;p&gt;The directory structure of a new CRA application only contains the files that
you would actually need to modify in order to work on your application. The
&lt;a href=&quot;https://facebook.github.io/create-react-app/docs/folder-structure&quot; rel=&quot;noopener&quot;&gt;CRA documentation&lt;/a&gt;
explains this in detail.&lt;/p&gt;
&lt;h2 id=&quot;whats-next&quot;&gt;What&#39;s next? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/get-started-optimize-react/#whats-next&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you know how to get started building a Create React App, learn how
to improve your app&#39;s performance and accessibility with all the guides in
this learning path:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/code-splitting-suspense&quot;&gt;Code splitting with React.lazy and Suspense&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/virtualize-long-lists-react-window&quot;&gt;Virtualize large lists with react-window&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/precache-with-workbox-react&quot;&gt;Precaching in Create React App with Workbox&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/prerender-with-react-snap&quot;&gt;Pre-render routes with react-snap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/add-manifest-react&quot;&gt;Add a web app manifest with Create React App&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.dev/accessibility-auditing-react&quot;&gt;Accessibility auditing with react-axe and eslint-plugin-jsx-a11y&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Precaching in Create React App with Workbox</title>
    <link href="https://web.dev/precache-with-workbox-react/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/precache-with-workbox-react/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; If you don&#39;t yet understand the basic idea behind service workers and precaching, read the &lt;a href=&quot;https://web.dev/precache-with-workbox&quot;&gt;Precaching with Workbox&lt;/a&gt; guide first. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Workbox&lt;/code&gt;&lt;/a&gt; is built into
Create React App (CRA) with a default configuration that precaches all the
static assets in your application with every build.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Requests/responses with service worker&quot; decoding=&quot;async&quot; height=&quot;1224&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/3s4l29dJ6ch6QBmTvVg3.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/precache-with-workbox-react/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Service workers enable you to store important resources in its cache
(&lt;em&gt;precaching&lt;/em&gt;) so that when a user loads the web page for a second time, the
browser can retrieve them from the service worker instead of making requests to
the network. This results in faster page loads on repeat visits as well as in the
ability to surface content when the user is offline.&lt;/p&gt;
&lt;h2 id=&quot;workbox-in-cra&quot;&gt;Workbox in CRA &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/precache-with-workbox-react/#workbox-in-cra&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Workbox&lt;/strong&gt; is a collection of tools that allow you create and maintain service
workers. In CRA, the
&lt;a href=&quot;https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;workbox-webpack-plugin&lt;/code&gt;&lt;/a&gt;
is already included into the production build and only needs to be enabled in
the &lt;code&gt;src/index.js&lt;/code&gt; file in order to register a new service worker with every
build:&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ReactDOM &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-dom&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./index.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./App&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; serviceWorker &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./serviceWorker&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;serviceWorker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;unregister&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;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;serviceWorker&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&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;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Here is an example of a React app built with CRA that has a service worker enabled through this file:&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 480px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-sw-example?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2Findex.css&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-sw-example on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;To see which assets are being cached:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&#39;ll notice that instead of showing the payload size, the &lt;code&gt;Size&lt;/code&gt; column shows
a &lt;code&gt;(from ServiceWorker)&lt;/code&gt; message to indicate that these resources were retrieved
from the service worker.&lt;/p&gt;
&lt;img alt=&quot;Network requests with a service worker&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/N7YbiAIT88s8wPUriwo0.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Since the service worker caches all static assets, try to use the application
while offline:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;In the &lt;strong&gt;Network&lt;/strong&gt; tab in DevTools, enable the &lt;strong&gt;Offline&lt;/strong&gt; checkbox to
simulate an offline experience.&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The application works in exactly the same way, even without a network
connection!&lt;/p&gt;
&lt;h2 id=&quot;modifying-caching-strategies&quot;&gt;Modifying caching strategies &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/precache-with-workbox-react/#modifying-caching-strategies&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The default precaching strategy used by Workbox in CRA is &lt;strong&gt;cache-first&lt;/strong&gt;, where
all static assets are fetched from the service worker cache and if that fails
(if the resource is not cached for example), the network request is made. This
is how content can still be served to users even when they are in a complete
offline state.&lt;/p&gt;
&lt;p&gt;Although Workbox provides support to define different strategies and approaches
to caching static and dynamic resources, the default configuration in CRA cannot
be modified or overwritten unless you eject entirely. However, there is an
&lt;a href=&quot;https://github.com/facebook/create-react-app/issues/5359&quot; rel=&quot;noopener&quot;&gt;open proposal&lt;/a&gt;
to explore adding support for an external &lt;code&gt;workbox.config.js&lt;/code&gt; file. This
would allow developers to override the default settings by just creating a
single &lt;code&gt;workbox.config.js&lt;/code&gt; file.&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; For more details on all the caching strategies that a service worker can use, take a look at the &lt;a href=&quot;https://web.dev/offline-cookbook/&quot;&gt;Offline Cookbook&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;handling-a-cache-first-strategy&quot;&gt;Handling a cache-first strategy &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/precache-with-workbox-react/#handling-a-cache-first-strategy&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Relying on the service worker cache first and then falling back to the network
is an excellent way to build sites that load faster on subsequent visits and
work offline to some extent. However, there are a few things that need to
be taken into consideration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How can caching behaviors by a service worker be tested?&lt;/li&gt;
&lt;li&gt;Should there be a message for users to let them know they are looking at
cached content?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app#offline-first-considerations&quot; rel=&quot;noopener&quot;&gt;The CRA
documentation&lt;/a&gt;
explains these points, and more, in detail.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/precache-with-workbox-react/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use a service worker to precache important resources in your application to
provide a faster experience for your users as well as offline support.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you are using CRA, enable the pre-configured service worker in
&lt;code&gt;src/index.js&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If you are not using CRA to build a React application, include one of the
many libraries Workbox provides, such as &lt;code&gt;workbox-webpack-plugin&lt;/code&gt;, into your
build process.&lt;/li&gt;
&lt;li&gt;Keep an eye out for when CRA will support a &lt;code&gt;workbox.config.js&lt;/code&gt; override file
in this
&lt;a href=&quot;https://github.com/facebook/create-react-app/issues/5359&quot; rel=&quot;noopener&quot;&gt;GitHub issue&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Pre-render routes with react-snap</title>
    <link href="https://web.dev/prerender-with-react-snap/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/prerender-with-react-snap/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://github.com/stereobooster/react-snap&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-snap&lt;/code&gt;&lt;/a&gt; is a third-party
library that pre-renders pages on your site into static HTML files. This can
improve
&lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#important-metrics-to-measure&quot;&gt;First Paint&lt;/a&gt;
times in your application.&lt;/p&gt;
&lt;p&gt;Here&#39;s a comparison of the same application with and without pre-rendering
loaded on a simulated 3G connection and mobile device:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;A side by side loading comparison. The version using pre-rendering loads 4.2 seconds faster.&quot; decoding=&quot;async&quot; height=&quot;435&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 600px) 600px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/t5OiDw1VGxrbqbcxMh3J.gif?auto=format&amp;w=1200 1200w&quot; width=&quot;600&quot; /&gt;
&lt;/figure&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;react-snap&lt;/code&gt; is not the only library that can pre-render static HTML content for your React application. &lt;a href=&quot;https://github.com/geelen/react-snapshot&quot;&gt;&lt;code&gt;react-snapshot&lt;/code&gt;&lt;/a&gt; is another alternative. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/prerender-with-react-snap/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The main performance problem with large single-page applications is that the
user needs to wait for the JavaScript bundle(s) that make up the site to finish
downloading before they can see any real content. The larger the bundles, the
longer the user will have to wait.&lt;/p&gt;
&lt;p&gt;To solve this, many developers take the approach of rendering the application on
the server instead of only booting it up on the browser. With each
page/route transition, the complete HTML is generated on the server and sent to
the browser, which reduces First Paint times but comes at the cost of a slower
Time to First Byte.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pre-rendering&lt;/strong&gt; is a separate technique that is less complex than server
rendering, but also provides a way to improve First Paint times in your
application. A headless browser, or a browser without a user interface, is used
to generate static HTML files of every route during &lt;em&gt;build time&lt;/em&gt;. These files
can then be shipped along with the JavaScript bundles that are needed for the
application.&lt;/p&gt;
&lt;h2 id=&quot;react-snap&quot;&gt;react-snap &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/prerender-with-react-snap/#react-snap&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;react-snap&lt;/code&gt; uses &lt;a href=&quot;https://github.com/GoogleChrome/puppeteer&quot; rel=&quot;noopener&quot;&gt;Puppeteer&lt;/a&gt; to
create pre-rendered HTML files of different routes in your application. To
begin, install it as a development dependency:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; --save-dev react-snap&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Then add a &lt;code&gt;postbuild&lt;/code&gt; script in your &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&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 comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;postbuild&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-snap&quot;&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;This would automatically run the &lt;code&gt;react-snap&lt;/code&gt; command every time a new build of
the applications made (&lt;code&gt;npm build&lt;/code&gt;).&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; &lt;code&gt;npm&lt;/code&gt; supports &lt;em&gt;pre&lt;/em&gt; and &lt;em&gt;post&lt;/em&gt; commands for main and arbitrary scripts which will always run directly before or after the original script respectively. You can learn more in the &lt;a href=&quot;https://docs.npmjs.com/misc/scripts&quot;&gt;npm documentation&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The last thing you will need to do is change how the application is booted.
Change the &lt;code&gt;src/index.js&lt;/code&gt; file to 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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ReactDOM &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-dom&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./index.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; App &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./App&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;root&#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;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; rootElement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;root&quot;&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;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;rootElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hasChildNodes&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;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;hydrate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rootElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  ReactDOM&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;App &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; rootElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Instead of only using &lt;code&gt;ReactDOM.render&lt;/code&gt; to render the root React element
directly into the DOM, this checks to see if any child nodes are already present
to determine whether HTML contents were pre-rendered (or rendered on the
server). If that&#39;s the case, &lt;code&gt;ReactDOM.hydrate&lt;/code&gt; is used instead to attach event
listeners to the already created HTML instead of creating it anew.&lt;/p&gt;
&lt;p&gt;Building the application will now generate static HTML files as payloads for
each route that is crawled. You can take a look at what the HTML payload looks
like by clicking the URL of the HTML request and then clicking the &lt;strong&gt;Previews&lt;/strong&gt;
tab within Chrome DevTools.&lt;/p&gt;
&lt;img alt=&quot;A before and after comparison. The after shot shows content has rendered.&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/l5U36PBU7H7Boswn5Gfq.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;react-snap&lt;/code&gt; can be used for other frameworks than React! This includes Vue and Preact. More instructions about this can be found in the &lt;a href=&quot;https://github.com/stereobooster/react-snap&quot;&gt;&lt;code&gt;react-snap&lt;/code&gt; README&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;flash-of-unstyled-content&quot;&gt;Flash of unstyled content &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/prerender-with-react-snap/#flash-of-unstyled-content&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Although static HTML is now rendered almost immediately, it still remains
unstyled by default which may cause the issue of showing a &amp;quot;flash of unstyled
content&amp;quot; (FOUC). This can be especially noticeable if you are using a CSS-in-JS
library to generate selectors since the JavaScript bundle will have to finish
executing before any styles can be applied.&lt;/p&gt;
&lt;p&gt;To help prevent this, the &lt;strong&gt;critical&lt;/strong&gt; CSS, or the minimum amount of CSS that is
needed for the initial page to render, can be inlined directly to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;
of the HTML document. &lt;code&gt;react-snap&lt;/code&gt; uses another third-party library under the
hood, &lt;a href=&quot;https://github.com/peterbe/minimalcss&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;minimalcss&lt;/code&gt;&lt;/a&gt;, to extract any
critical CSS for different routes. You can enable this by specifying the
following in your &lt;code&gt;package.json&lt;/code&gt; file:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;reactSnap&quot;&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 property&quot;&gt;&quot;inlineCss&quot;&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;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;Taking a look at the response preview in Chrome DevTools will now show the styled page with critical CSS inlined.&lt;/p&gt;
&lt;img alt=&quot;A before and after comparison. The after shot shows content has rendered and is styled because of inlined critical CSS.&quot; decoding=&quot;async&quot; height=&quot;450&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/sgxwVZfvpYchXnn1mQrY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; The &lt;code&gt;inlineCSS&lt;/code&gt; option is still experimental. It is worth double-checking to make sure styles are being applied correctly for your routes. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/prerender-with-react-snap/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are not server-side rendering routes in your application, use
&lt;code&gt;react-snap&lt;/code&gt; to pre-render static HTML to your users.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install it as a development dependency and begin with just the default
settings.&lt;/li&gt;
&lt;li&gt;Use the experimental &lt;code&gt;inlineCss&lt;/code&gt; option to inline critical CSS if it works
for your site.&lt;/li&gt;
&lt;li&gt;If you are using code splitting on a component level within any routes, be
careful not to pre-render a loading state to your users. The
&lt;a href=&quot;https://github.com/stereobooster/react-snap#async-components&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-snap&lt;/code&gt; README&lt;/a&gt;
covers this in more detail.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Virtualize large lists with react-window</title>
    <link href="https://web.dev/virtualize-long-lists-react-window/"/>
    <updated>2019-04-29T00:00:00Z</updated>
    <id>https://web.dev/virtualize-long-lists-react-window/</id>
    <content type="html" mode="escaped">&lt;p&gt;&lt;a href=&quot;https://react-window.now.sh/#/examples/list/fixed-size&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-window&lt;/code&gt;&lt;/a&gt; is a
library that allows large lists to be rendered efficiently.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of a list that contains 1000 rows being rendered with
&lt;code&gt;react-window&lt;/code&gt;. Try scrolling as fast you can.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 750px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-window-fixed?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2FApp.js&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-window-fixed on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id=&quot;why-is-this-useful&quot;&gt;Why is this useful? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#why-is-this-useful&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There may be times where you need to display a large table or list that contains
many rows. Loading every single item on such a list can affect performance
significantly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;List virtualization&lt;/strong&gt;, or &amp;quot;windowing&amp;quot;, is the concept of only rendering what
is visible to the user. The number of elements that are rendered at first is a
very small subset of the entire list and the &amp;quot;window&amp;quot; of visible content &lt;em&gt;moves&lt;/em&gt;
when the user continues to scroll. This improves both the rendering and
scrolling performance of the list.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Window of content in a virtualized list&quot; decoding=&quot;async&quot; height=&quot;525&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 578px) 578px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/aWscOPGSFKVAIkgnUplQ.jpg?auto=format&amp;w=1156 1156w&quot; width=&quot;578&quot; /&gt;
  &lt;figcaption&gt;
    Moving &quot;window&quot; of content in a virtualized list
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;DOM nodes that exit the &amp;quot;window&amp;quot; are recycled, or immediately replaced with
newer elements as the user scrolls down the list. This keeps the number of all
rendered elements specific to the size of the window.&lt;/p&gt;
&lt;h2 id=&quot;react-window&quot;&gt;react-window &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#react-window&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;react-window&lt;/code&gt; is a small, third-party library that makes it easier to
create virtualized lists in your application. It provides a number of base APIs
that can be used for different types of lists and tables.&lt;/p&gt;
&lt;h3 id=&quot;when-to-use-fixed-size-lists&quot;&gt;When to use fixed size lists &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#when-to-use-fixed-size-lists&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the &lt;code&gt;FixedSizeList&lt;/code&gt; component if you have a long, one-dimensional list
of equally sized items.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; FixedSizeList &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-window&#39;&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 keyword&quot;&gt;const&lt;/span&gt; items &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 operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// some list of items&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Row&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;     &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* define the row component using items[index] */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;div&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 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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;ListComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;itemSize&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;120&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;itemCount&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Row&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&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 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 keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; ListComponent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;FixedSizeList&lt;/code&gt; component accepts a &lt;code&gt;height&lt;/code&gt;, &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;itemSize&lt;/code&gt; prop
to control the size of the items within the list.&lt;/li&gt;
&lt;li&gt;A function that renders the rows is passed as a child to &lt;code&gt;FixedSizeList&lt;/code&gt;.
Details about the particular item can be accessed with the &lt;code&gt;index&lt;/code&gt; argument
(&lt;code&gt;items[index]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;A &lt;code&gt;style&lt;/code&gt; parameter is also passed in to the row rendering method that
&lt;strong&gt;must&lt;/strong&gt; be attached to the row element. List items are absolutely positioned
with their height and width values assigned inline, and the &lt;code&gt;style&lt;/code&gt; parameter
is responsible for this.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Do not assign &lt;code&gt;height&lt;/code&gt; and &lt;code&gt;width&lt;/code&gt; properties to the list or the list item with an external CSS file. They would be ignored due to the fact that these style attributes are applied inline. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The Glitch example shown earlier in this article shows an example of a
&lt;code&gt;FixedSizeList&lt;/code&gt; component.&lt;/p&gt;
&lt;h3 id=&quot;when-to-use-variable-sized-lists&quot;&gt;When to use variable sized lists &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#when-to-use-variable-sized-lists&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Use the &lt;code&gt;VariableSizeList&lt;/code&gt; component to render a list of items that have
different sizes. This component works in the same way as a fixed size list, but
instead expects a function for the &lt;code&gt;itemSize&lt;/code&gt; prop instead of a specific value.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; VariableSizeList &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-window&#39;&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 keyword&quot;&gt;const&lt;/span&gt; items &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 operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// some list of items&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Row&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;style&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;     &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* define the row component using items[index] */&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;div&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 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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;getItemSize&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// return a size for items[index]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;ListComponent&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;VariableSizeList&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;itemCount&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token attr-name&quot;&gt;itemSize&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;getItemSize&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Row&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;VariableSizeList&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 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 keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; ListComponent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The following embed shows an example of this component.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 750px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-window-variable?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2FListComponent.js&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-window-variable on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;The item size function passed to the &lt;code&gt;itemSize&lt;/code&gt; prop randomizes the row heights
in this example. In a real application however, there should be actual logic
defining the sizes of each item. Ideally, these sizes should be calculated based
on data or obtained from an API.&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; Both &lt;code&gt;FixedSizeList&lt;/code&gt; and &lt;code&gt;VariableSizeList&lt;/code&gt; components support horizontal lists by using a &lt;code&gt;layout=&amp;quot;horizontal&amp;quot;&lt;/code&gt; prop. Take a look at the &lt;a href=&quot;https://react-window.now.sh/#/examples/list/fixed-size&quot;&gt;documentation&lt;/a&gt; to see an example. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;grids&quot;&gt;Grids &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#grids&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;react-window&lt;/code&gt; also provides support for virtualizing multi-dimensional lists,
or grids. In this context, the &amp;quot;window&amp;quot; of visible content changes as the user
scrolls horizontally &lt;strong&gt;and&lt;/strong&gt; vertically.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Moving window of content in a virtualized grid is two-dimensional&quot; decoding=&quot;async&quot; height=&quot;516&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 739px) 739px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/1j2qoGW8bFzBNiOzaJKZ.jpg?auto=format&amp;w=1478 1478w&quot; width=&quot;739&quot; /&gt;
  &lt;figcaption&gt;
    Moving &quot;window&quot; of content in a virtualized grid is two-dimensional
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Similarly, both &lt;code&gt;FixedSizeGrid&lt;/code&gt; and &lt;code&gt;VariableSizeGrid&lt;/code&gt; components can be used
depending on whether the size of specific list items can vary.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For &lt;code&gt;FixedSizeGrid&lt;/code&gt;, the API is about the same but with the fact that heights,
widths and item counts need to be represented for both columns and rows.&lt;/li&gt;
&lt;li&gt;For &lt;code&gt;VariableSizeGrid&lt;/code&gt;, both the column widths and row heights can be changed
by passing in functions instead of values to their respective props.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a look at the
&lt;a href=&quot;https://react-window.now.sh/#/examples/grid/fixed-size&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt; to see
examples of virtualized grids.&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; Aside from providing the base components to create efficient lists and grids, &lt;code&gt;react-window&lt;/code&gt; also provides other capabilities such as scrolling to a specific item or providing an indicator when the user is scrolling. The &lt;a href=&quot;https://react-window.now.sh/#/examples/list/scrolling-indicators&quot;&gt;documentation&lt;/a&gt; provides examples for this. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;lazy-loading-on-scroll&quot;&gt;Lazy loading on scroll &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#lazy-loading-on-scroll&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Many websites improve performance by waiting to load and render items in a long
list until the user has scrolled down. This technique, commonly referred to as
&amp;quot;infinite loading&amp;quot;, adds new DOM nodes into the list as the user scrolls past a
certain threshold close to the end. Although this is better than loading all
items on a list at once, it still ends up populating the DOM with thousands of
row entries if the user has scrolled past that many. This can lead to an
excessively large DOM size, which starts to impact performance by making style
calculations and DOM mutations slower.&lt;/p&gt;
&lt;p&gt;The following diagram might help summarize this:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Difference in scrolling between a regular and virtualized list&quot; decoding=&quot;async&quot; height=&quot;531&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/tcFciHGuF3MxnTr1y5ue01OGLBn2/dKuKVjP02xWxO9LPoOuc.jpg?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
  &lt;figcaption&gt;
    Difference in scrolling between a regular and virtualized list
  &lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The best approach to solve this problem is continue to use a library like
&lt;code&gt;react-window&lt;/code&gt; to maintain a small &amp;quot;window&amp;quot; of elements on a page, but to also
lazy load newer entries as the user scrolls down. A separate package,
&lt;code&gt;react-window-infinite-loader&lt;/code&gt;, makes this possible with &lt;code&gt;react-window&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Consider the following piece of code which shows an example of state that is
managed in a parent &lt;code&gt;App&lt;/code&gt; component.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Component &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&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 keyword&quot;&gt;import&lt;/span&gt; ListComponent &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./ListComponent&#39;&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 keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Component&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;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;props&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 keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;props&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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state &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;items&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// instantiate initial list here&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;moreItemsLoading&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;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token literal-property property&quot;&gt;hasNextPage&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;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 keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loadMore &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;loadMore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;loadMore&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;span class=&quot;token comment&quot;&gt;// method to fetch newer entries for the list&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;render&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;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; moreItemsLoading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hasNextPage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;state&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;ListComponent&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;items&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;moreItemsLoading&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;moreItemsLoading&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;loadMore&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;loadMore&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token attr-name&quot;&gt;hasNextPage&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;hasNextPage&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; App&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A &lt;code&gt;loadMore&lt;/code&gt; method is passed into a child &lt;code&gt;ListComponent&lt;/code&gt; that contains the
infinite loader list. This is important because the infinite loader needs to
fire a callback to load more items once the user has scrolled past a certain
point.&lt;/p&gt;
&lt;p&gt;Here&#39;s how the &lt;code&gt;ListComponent&lt;/code&gt; that renders the list can look like:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; React &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; FixedSizeList &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;react-window&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; InfiniteLoader &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;react-window-infinite-loader&quot;&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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;ListComponent&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; moreItemsLoading&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; loadMore&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; hasNextPage &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Row&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&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 comment&quot;&gt;/* define the row component using items[index] */&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;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; itemCount &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; hasNextPage &lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;InfiniteLoader&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;isItemLoaded&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;itemCount&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;itemCount&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token attr-name&quot;&gt;loadMoreItems&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;loadMore&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&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;span class=&quot;token parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; onItemsRendered&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ref &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;itemCount&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;itemCount&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;itemSize&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;120&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;onItemsRendered&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;onItemsRendered&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token attr-name&quot;&gt;ref&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;ref&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;          &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;Row&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;        &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&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 punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;InfiniteLoader&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 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;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;default&lt;/span&gt; ListComponent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In here, the &lt;code&gt;FixedSizeList&lt;/code&gt; component is wrapped within the &lt;code&gt;InfiniteLoader&lt;/code&gt;.
The props assigned to the loader are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;isItemLoaded&lt;/code&gt;: Method that checks whether a certain item has loaded&lt;/li&gt;
&lt;li&gt;&lt;code&gt;itemCount&lt;/code&gt;: Number of items on the list (or expected)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;loadMoreItems&lt;/code&gt;: Callback that returns a promise that resolves to additional
data for the list&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A
&lt;a href=&quot;https://reactjs.org/docs/render-props.html#using-props-other-than-render&quot; rel=&quot;noopener&quot;&gt;render prop&lt;/a&gt;
is used to return a function that the list component uses in order to render.
Both &lt;code&gt;onItemsRendered&lt;/code&gt; and &lt;code&gt;ref&lt;/code&gt; attributes are attributes that need to be
passed in.&lt;/p&gt;
&lt;p&gt;The following is an example of how infinite loading can work with a virtualized
list.&lt;/p&gt;
&lt;div class=&quot;glitch-embed-wrap&quot; style=&quot;height: 750px; width: 100%;&quot;&gt;
  &lt;iframe allow=&quot;camera; clipboard-read; clipboard-write; encrypted-media; geolocation; microphone; midi&quot; loading=&quot;lazy&quot; src=&quot;https://glitch.com/embed/#!/embed/react-window-infinite?attributionHidden=true&amp;sidebarCollapsed=true&amp;path=src%2FListComponent.js&amp;previewSize=100&quot; style=&quot;height: 100%; width: 100%; border: 0;&quot; title=&quot;react-window-infinite on Glitch&quot;&gt;&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;Scrolling down the list might feel the same, but a request is now made to
retrieve 10 users from a &lt;a href=&quot;https://randomuser.me/&quot; rel=&quot;noopener&quot;&gt;random user API&lt;/a&gt; every time you
scroll close to the end of the list. This is all done while only rendering a
single &amp;quot;window&amp;quot; of results at at a time.&lt;/p&gt;
&lt;p&gt;By checking the &lt;code&gt;index&lt;/code&gt; of a certain item, a different loading state can be
shown for an item depending on whether a request has been made for newer entries
and the item is still loading.&lt;/p&gt;
&lt;p&gt;For example:&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;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Row&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 parameter&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; style &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; itemLoading &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; index &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; items&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;itemLoading&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 comment&quot;&gt;// return loading state&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token comment&quot;&gt;// return item&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;h2 id=&quot;overscanning&quot;&gt;Overscanning &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#overscanning&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since items in a virtualized list only change when the user scrolls, blank
space can briefly flash as newer entries are about to be displayed. You can
try quickly scrolling any of the previous examples in this guide to notice
this.&lt;/p&gt;
&lt;p&gt;To improve the user experience of virtualized lists, &lt;code&gt;react-window&lt;/code&gt; allows
you to overscan items with the &lt;code&gt;overscanCount&lt;/code&gt; property. This allows you to
define how many items outside of the visible &amp;quot;window&amp;quot; to render at all times.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-jsx&quot;&gt;&lt;code class=&quot;language-jsx&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token attr-name&quot;&gt;overscanCount&lt;/span&gt;&lt;span class=&quot;token script language-javascript&quot;&gt;&lt;span class=&quot;token script-punctuation punctuation&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token plain-text&quot;&gt;&lt;br /&gt;  &lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&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 plain-text&quot;&gt;&lt;br /&gt;&lt;/span&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;&lt;span class=&quot;token class-name&quot;&gt;FixedSizeList&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;&lt;code&gt;overscanCount&lt;/code&gt; works for both the &lt;code&gt;FixedSizeList&lt;/code&gt; and &lt;code&gt;VariableSizeList&lt;/code&gt;
components and has a default value of 1. Depending on how large a list is
as well as the size of each item, overscanning more than just one entry can
help prevent a noticeable flash of empty space when the user scrolls. However,
overscanning too many entries can affect performance negatively. The whole
point of using a virtualized list is to minimize the number of entries to what
the user can see at any given moment, so try to keep the number of overscanned
items as low as possible.&lt;/p&gt;
&lt;p&gt;For &lt;code&gt;FixedSizeGrid&lt;/code&gt; and &lt;code&gt;VariableSizeGrid&lt;/code&gt;, use the &lt;code&gt;overscanColumnsCount&lt;/code&gt; and
&lt;code&gt;overscanRowsCount&lt;/code&gt; properties to control the number of columns and rows to
overscan respectively.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/virtualize-long-lists-react-window/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If you are unsure where to begin virtualizing lists and tables in your
application, follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Measure rendering and scrolling performance. This
&lt;a href=&quot;https://addyosmani.com/blog/react-window/&quot; rel=&quot;noopener&quot;&gt;article&lt;/a&gt; shows how the &lt;a href=&quot;https://developer.chrome.com/docs/devtools/evaluate-performance/#analyze_frames_per_second&quot; rel=&quot;noopener&quot;&gt;FPS
meter&lt;/a&gt;
in Chrome DevTools can be used to explore how efficiently items are rendered
on a list.&lt;/li&gt;
&lt;li&gt;Include &lt;code&gt;react-window&lt;/code&gt; for any long lists or grids that are affecting
performance.&lt;/li&gt;
&lt;li&gt;If there are certain features not supported in &lt;code&gt;react-window&lt;/code&gt;, consider using
&lt;a href=&quot;https://github.com/bvaughn/react-virtualized&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;react-virtualized&lt;/code&gt;&lt;/a&gt; if you
cannot add this functionality yourself.&lt;/li&gt;
&lt;li&gt;Wrap your virtualized list with &lt;code&gt;react-window-infinite-loader&lt;/code&gt; if you need to
lazy load items as the user scrolls.&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;overscanCount&lt;/code&gt; property for your lists and the
&lt;code&gt;overscanColumnsCount&lt;/code&gt; and &lt;code&gt;overscanRowsCount&lt;/code&gt; properties for your grids
to prevent a flash of empty content. Do not overscan too many entries as
this will affect performance negatively.&lt;/li&gt;
&lt;/ol&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Jason Miller</name>
    </author>
  </entry>
  
  <entry>
    <title>Codelab: Preload critical assets to improve loading speed</title>
    <link href="https://web.dev/codelab-preload-critical-assets/"/>
    <updated>2019-04-24T00:00:00Z</updated>
    <id>https://web.dev/codelab-preload-critical-assets/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses Chrome DevTools. &lt;a href=&quot;https://www.google.com/chrome&quot;&gt;Download Chrome&lt;/a&gt; if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;In this codelab, the performance of the following web page is improved
by preloading and prefetching a few resources:&lt;/p&gt;
&lt;img alt=&quot;App Screenshot&quot; decoding=&quot;async&quot; height=&quot;578&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Ln5Oxy5vp8QWTn0GoOFh.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-preload-critical-assets/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;First measure how the website performs before adding any optimizations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run the Lighthouse performance audit (&lt;strong&gt;Lighthouse &amp;gt; Options &amp;gt; Performance&lt;/strong&gt;) on
the live version of your Glitch (see also
&lt;a href=&quot;https://web.dev/discover-performance-opportunities-with-lighthouse&quot;&gt;Discover performance opportunities with Lighthouse&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Lighthouse shows the following failed audit for a resource that is fetched
late:&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Lighthouse: Preload key requests audit&quot; decoding=&quot;async&quot; height=&quot;231&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/AMhzorWlWYejd0tA11rY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;ul&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network panel with late-discovered resource&quot; decoding=&quot;async&quot; height=&quot;166&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/pO1f6x9pOqzYwPciKnTy.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;main.css&lt;/code&gt; file is not fetched by a Link element (&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;) placed in the HTML
document, but a separate JavaScript file, &lt;code&gt;fetch-css.js&lt;/code&gt;, attaches
the Link element to the DOM after the &lt;code&gt;window.onLoad&lt;/code&gt; event. This means that the
file is only fetched &lt;em&gt;after&lt;/em&gt; the browser finishes parsing and executing the JS
file.  Similarly, a web font (&lt;code&gt;K2D.woff2&lt;/code&gt;) specified within &lt;code&gt;main.css&lt;/code&gt; is only
fetched once the CSS file has finished downloading.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;critical request chain&lt;/strong&gt; represents the order of resources that are
prioritized and fetched by the browser. For this web page, it currently looks
like this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;├─┬ / &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;initial HTML &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  └── fetch-css.js&lt;br /&gt;    └── main.css&lt;br /&gt;      └── K2D.woff2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Since the CSS file is on the third level of the request chain, Lighthouse has
identified it as a late-discovered resource.&lt;/p&gt;
&lt;h2 id=&quot;preload-critical-resources&quot;&gt;Preload critical resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-preload-critical-assets/#preload-critical-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;main.css&lt;/code&gt; file is a critical asset that&#39;s needed immediately as soon as the
page is loaded. For important files like this resource that are fetched late in
your application, use a link preload tag to inform the browser to download
it sooner by adding a Link element to the head of the document.&lt;/p&gt;
&lt;p&gt;Add a preload tag for this application:&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;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;preload&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;main.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;style&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;as&lt;/code&gt; attribute is used to identify which type of resource is being
fetched, and &lt;code&gt;as=&amp;quot;style&amp;quot;&lt;/code&gt; is used to preload stylesheet files.&lt;/p&gt;
&lt;p&gt;Reload the application and take a look at the &lt;strong&gt;Network&lt;/strong&gt; panel in DevTools.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network panel with preloaded resource&quot; decoding=&quot;async&quot; height=&quot;166&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/3xjh4kLTps0fCqs7wRwP.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Notice how the browser fetches the CSS file before the JavaScript
responsible for fetching it has even been finished parsing. With preload, the browser
knows to make a preemptive fetch for the resource with the assumption that it is
critical for the web page.&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; If this was a real production app, it would make more sense to just place a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; element in index.html to fetch the CSS file instead of using JavaScript to append it. Browsers already know to fetch a CSS file defined at the head of an HTML document with a high priority as soon as possible. However, preload is used in this codelab to demonstrate the best course of action for files that are fetched late in the request chain. For a large application, this can happen quite often. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;If not used correctly, preload can harm performance by making unnecessary
requests for resources that aren&#39;t used. In this application, &lt;code&gt;details.css&lt;/code&gt; is
another CSS file located at the root of the project but is used for a separate
&lt;code&gt;/details route&lt;/code&gt;. To show an example of how preload can be used incorrectly, add a
preload hint for this resource as well.&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;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;preload&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;main.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;style&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;preload&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;details.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;style&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Reload the application and take a look at the &lt;strong&gt;Network&lt;/strong&gt; panel.
A request is made to retrieve &lt;code&gt;details.css&lt;/code&gt; even though it is not being used by the web page.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network panel with unecessary preload&quot; decoding=&quot;async&quot; height=&quot;189&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/vOyq8M3X2UPd5JUTvex0.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Chrome displays a warning in the &lt;strong&gt;Console&lt;/strong&gt; panel when a preloaded resource is
not used by the page within a few seconds after it has loaded.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Preload warning in console&quot; decoding=&quot;async&quot; height=&quot;150&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/elfGvORyRu1s0slntYHo.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Use this warning as an indicator to identify if you have any preloaded resources
that are not being used immediately by your web page. You can now remove the
unnecessary preload link for this 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;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;preload&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;main.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;style&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;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&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;preload&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;details.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;style&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;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;For a list of all the types of resources that can be fetched along with the
correct values that should be used for the &lt;code&gt;as&lt;/code&gt; attribute, refer to the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Preloading_content#What_types_of_content_can_be_preloaded&quot; rel=&quot;noopener&quot;&gt;MDN article on Preloading&lt;/a&gt;.&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; Cross-origin resources can also be preloaded using the &lt;code&gt;crossorigin&lt;/code&gt; attribute. Moreover, same-origin font resources must be fetched using anonymous mode CORS which is why the &lt;code&gt;crossorigin&lt;/code&gt; attribute is also used in this preload tag. The &lt;a href=&quot;https://web.dev/cross-origin-resource-sharing&quot;&gt;Cross Origin Resource Sharing&lt;/a&gt; guide explains the topic of same-origin and cross-origin requests in more detail. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;prefetch-future-resources&quot;&gt;Prefetch future resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-preload-critical-assets/#prefetch-future-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Prefetch&lt;/strong&gt; is another browser hint that can be used to make
a request for an asset used for a different navigation route but at
a lower priority than other important assets needed for the current page.&lt;/p&gt;
&lt;p&gt;In this website, clicking the image takes you to a separate &lt;code&gt;details/&lt;/code&gt;
route.&lt;/p&gt;
&lt;img alt=&quot;Details route&quot; decoding=&quot;async&quot; height=&quot;585&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/KLzVOClmdtwTZ3nhzGz5.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;A separate CSS file, &lt;code&gt;details.css&lt;/code&gt;, contains all the styles needed for this
simple page. Add a link element to &lt;code&gt;index.html&lt;/code&gt; to prefetch this resource.&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;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- ... --&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;prefetch&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;details.css&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;To understand how this triggers a request for the file, open the &lt;strong&gt;Network&lt;/strong&gt; panel in DevTools
and uncheck the &lt;strong&gt;Disable cache&lt;/strong&gt; option.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Disable cache in Chrome DevTools&quot; decoding=&quot;async&quot; height=&quot;145&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/dddEy2ERtrha2WZKN5Ou.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Reload the application and notice how a very low priority request is made for
&lt;code&gt;details.css&lt;/code&gt; after all the other files have been fetched.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network panel with prefetched resource&quot; decoding=&quot;async&quot; height=&quot;211&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/STiBaCDoaZ1Ghzbp5fOH.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;With DevTools open, click the image on the website to navigate to the &lt;code&gt;details&lt;/code&gt; page.
Since a link element is used in &lt;code&gt;details.html&lt;/code&gt; to fetch &lt;code&gt;details.css&lt;/code&gt;, a request is made for the
resource as expected.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Details page network requests&quot; decoding=&quot;async&quot; height=&quot;106&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/AfkaIGXdHifq8n1xD8YQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Click the &lt;code&gt;details.css&lt;/code&gt; network request in DevTools to view its details. You&#39;ll notice
that the file is retrieved from the browser&#39;s disk cache.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Details request fetched from disk cache&quot; decoding=&quot;async&quot; height=&quot;170&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/3pPpPCjbwugX1nnqCf5e.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;By taking advantage of browser idle time, prefetch makes an early request for a
resource needed for a different page. This speeds up future navigation requests
by allowing the browser to cache the asset sooner and serve it from the cache
when needed.&lt;/p&gt;
&lt;h2 id=&quot;preloading-and-prefetching-with-webpack&quot;&gt;Preloading and prefetching with webpack &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-preload-critical-assets/#preloading-and-prefetching-with-webpack&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The
&lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;Reduce JavaScript payloads with code splitting&lt;/a&gt;
post explores the use of dynamic imports to split a bundle into multiple chunks.
This is demonstrated with a simple application that
dynamically imports a module from &lt;a href=&quot;https://lodash.com/&quot; rel=&quot;noopener&quot;&gt;Lodash&lt;/a&gt; when a form is submitted.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Magic Sorter app that demonstrates code splitting&quot; decoding=&quot;async&quot; height=&quot;375&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 600px) 600px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/yg2lFaDyWQFBvw7YaJ3g.gif?auto=format&amp;w=1200 1200w&quot; width=&quot;600&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;You can access &lt;a href=&quot;https://glitch.com/edit/#!/code-splitting&quot; rel=&quot;noopener&quot;&gt;the Glitch for this application here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The following block of code, which lives in &lt;code&gt;src/index.js,&lt;/code&gt; is responsible for
dynamically importing the method when the button is clicked.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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 keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lodash.sortby&#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 function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default&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 function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sortInput&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;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&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;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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Splitting a bundle improves page loading times by
reducing its initial size. Version 4.6.0 of webpack provides support to preload or
prefetch chunks that are imported dynamically. Using this application as an
example, the &lt;code&gt;lodash&lt;/code&gt; method can be prefetched at browser idle time; when a user
presses the button, there is no delay for the resource to be fetched.&lt;/p&gt;
&lt;p&gt;Use the specific &lt;code&gt;webpackPrefetch&lt;/code&gt; comment parameter within a dynamic import to prefetch a particular chunk.
Here is how it would look with this particular application.&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;highlight-line&quot;&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackPrefetch: true */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lodash.sortby&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sortInput&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once the application is reloaded, webpack injects a prefetch tag for the
resource into the head of the document. This can be seen in the &lt;strong&gt;Elements&lt;/strong&gt;
panel in DevTools.&lt;/p&gt;
&lt;img alt=&quot;Elements panel with prefetch tag&quot; decoding=&quot;async&quot; height=&quot;520&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/5Zs5L6UMnkUJXyfwtru7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Observing the requests in the &lt;strong&gt;Network&lt;/strong&gt; panel also shows that this chunk is
fetched with a low priority after all other resources have been requested.&lt;/p&gt;
&lt;figure&gt;
  &lt;img alt=&quot;Network panel with prefetched request&quot; decoding=&quot;async&quot; height=&quot;181&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/nGh06M2LqgTfBUwPaXK7.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;p&gt;Although prefetch makes more sense for this use case, webpack also provides support for preloading
chunks that are dynamically imported.&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;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;/* webpackPreload: true */&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;module&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-preload-critical-assets/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With this codelab, you should have a solid understanding of how preloading or prefetching certain assets can improve the user experience of your site. It is important to mention that these techniques should not be used for every resource and using them incorrectly can harm performance. The best results are noticed by only preloading or prefetching selectively.&lt;/p&gt;
&lt;p&gt;To summarize:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;preload&lt;/strong&gt; for resources that are discovered late but are critical to the current page.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;prefetch&lt;/strong&gt; for resources that are needed for a future navigation route or user action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Not all browsers currently support both preload and prefetch. This means that
not all users of your application may notice performance improvements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/#feat=link-rel-preload&quot; rel=&quot;noopener&quot;&gt;Browser support: Preload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://caniuse.com/#feat=link-rel-prefetch&quot; rel=&quot;noopener&quot;&gt;Browser support: Prefetch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you would like more information about specific aspects of how preloading and
prefetching can affect your web page, refer to these articles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf&quot; rel=&quot;noopener&quot;&gt;Preload, Prefetch and Priorities in Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://medium.com/webpack/link-rel-prefetch-preload-in-webpack-51a52358f84c&quot; rel=&quot;noopener&quot;&gt;&amp;lt;link rel=&amp;quot;prefetch/preload&amp;quot;&amp;gt; in webpack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Serve modern code to modern browsers for faster page loads</title>
    <link href="https://web.dev/codelab-serve-modern-code/"/>
    <updated>2018-12-12T00:00:00Z</updated>
    <id>https://web.dev/codelab-serve-modern-code/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses Chrome DevTools. &lt;a href=&quot;https://www.google.com/chrome&quot;&gt;Download Chrome&lt;/a&gt; if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;In this codelab, improve the performance of this simple application that allows
users to rate random cats. Learn how to optimize the JavaScript bundle by
minizming how much code is transpiled.&lt;/p&gt;
&lt;img alt=&quot;App screenshot&quot; decoding=&quot;async&quot; height=&quot;681&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/E8nNmPiUnD9unvl0ydwT.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In the sample app,
you can select a word or emoji to convey how much you like each cat.
When you click a button,
the app displays the button&#39;s value underneath the current cat image.&lt;/p&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Since webpack is used in this application, any changes made to the code will trigger a new build, which can take a few seconds. Once it completes, you should see your changes reflected in the application. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;It&#39;s always a good idea to begin by inspecting a website before adding any
optimizations:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Original bundle size request&quot; decoding=&quot;async&quot; height=&quot;127&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 717px) 717px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/WOLgtkSsnLlAVqXXkvS2.png?auto=format&amp;w=1434 1434w&quot; width=&quot;717&quot; /&gt;
&lt;p&gt;Over 80 KB is used for this application! Time to find out if parts of the bundle
aren&#39;t being used:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press &lt;code&gt;Control+Shift+P&lt;/code&gt; (or &lt;code&gt;Command+Shift+P&lt;/code&gt; on Mac) to
open the &lt;strong&gt;Command&lt;/strong&gt; menu.&lt;/li&gt;
&lt;/ol&gt;
&lt;!--lint disable code-block-style--&gt;
&lt;p&gt;&lt;img alt=&quot;Command Menu&quot; decoding=&quot;async&quot; height=&quot;170&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/bUJOV2XobvxF0LrIvML4.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Enter &lt;code&gt;Show Coverage&lt;/code&gt; and hit &lt;code&gt;Enter&lt;/code&gt; to display the &lt;strong&gt;Coverage&lt;/strong&gt; tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Coverage&lt;/strong&gt; tab, click &lt;strong&gt;Reload&lt;/strong&gt; to reload the
application while capturing coverage.&lt;/p&gt;
 &lt;img alt=&quot;Reload app with code coverage&quot; decoding=&quot;async&quot; height=&quot;363&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/MVS59W0Ei307x4Ab3FvU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Take a look at how much code was used versus how much was loaded for
the main bundle:&lt;/p&gt;
 &lt;img alt=&quot;Code coverage of bundle&quot; decoding=&quot;async&quot; height=&quot;77&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/YaXfH1OcPENdyMeBBrqK.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;!--lint enable code-block-style--&gt;
&lt;p&gt;Over half the bundle (44 KB) is not even utilized. This is because a lot of the
code within consists of polyfills to ensure that the application works in older
browsers.&lt;/p&gt;
&lt;h2 id=&quot;use-babelpreset-env&quot;&gt;Use @babel/preset-env &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#use-babelpreset-env&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The syntax of the JavaScript language conforms to a standard known as
ECMAScript, or &lt;a href=&quot;https://github.com/tc39/ecma262&quot; rel=&quot;noopener&quot;&gt;ECMA-262&lt;/a&gt;. Newer versions of
the specification are released every year and include new features that have
passed the proposal process. Each major browser is always at a different stage
of supporting these features.&lt;/p&gt;
&lt;!-- lint disable no-repeat-punctuation --&gt;
&lt;!-- note &quot;...&quot; is used in the url for &quot;For…of loop&quot; --&gt;
&lt;p&gt;The following ES2015 features are used in the application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot; rel=&quot;noopener&quot;&gt;Arrow functions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Template_literals&quot; rel=&quot;noopener&quot;&gt;Template literals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for...of&quot; rel=&quot;noopener&quot;&gt;For…of loop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring&quot; rel=&quot;noopener&quot;&gt;Destructuring assignment&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;!-- lint enable no-repeat-punctuation --&gt;
&lt;p&gt;The following ES2017 feature is used as well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function&quot; rel=&quot;noopener&quot;&gt;Async functions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Feel free to dive into the source code in &lt;code&gt;src/index.js&lt;/code&gt; to see how all of this
is used.&lt;/p&gt;
&lt;p&gt;All of these features are supported in the latest version of Chrome, but what
about other browsers that don&#39;t support them? &lt;a href=&quot;https://babeljs.io/docs/en&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt;,
which is included in the application, is the most popular library used to compile
code that contains newer syntax into code that older browsers and environments can
understand. It does this in two ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Polyfills&lt;/strong&gt; are included to emulate newer ES2015+ functions so that their APIs
can be used even if it is not supported by the browser. Here is an example of a
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill&quot; rel=&quot;noopener&quot;&gt;polyfill&lt;/a&gt;
of the &lt;code&gt;Array.includes&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plugins&lt;/strong&gt; are used to transform ES2015 code (or later) into older ES5 syntax.
Since these are syntax related changes (such as arrow functions), they cannot be emulated with polyfills.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Look at &lt;code&gt;package.json&lt;/code&gt; to see which Babel libraries are included:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&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 property&quot;&gt;&quot;@babel/polyfill&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^7.0.0&quot;&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 property&quot;&gt;&quot;devDependencies&quot;&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 comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;babel-loader&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^8.0.2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;@babel/core&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^7.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;@babel/preset-env&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^7.1.0&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&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;ul&gt;
&lt;li&gt;&lt;code&gt;@babel/core&lt;/code&gt; is the core Babel compiler. With this, all the Babel configurations are defined in a &lt;code&gt;.babelrc&lt;/code&gt; at the root of the project.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;babel-loader&lt;/code&gt; includes Babel in the webpack build process.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now look at &lt;code&gt;webpack.config.js&lt;/code&gt; to see how &lt;code&gt;babel-loader&lt;/code&gt; is included as a
rule:&lt;/p&gt;
&lt;pre&gt;
module: {
  rules: [
    //...
    &lt;strong&gt;{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: &quot;babel-loader&quot;
    }&lt;/strong&gt;
  ]
},
&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@babel/polyfill&lt;/code&gt; provides all the necessary polyfills for any newer ECMAScript features so that they can
work in environments that do not support them. It is already imported at the very top of &lt;code&gt;src/index.js.&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./style.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@babel/polyfill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt; identifies which transforms and polyfills are necessary
for any browsers or environments chosen as targets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a look at the Babel configurations file, &lt;code&gt;.babelrc&lt;/code&gt;, to see how it&#39;s
included:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;presets&quot;&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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 property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&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;This is a Babel and webpack setup. &lt;a href=&quot;https://babeljs.io/en/setup&quot; rel=&quot;noopener&quot;&gt;Learn how to include Babel in your
application&lt;/a&gt; if you happen to use a different
module bundler than webpack.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;targets&lt;/code&gt; attribute
in &lt;code&gt;.babelrc&lt;/code&gt; identifies which browsers are being targeted. &lt;code&gt;@babel/preset-env&lt;/code&gt;
integrates with browserslist, which means you can find a full list of compatible
queries that can be used in this field in the
&lt;a href=&quot;https://github.com/browserslist/browserslist#full-list&quot; rel=&quot;noopener&quot;&gt;browserlist documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;quot;last 2 versions&amp;quot;&lt;/code&gt; value transpiles the code in the application for the
&lt;a href=&quot;http://browserl.ist/?q=last+2+versions&quot; rel=&quot;noopener&quot;&gt;last two versions&lt;/a&gt; of every browser.&lt;/p&gt;
&lt;h3 id=&quot;debugging&quot;&gt;Debugging &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#debugging&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;To get a complete look at all the browser&#39;s Babel targets as well as all the
transforms and polyfills that are included, add a &lt;code&gt;debug&lt;/code&gt; field to &lt;code&gt;.babelrc:&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;presets&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;debug&quot;&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;Click &lt;strong&gt;Tools&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Logs&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reload the application and take a look at the Glitch status logs at the bottom
of the editor.&lt;/p&gt;
&lt;h3 id=&quot;targeted-browsers&quot;&gt;Targeted browsers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#targeted-browsers&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Babel logs a number of details to the console about the compilation process,
including all the target environments that the code has been compiled for.&lt;/p&gt;
&lt;img alt=&quot;Targeted browsers&quot; decoding=&quot;async&quot; height=&quot;457&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 464px) 464px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/X6nauvGqKuyWoBekgCbw.png?auto=format&amp;w=928 928w&quot; width=&quot;464&quot; /&gt;
&lt;p&gt;Notice how discontinued browsers, such as Internet Explorer, are included in
this list. This is a problem because unsupported browsers won&#39;t have newer
features added, and Babel continues to transpile specific syntax for them. This
unnecessarily increases the size of your bundle if users are not using this
browser to access your site.&lt;/p&gt;
&lt;p&gt;Babel also logs a list of transform plugins used:&lt;/p&gt;
&lt;img alt=&quot;List of plugins used&quot; decoding=&quot;async&quot; height=&quot;604&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/clNXHWSfeD2RKDkIrJo8.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;That&#39;s a pretty long list! These are all the plugins that Babel needs to use to
transform any ES2015+ syntax to older syntax for all the targeted browsers.&lt;/p&gt;
&lt;p&gt;However, Babel doesn&#39;t show any specific polyfills that are used:&lt;/p&gt;
&lt;img alt=&quot;No polyfills added&quot; decoding=&quot;async&quot; height=&quot;38&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xPhc2usfwfIJkoK4EubY.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This is because the entire &lt;code&gt;@babel/polyfill&lt;/code&gt; is being imported directly.&lt;/p&gt;
&lt;h3 id=&quot;load-polyfills-individually&quot;&gt;Load polyfills individually &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#load-polyfills-individually&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;By default, Babel includes every polyfill needed for a complete ES2015+ environment when
&lt;code&gt;@babel/polyfill&lt;/code&gt; is imported into a file. To import specific polyfills needed for
the target browsers, add a &lt;code&gt;useBuiltIns: &#39;entry&#39;&lt;/code&gt; to the configuration.&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;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;presets&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;debug&quot;&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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;entry&quot;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Reload the application. You can now see all the specific polyfills included:&lt;/p&gt;
&lt;img alt=&quot;List of polyfills imported&quot; decoding=&quot;async&quot; height=&quot;465&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/VQHDI6qG94zbTiorG3aT.gif?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Although only needed polyfills for &lt;code&gt;&amp;quot;last 2 versions&amp;quot;&lt;/code&gt; is now included, it is still a super long list! This is because
polyfills needed for the target browsers for &lt;em&gt;every&lt;/em&gt; newer feature is still included. Change the value of the attribute to &lt;code&gt;usage&lt;/code&gt;
to only include those needed for features that are being used in the code.&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;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;presets&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;debug&quot;&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;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;entry&quot;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;usage&quot;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;With this, polyfills are automatically included where needed.
This means you can remove the &lt;code&gt;@babel/polyfill&lt;/code&gt; import in &lt;code&gt;src/index.js.&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./style.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;@babel/polyfill&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now only the required polyfills needed for the application are included.&lt;/p&gt;
&lt;img alt=&quot;List of polyfills automatically included&quot; decoding=&quot;async&quot; height=&quot;114&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ir2qkYhxoJDWoQUhD8KD.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The application bundle size is reduced significantly.&lt;/p&gt;
&lt;img alt=&quot;Bundle size reduced to 30.1 KB&quot; decoding=&quot;async&quot; height=&quot;135&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 796px) 796px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/6cIW1H9dYz38h3jp9QpK.png?auto=format&amp;w=1592 1592w&quot; width=&quot;796&quot; /&gt;
&lt;h2 id=&quot;narrowing-the-list-of-supported-browsers&quot;&gt;Narrowing the list of supported browsers &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#narrowing-the-list-of-supported-browsers&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The number of browser targets included is still quite large, and not many users
use discontinued browsers such as Internet Explorer. Update the configurations
to 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;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;presets&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;targets&quot;&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;&quot;&gt;0.25%&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;not ie 11&quot;&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;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;debug&quot;&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;        &lt;span class=&quot;token string-property property&quot;&gt;&quot;useBuiltIns&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;usage&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Take a look at the details for the fetched bundle.&lt;/p&gt;
&lt;img alt=&quot;Bundle size of 30.0 KB&quot; decoding=&quot;async&quot; height=&quot;131&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 793px) 793px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/LQrCZtEqujASX2KBR9ku.png?auto=format&amp;w=1586 1586w&quot; width=&quot;793&quot; /&gt;
&lt;p&gt;Since the application is so small, there really isn&#39;t much of a difference with
these changes. However, using a browser market share percentage (such as
&lt;code&gt;&amp;quot;&amp;gt;0.25%&amp;quot;&lt;/code&gt;) along with excluding specific browsers that you are confident your
users are not using is the recommended approach. Take a look at the
&lt;a href=&quot;https://jamie.build/last-2-versions&quot; rel=&quot;noopener&quot;&gt;&amp;quot;Last 2 versions&amp;quot; considered harmful&lt;/a&gt;
article by James Kyle to learn more about this.&lt;/p&gt;
&lt;h2 id=&quot;use-lessscript-type=modulegreater&quot;&gt;Use &amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#use-lessscript-type=modulegreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There is still more room for improvement. Although a number of unused polyfills
have been removed, there are many that are being shipped that are not needed for
some browsers. By using modules, newer syntax can be written and shipped to
browsers directly without the use of any unnecessary polyfills.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JavaScript modules&lt;/strong&gt; are a relatively new feature supported in &lt;a href=&quot;https://caniuse.com/#feat=es6-module&quot; rel=&quot;noopener&quot;&gt;all major browsers&lt;/a&gt;.
Modules can be created using a &lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt; attribute to define scripts that import and export from other
modules. For example:&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;// math.mjs&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;add&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 parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt; index&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;html &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;script type&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;module&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; add &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./math.mjs&#39;&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 function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&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 comment&quot;&gt;// 7&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;script&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Many newer ECMAScript features are already supported in environments that
support JavaScript modules (instead of needing Babel.) This means that the Babel
config can be modified to send two different versions of your application to the
browser:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A version that would work in newer browsers that support modules and that includes a module that is largely untranspiled but has a smaller file size&lt;/li&gt;
&lt;li&gt;A version that includes a larger, transpiled script that would work in any legacy browser&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;using-es-modules-with-babel&quot;&gt;Using ES Modules with Babel &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#using-es-modules-with-babel&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To have separate &lt;code&gt;@babel/preset-env&lt;/code&gt; settings for the two versions of
the application, remove the &lt;code&gt;.babelrc&lt;/code&gt; file. Babel settings can be added to the
webpack configuration by specifying two different compilation formats for each
version of the application.&lt;/p&gt;
&lt;p&gt;Begin by adding a configuration for the legacy script to &lt;code&gt;webpack.config.js&lt;/code&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;const&lt;/span&gt; legacyConfig &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;  entry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;output&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;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public&quot;&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;filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[name].bundle.js&quot;&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;module&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;rules&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;js&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;exclude&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;loader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;babel-loader&quot;&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;presets&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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;useBuiltIns&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;usage&quot;&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;targets&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;esmodules&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;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;br /&gt;      cssRule&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;  plugins&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;Notice that instead of using the &lt;code&gt;targets&lt;/code&gt; value for &lt;code&gt;&amp;quot;@babel/preset-env&amp;quot;&lt;/code&gt;,
&lt;code&gt;esmodules&lt;/code&gt; with a value of &lt;code&gt;false&lt;/code&gt; is used instead. This means that Babel
includes all the necessary transforms and polyfills to target every browser that does
not yet support ES modules.&lt;/p&gt;
&lt;p&gt;Add &lt;code&gt;entry&lt;/code&gt;, &lt;code&gt;cssRule&lt;/code&gt;, and &lt;code&gt;corePlugins&lt;/code&gt; objects to the beginning of the
&lt;code&gt;webpack.config.js&lt;/code&gt; file. These are all shared between both the module and
legacy scripts served to the browser.&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;const&lt;/span&gt; entry &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;main&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./src&quot;&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 keyword&quot;&gt;const&lt;/span&gt; cssRule &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;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;css&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;use&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ExtractTextPlugin&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extract&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;fallback&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;style-loader&quot;&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;use&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;css-loader&quot;&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plugins &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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExtractTextPlugin&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 literal-property property&quot;&gt;filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[name].css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;allChunks&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;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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HtmlWebpackPlugin&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 literal-property property&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./src/index.html&quot;&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 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;Now similarly, create a config object for the module script below where &lt;code&gt;legacyConfig&lt;/code&gt; is defined:&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;const&lt;/span&gt; moduleConfig &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;  entry&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;output&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;path&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;public&quot;&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;filename&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;[name].mjs&quot;&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;module&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;rules&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 punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token literal-property property&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;&lt;span class=&quot;token special-escape escape&quot;&gt;\.&lt;/span&gt;js&lt;span class=&quot;token anchor function&quot;&gt;$&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;exclude&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token regex-source language-regex&quot;&gt;node_modules&lt;/span&gt;&lt;span class=&quot;token regex-delimiter&quot;&gt;/&lt;/span&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;loader&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;babel-loader&quot;&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;presets&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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;useBuiltIns&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;usage&quot;&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;targets&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;esmodules&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;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 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;      cssRule&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;  plugins&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;The main difference here is that a &lt;code&gt;.mjs&lt;/code&gt; file extension is used for the output
filename. The &lt;code&gt;esmodules&lt;/code&gt; value is set to true here which means that the code
that is outputted into this module is a smaller, less compiled script that does
not go through any transformation in this example since all the features used
are already supported in browsers that support modules.&lt;/p&gt;
&lt;p&gt;At the very end of the file, export both configurations in a single array.&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;  legacyConfig&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; moduleConfig&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;Now this builds both a smaller module for browsers that support it and a larger
transpiled script for older browsers.&lt;/p&gt;
&lt;p&gt;Browsers that support modules ignore scripts with a &lt;code&gt;nomodule&lt;/code&gt; attribute.
Conversely, browsers that do not support modules ignore script elements with
&lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt;. This means you can include a module as well as a compiled
fallback. Ideally, the two versions of the application should be in &lt;code&gt;index.html&lt;/code&gt;
like this:&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.mjs&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.bundle.js&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;Browsers that support modules fetch and execute &lt;code&gt;main.mjs&lt;/code&gt; and ignore
&lt;code&gt;main.bundle.js.&lt;/code&gt; The browsers that do not support modules do the opposite.&lt;/p&gt;
&lt;p&gt;It is important to note that unlike regular scripts, module scripts are always deferred by default.
If you would like the equivalent &lt;code&gt;nomodule&lt;/code&gt; script to also be deferred and only executed after
parsing, then you&#39;ll need to add the &lt;code&gt;defer&lt;/code&gt; attribute:&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.mjs&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.bundle.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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 last thing that needs to be done here is to add the &lt;code&gt;module&lt;/code&gt; and &lt;code&gt;nomodule&lt;/code&gt;
attributes to the module and legacy script respectively, Import the
&lt;a href=&quot;https://github.com/numical/script-ext-html-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;ScriptExtHtmlWebpackPlugin&lt;/a&gt;
at the very top of &lt;code&gt;webpack.config.js&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;path&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; webpack &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;webpack&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; HtmlWebpackPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;html-webpack-plugin&quot;&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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ScriptExtHtmlWebpackPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;script-ext-html-webpack-plugin&quot;&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;/mark&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now update the &lt;code&gt;plugins&lt;/code&gt; array in the configurations to include this plugin:&lt;/p&gt;
&lt;pre&gt;
const plugins = [
  new ExtractTextPlugin({filename: &quot;[name].css&quot;, allChunks: true}),
  new HtmlWebpackPlugin({template: &quot;./src/index.html&quot;}),
  new ScriptExtHtmlWebpackPlugin({
    &lt;strong&gt;module: /\.mjs$/,
    custom: [
      {
        test: /\.js$/,
        attribute: &#39;nomodule&#39;,
        value: &#39;&#39;
    },
    ]&lt;/strong&gt;
  })
];
&lt;/pre&gt;
&lt;p&gt;These plugin settings add a &lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt; attribute for all &lt;code&gt;.mjs&lt;/code&gt; script
elements as well as a &lt;code&gt;nomodule&lt;/code&gt; attribute for all &lt;code&gt;.js&lt;/code&gt; script modules.&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; If you&#39;re having trouble understanding how to add all of these configurations to &lt;code&gt;webpack.config.js&lt;/code&gt;, take a look at the &lt;a href=&quot;https://glitch.com/edit/#!/serve-modern-code-complete?path=webpack.config.js:1:0&quot;&gt;complete version of the file&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;serving-modules-in-the-html-document&quot;&gt;Serving modules in the HTML document &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#serving-modules-in-the-html-document&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The last thing that needs to be done is to output both the legacy and modern script elements to the HTML file. Unfortunately, the plugin that creates the final HTML file, &lt;code&gt;HTMLWebpackPlugin&lt;/code&gt;, &lt;a href=&quot;https://github.com/jantimon/html-webpack-plugin/issues/782&quot; rel=&quot;noopener&quot;&gt;does not currently support&lt;/a&gt; the output of both the module and nomodule scripts. Although there are workarounds and separate plugins created to solve this problem, such as &lt;a href=&quot;https://github.com/DanielSchaffer/webpack-babel-multi-target-plugin&quot; rel=&quot;noopener&quot;&gt;BabelMultiTargetPlugin&lt;/a&gt; and &lt;a href=&quot;https://github.com/firsttris/html-webpack-multi-build-plugin&quot; rel=&quot;noopener&quot;&gt;HTMLWebpackMultiBuildPlugin&lt;/a&gt;, a simpler approach of adding the module script element manually is used for the purpose of this tutorial.&lt;/p&gt;
&lt;p&gt;Add the following to &lt;code&gt;src/index.js&lt;/code&gt; at the end of the file:&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;highlight-line&quot;&gt;    ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;form&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.mjs&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&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;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now load the application in a browser that supports modules, such as the latest
version of Chrome.&lt;/p&gt;
&lt;img alt=&quot;5.2 KB module fetched over network for newer browsers&quot; decoding=&quot;async&quot; height=&quot;100&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/7DHv0rPqfFE14Qp7OtqJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Only the module is fetched, with a much smaller bundle size due to it being
largely untranspiled! The other script element is completely ignored by the
browser.&lt;/p&gt;
&lt;p&gt;If you load the application on an older browser, only the larger, transpiled
script with all the needed polyfills and transforms are be fetched. Here is a
screenshot for all the requests made on an older version of Chrome (version
38).&lt;/p&gt;
&lt;img alt=&quot;30 KB script fetched for older browsers&quot; decoding=&quot;async&quot; height=&quot;324&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xapbFvWftJjVdsekOAFJ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-serve-modern-code/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You now understand how to use &lt;code&gt;@babel/preset-env&lt;/code&gt; to provide only the necessary
polyfills required for targeted browsers. You also know how JavaScript modules
can improve performance further by shipping two different transpiled versions of an
application. With a decent understanding of how both these techniques can cut
your bundle size down significantly, go forth and optimize!&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Remove unused code</title>
    <link href="https://web.dev/remove-unused-code/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/remove-unused-code/</id>
    <content type="html" mode="escaped">&lt;p&gt;Registries like &lt;a href=&quot;https://docs.npmjs.com/getting-started/what-is-npm&quot; rel=&quot;noopener&quot;&gt;npm&lt;/a&gt; have
transformed the JavaScript world for the better by allowing anyone to easily
download and use over &lt;em&gt;half a million&lt;/em&gt; public packages. But we often include
libraries we&#39;re not fully utilizing. To fix this issue, &lt;strong&gt;analyze your bundle&lt;/strong&gt;
to detect unused code. Then remove &lt;strong&gt;unused&lt;/strong&gt; and &lt;strong&gt;unnecessary&lt;/strong&gt; libraries.&lt;/p&gt;
&lt;h2 id=&quot;impact-on-core-web-vitals&quot;&gt;Impact on Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/remove-unused-code/#impact-on-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By removing unused code, you can improve your website&#39;s &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt;. &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint&lt;/a&gt;, for example, can be affected by unused code by increased bandwidth contention caused by larger than necessary assets. LCP can also be affected if large JavaScript assets that render markup solely on the client &lt;a href=&quot;https://web.dev/preload-scanner/#rendering-markup-with-client-side-javascript&quot;&gt;contain references to LCP candidates&lt;/a&gt; by &lt;a href=&quot;https://web.dev/optimize-lcp/#1-eliminate-resource-load-delay&quot;&gt;delaying when these resources can load&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Other metrics such as &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; can also be affected by unused code, because even unused JavaScript must be downloaded, parsed, compiled, and then executed. The unused code can introduce unnecessary delays in resource load time, memory usage, and main thread activity that contribute to poor page responsiveness.&lt;/p&gt;
&lt;p&gt;This guide will help you get a handle on your project&#39;s unused code by showing you how to analyze your project&#39;s codebase, and offer strategies for pruning unused code from the JavaScript assets you ship to your users in production.&lt;/p&gt;
&lt;h2 id=&quot;analyze-your-bundle&quot;&gt;Analyze your bundle &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/remove-unused-code/#analyze-your-bundle&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;DevTools makes it easy to see the size of all network requests:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Reload the page.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Network panel with bundle request&quot; decoding=&quot;async&quot; height=&quot;169&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/aq6QZj5p4KTuaWnUJnLC.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The &lt;a href=&quot;https://developer.chrome.com/docs/devtools/coverage/&quot; rel=&quot;noopener&quot;&gt;Coverage&lt;/a&gt;
tab in DevTools will also tell you how much CSS and JS code in your application
is unused.&lt;/p&gt;
&lt;img alt=&quot;Code Coverage in DevTools&quot; decoding=&quot;async&quot; height=&quot;562&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xlPdOMaeykJhYqGcaMJr.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;By specifying a full Lighthouse configuration through its Node CLI, an &amp;quot;Unused
JavaScript&amp;quot; audit can also be used to trace how much unused code is being
shipped with your application.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse Unused JS Audit&quot; decoding=&quot;async&quot; height=&quot;347&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/tdC0d65gEIiHZy6eyo82.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;If you happen to be using &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; as your bundler,
&lt;a href=&quot;https://github.com/webpack-contrib/webpack-bundle-analyzer&quot; rel=&quot;noopener&quot;&gt;Webpack Bundle Analyzer&lt;/a&gt;
will help you investigate what makes up the bundle. Include the plugin in your
webpack configurations file like any other plugin:&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BundleAnalyzerPlugin&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Although webpack is commonly used to build single-page applications, other
bundlers, such as &lt;a href=&quot;https://parceljs.org/&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt; and
&lt;a href=&quot;https://rollupjs.org/guide/en&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt;, also have visualization tools that you
can use to analyze your bundle.&lt;/p&gt;
&lt;p&gt;Reloading the application with this plugin included shows a zoomable treemap of
your entire bundle.&lt;/p&gt;
&lt;img alt=&quot;Webpack Bundle Analyzer&quot; decoding=&quot;async&quot; height=&quot;468&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/pLAHEtl5C011wTk2IJij.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Using this visualization allows you to inspect which parts of your bundle are
larger than others, as well as get a better idea of all the libraries that
you&#39;re importing. This can help identify if you are using any unused or
unnecessary libraries.&lt;/p&gt;
&lt;h2 id=&quot;remove-unused-libraries&quot;&gt;Remove unused libraries &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/remove-unused-code/#remove-unused-libraries&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the previous treemap image, there are quite a few packages within a single
&lt;code&gt;@firebase&lt;/code&gt; domain. If your website only needs the firebase database component,
update the imports to fetch that library:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; firebase &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; firebase &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/app&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/database&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;It is important to emphasize that this process is significantly more complex for
larger applications.&lt;/p&gt;
&lt;p&gt;For the mysterious looking package that you&#39;re quite sure is not being used
anywhere, take a step back and see which of your top-level dependencies are
using it. Try to find a way to only import the components that you need from it.
If you aren&#39;t using a library, remove it.  If the library isn&#39;t required for the
initial page load, consider if it can be &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;lazy loaded&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And in case you&#39;re using webpack, check out &lt;a href=&quot;https://github.com/GoogleChromeLabs/webpack-libs-optimizations&quot; rel=&quot;noopener&quot;&gt;the list of plugins
that automatically remove unused code from popular libraries&lt;/a&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://web.dev/codelab-remove-unused-code&quot;&gt;Remove unused code.&lt;/a&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;remove-unnecessary-libraries&quot;&gt;Remove unnecessary libraries &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/remove-unused-code/#remove-unnecessary-libraries&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Not all libraries can be easily broken down into parts and selectively imported.
In these scenarios, consider if the library could be removed entirely. Building
a custom solution or leveraging a lighter alternative should always be options
worth considering. However, it is important to weigh the complexity and effort
required for either of these efforts before removing a library entirely from an
application.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Reduce JavaScript payloads with code splitting</title>
    <link href="https://web.dev/reduce-javascript-payloads-with-code-splitting/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/reduce-javascript-payloads-with-code-splitting/</id>
    <content type="html" mode="escaped">&lt;p&gt;Nobody likes waiting.
&lt;strong&gt;&lt;a href=&quot;https://www.thinkwithgoogle.com/intl/en-154/insights-inspiration/research-data/need-mobile-speed-how-mobile-latency-impacts-publisher-revenue/&quot; rel=&quot;noopener&quot;&gt;Over 50% of users abandon a website if it takes longer than 3 seconds to load&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Sending large JavaScript payloads impacts the speed of your site
significantly. Instead of shipping all the JavaScript to your user as soon as
the first page of your application is loaded, split your bundle into
multiple pieces and only send what&#39;s necessary at the very beginning.&lt;/p&gt;
&lt;h2 id=&quot;why-is-code-splitting-beneficial&quot;&gt;Why is code splitting beneficial? &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/#why-is-code-splitting-beneficial&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Code splitting is a technique that seeks to minimize startup time. When we ship less JavaScript at startup, we can get applications to be &lt;a href=&quot;https://web.dev/tti/&quot;&gt;interactive faster&lt;/a&gt; by minimizing main thread work during this critical period.&lt;/p&gt;
&lt;p&gt;When it comes to &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt;, reducing JavaScript payloads downloaded at startup will contribute to better &lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint (INP)&lt;/a&gt; times. The reasoning behind this is that, by freeing up the main thread, the application is able to respond to user inputs more quickly by reducing JavaScript parse, compile, and execution-related startup costs.&lt;/p&gt;
&lt;p&gt;Depending on your website&#39;s architecture—particularly if your website relies heavily on client-side rendering—reducing the size of JavaScript payloads responsible for rendering markup may lead to improved &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt; times. This can occur when the LCP resource is &lt;a href=&quot;https://web.dev/optimize-lcp/#optimize-when-the-resource-is-discovered&quot;&gt;delayed in being discovered by the browser&lt;/a&gt; until after client-side markup is completed, or when the main thread is too busy to &lt;a href=&quot;https://web.dev/optimize-lcp/#2-eliminate-element-render-delay&quot;&gt;render that LCP element&lt;/a&gt;. Both scenarios can delay the LCP time for the page.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-tertiary-box-bg color-tertiary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; role=&quot;img&quot; aria-label=&quot;Lightbulb&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path d=&quot;M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6A4.997 4.997 0 017 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Important&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; If your website relies on client-side rendering exclusively, you should seek to use &lt;a href=&quot;https://web.dev/rendering-on-the-web/#server-rendering&quot;&gt;Server-Side Rendering (SSR)&lt;/a&gt; to ensure that the server is sending meaningful markup to the client in response to the navigation request. This can help &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;the browser preload scanner&lt;/a&gt; to opportunistically fetch resources &lt;a href=&quot;https://web.dev/preload-scanner/#rendering-markup-with-client-side-javascript&quot;&gt;more effectively&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse displays a failed audit when a significant amount of time is taken to
execute all the JavaScript on a page.&lt;/p&gt;
&lt;img alt=&quot;A failing Lighthouse audit showing scripts taking too long to execute.&quot; decoding=&quot;async&quot; height=&quot;100&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 797px) 797px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/p0Ahh3pzXog3jPdDp6La.png?auto=format&amp;w=1594 1594w&quot; width=&quot;797&quot; /&gt;
&lt;p&gt;Split the JavaScript bundle to only send the code needed for the initial route when the
user loads an application. This minimizes the amount of script that needs to be
parsed and compiled, which results in faster page load times.&lt;/p&gt;
&lt;p&gt;Popular module bundlers like &lt;a href=&quot;https://webpack.js.org/guides/code-splitting/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt;,
&lt;a href=&quot;https://parceljs.org/code_splitting.html&quot; rel=&quot;noopener&quot;&gt;Parcel&lt;/a&gt;, and
&lt;a href=&quot;https://rollupjs.org/guide/en#dynamic-import&quot; rel=&quot;noopener&quot;&gt;Rollup&lt;/a&gt; allow you to split your
bundles using &lt;a href=&quot;https://v8.dev/features/dynamic-import&quot; rel=&quot;noopener&quot;&gt;dynamic imports&lt;/a&gt;.
For example, consider the following code snippet that shows an example of a
&lt;code&gt;someFunction&lt;/code&gt; method that gets fired when a form is submitted.&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;import&lt;/span&gt; moduleA &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;library&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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;span class=&quot;token function&quot;&gt;someFunction&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;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 keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;someFunction&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// uses moduleA&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 here, &lt;code&gt;someFunction&lt;/code&gt; uses a module imported from a particular library. If
this module is not being used elsewhere, the code block can be modified to use a
dynamic import to fetch it only when the form is submitted by the user.&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;highlight-line&quot;&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;library.moduleA&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// using the default export&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;someFunction&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;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;handleError&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;someFunction&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;// uses moduleA&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The code that makes up the module does not get included into the initial bundle
and is now &lt;strong&gt;lazy loaded&lt;/strong&gt;, or provided to the user only when it is needed after
the form submission. To further improve page performance, &lt;a href=&quot;https://web.dev/preload-critical-assets&quot;&gt;preload critical chunks to prioritize and fetch them sooner&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Although the previous code snippet is a simple example, lazy loading third party
dependencies is not a common pattern in larger applications. Usually, third
party dependencies are split into a separate vendor bundle that can be cached
since they don&#39;t update as often. You can read more about how the
&lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/&quot; rel=&quot;noopener&quot;&gt;&lt;strong&gt;SplitChunksPlugin&lt;/strong&gt;&lt;/a&gt; can
help you do this.&lt;/p&gt;
&lt;p&gt;Splitting on the route or component level when using a client-side framework is
a simpler approach to lazy loading different parts of your application. Many
popular frameworks that use webpack provide abstractions to make lazy loading
easier than diving into the configurations yourself.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Apply instant loading with the PRPL pattern</title>
    <link href="https://web.dev/apply-instant-loading-with-prpl/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/apply-instant-loading-with-prpl/</id>
    <content type="html" mode="escaped">&lt;p&gt;PRPL is an acronym that describes a pattern used to make web pages load and
become interactive, faster:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Preload&lt;/strong&gt; the most important resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render&lt;/strong&gt; the initial route as soon as possible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-cache&lt;/strong&gt; remaining assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lazy load&lt;/strong&gt; other routes and non-critical assets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this guide, learn how each of these techniques fit together but still can be
used independently to achieve performance results.&lt;/p&gt;
&lt;h2 id=&quot;audit-your-page-with-lighthouse&quot;&gt;Audit your page with Lighthouse &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#audit-your-page-with-lighthouse&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Run Lighthouse to identify opportunities for improvement aligned with the PRPL
techniques:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Lighthouse&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Performance&lt;/strong&gt; and &lt;strong&gt;Progressive Web App&lt;/strong&gt; checkboxes.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Run Audits&lt;/strong&gt; to generate a report.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For more information, see &lt;a href=&quot;https://web.dev/discover-performance-opportunities-with-lighthouse&quot;&gt;Discover performance opportunities with Lighthouse&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;preload-critical-resources&quot;&gt;Preload critical resources &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#preload-critical-resources&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse shows the following failed audit if a certain resource is parsed and
fetched late:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: Preload key requests audit&quot; decoding=&quot;async&quot; height=&quot;97&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 745px) 745px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/tgcMfl3HJLmdoERFn7Ji.png?auto=format&amp;w=1490 1490w&quot; width=&quot;745&quot; /&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Preloading_content&quot; rel=&quot;noopener&quot;&gt;&lt;strong&gt;Preload&lt;/strong&gt;&lt;/a&gt;
is a declarative fetch request that tells the browser to request a resource as
soon as possible. Preload critical resources by adding a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag with
&lt;code&gt;rel=&amp;quot;preload&amp;quot;&lt;/code&gt; to the head of your HTML document:&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;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;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;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;css/style.css&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 browser sets a more appropriate priority level for the resource in order to
try to download it sooner while not delaying the &lt;code&gt;window.onload&lt;/code&gt; event.&lt;/p&gt;
&lt;p&gt;For more information about preloading critical resources, refer to the
&lt;a href=&quot;https://web.dev/preload-critical-assets&quot;&gt;Preload critical assets&lt;/a&gt; guide.&lt;/p&gt;
&lt;h2 id=&quot;render-the-initial-route-as-soon-as-possible&quot;&gt;Render the initial route as soon as possible &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#render-the-initial-route-as-soon-as-possible&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse provides a warning if there are resources that delay &lt;a href=&quot;https://web.dev/user-centric-performance-metrics/#important-metrics-to-measure&quot;&gt;&lt;strong&gt;First Paint&lt;/strong&gt;&lt;/a&gt;,
the moment when your site renders pixels to the screen:&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: Eliminate render-blocking resources audit&quot; decoding=&quot;async&quot; height=&quot;111&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/gvj0jlCYbMdpLNtHu0Ji.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;To improve First Paint, Lighthouse recommends inlining critical JavaScript and
deferring the rest using
&lt;a href=&quot;https://web.dev/critical-rendering-path-adding-interactivity-with-javascript/&quot;&gt;&lt;code&gt;async&lt;/code&gt;&lt;/a&gt;,
as well as inlining critical CSS used above-the-fold. This improves performance
by eliminating round-trips to the server to fetch render-blocking assets.
However, inline code is harder to maintain from a development perspective and
cannot be cached separately by the browser.&lt;/p&gt;
&lt;p&gt;Another approach to improve First Paint is to &lt;strong&gt;server-side render&lt;/strong&gt; the initial
HTML of your page. This displays content immediately to the user while scripts
are still being fetched, parsed, and executed. However, this can increase the
payload of the HTML file significantly, which can harm &lt;a href=&quot;https://web.dev/tti/&quot;&gt;&lt;strong&gt;Time to Interactive&lt;/strong&gt;&lt;/a&gt;,
or the time it takes for your application to become interactive and can respond
to user input.&lt;/p&gt;
&lt;p&gt;There is no single correct solution to reduce the First Paint in your
application, and you should only consider inlining styles and server-side
rendering if the benefits outweigh the tradeoffs for your application. You can
learn more about both of these concepts with the following resources.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery&quot; rel=&quot;noopener&quot;&gt;Optimize CSS Delivery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=GQzn7XRdzxY&quot; rel=&quot;noopener&quot;&gt;What is Server-Side Rendering?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure data-float=&quot;right&quot;&gt;
  &lt;img alt=&quot;Requests/responses with service worker&quot; decoding=&quot;async&quot; height=&quot;1224&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xv1f7ZLKeBZD83Wcw6pd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;pre-cache-assets&quot;&gt;Pre-cache assets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#pre-cache-assets&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;By acting as a proxy, &lt;strong&gt;service workers&lt;/strong&gt; can fetch assets directly from the cache
rather than the server on repeat visits. This not only allows users to use your
application when they are offline, but also results in faster page load times on
repeat visits.&lt;/p&gt;
&lt;p&gt;Use a third-party library to simplify the process of generating a service worker
unless you have more complex caching requirements than what a library can
provide. For example,
&lt;a href=&quot;https://web.dev/workbox&quot;&gt;Workbox&lt;/a&gt; provides a
collection of tools that allow you to create and maintain a service worker to
cache assets. For more information on service workers and offline reliability,
refer to the &lt;a href=&quot;https://web.dev/service-workers-cache-storage&quot;&gt;service worker guide&lt;/a&gt; in the reliability learning path.&lt;/p&gt;
&lt;h2 id=&quot;lazy-load&quot;&gt;Lazy load &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#lazy-load&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse displays a failed audit if you send too much data over the network.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: Has enormous network payloads audit&quot; decoding=&quot;async&quot; height=&quot;99&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Ml4hOCqfD4kGWfuKYVTN.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;This includes all asset types, but large JavaScript payloads are especially
costly due to the time it takes the browser to parse and compile them.
Lighthouse also provides a warning for this when appropriate.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: JavaScript boot-up time audit&quot; decoding=&quot;async&quot; height=&quot;100&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 797px) 797px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/aKDCV8qv3nuTVFt0Txyj.png?auto=format&amp;w=1594 1594w&quot; width=&quot;797&quot; /&gt;
&lt;p&gt;To send a smaller JavaScript payload that contains only the code needed when a
user initially loads your application, split the entire bundle and &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;lazy load&lt;/a&gt; chunks on demand.&lt;/p&gt;
&lt;p&gt;Once you&#39;ve managed to split your bundle, preload the chunks that are more
important (see the &lt;a href=&quot;https://web.dev/preload-critical-assets&quot;&gt;Preload critical assets&lt;/a&gt; guide).
Preloading ensures more important resources are fetched and downloaded sooner
by the browser.&lt;/p&gt;
&lt;p&gt;Aside from splitting and loading different JavaScript chunks on demand,
Lighthouse also provides an audit for lazy loading non-critical images.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: Defer offscreen images audit&quot; decoding=&quot;async&quot; height=&quot;90&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/sEgLhoYadRCtKFCYVM1d.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;If you load many images on your web page, defer all that are below the fold, or
outside the device viewport, when a page is loaded (see &lt;a href=&quot;https://web.dev/use-lazysizes-to-lazyload-images&quot;&gt;Use lazysizes to lazyload images&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id=&quot;next-steps&quot;&gt;Next Steps &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/apply-instant-loading-with-prpl/#next-steps&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Now that you understand some of the basic concepts behind the PRPL pattern,
continue to the next guide in this section to learn more.
It&#39;s important to remember that not all of the techniques need to be
applied together. Any efforts made with any of the following will provide
noticeable performance improvements.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Preload&lt;/strong&gt; critical resources.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Render&lt;/strong&gt; the initial route as soon as possible.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pre-cache&lt;/strong&gt; remaining assets.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lazy load&lt;/strong&gt; other routes and non-critical assets.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can read up more about &lt;a href=&quot;https://www.patterns.dev/posts/prpl/&quot; rel=&quot;noopener&quot;&gt;PRPL&lt;/a&gt; patterns.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Replace animated GIFs with video for faster page loads</title>
    <link href="https://web.dev/replace-gifs-with-videos/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/replace-gifs-with-videos/</id>
    <content type="html" mode="escaped">&lt;p&gt;Have you ever seen an animated GIF on a service like Imgur or Gfycat, inspected
it in your dev tools, only to find out that GIF was really a video? There&#39;s a
good reason for that. Animated GIFs can be downright &lt;em&gt;huge&lt;/em&gt;.&lt;/p&gt;
&lt;img alt=&quot;DevTools network panel showing a 13.7 MB gif.&quot; decoding=&quot;async&quot; height=&quot;155&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/3UZ0b9dDotVIXWQT5Auk.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Thankfully, this is one of those areas of loading performance where you can do
relatively little work to realize huge gains! &lt;strong&gt;By converting large GIFs to
videos, you can save big on users&#39; bandwidth&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&quot;measure-first&quot;&gt;Measure first &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#measure-first&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Use Lighthouse to check your site for GIFs that can be converted to videos. In
DevTools, click on the Audits tab and check the Performance checkbox. Then run
Lighthouse and check the report.
If you have any GIFs that can be converted, you should see a suggestion to &amp;quot;Use
video formats for animated content&amp;quot;:&lt;/p&gt;
&lt;img alt=&quot;A failing Lighthouse audit, use video formats for animated content.&quot; decoding=&quot;async&quot; height=&quot;173&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/KOSr9IivnkyaFk6RJ5u1.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;create-mpeg-videos&quot;&gt;Create MPEG videos &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#create-mpeg-videos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a number of ways to convert GIFs to video,
&lt;strong&gt;&lt;a href=&quot;https://www.ffmpeg.org/&quot; rel=&quot;noopener&quot;&gt;FFmpeg&lt;/a&gt;&lt;/strong&gt; is the tool used in this guide.
To use FFmpeg to convert the GIF, &lt;code&gt;my-animation.gif&lt;/code&gt; to an MP4 video, run the
following command in your console:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ffmpeg -i my-animation.gif -b:v &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; -crf &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This tells FFmpeg to take &lt;code&gt;my-animation.gif&lt;/code&gt; as the &lt;strong&gt;input&lt;/strong&gt;, signified by the
&lt;code&gt;-i&lt;/code&gt; flag, and to convert it to a video called &lt;code&gt;my-animation.mp4&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The libx264 encoder only works with files that have even dimensions, like 320px
by 240px. If the input GIF has odd dimensions you can include a crop filter to
avoid FFmpeg throwing a &#39;height/width not divisible by 2&#39; error:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ffmpeg -i my-animation.gif -vf &lt;span class=&quot;token string&quot;&gt;&quot;crop=trunc(iw/2)*2:trunc(ih/2)*2&quot;&lt;/span&gt; -b:v &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; -crf &lt;span class=&quot;token number&quot;&gt;25&lt;/span&gt; -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;create-webm-videos&quot;&gt;Create WebM videos &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#create-webm-videos&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;While MP4 has been around since 1999, WebM is a relatively new file format
initially released in 2010. WebM videos are much smaller than MP4 videos, but
not all browsers support WebM so it makes sense to generate both.&lt;/p&gt;
&lt;p&gt;To use FFmpeg to convert &lt;code&gt;my-animation.gif&lt;/code&gt; to a WebM video, run the following
command in your console:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;ffmpeg -i my-animation.gif -c vp9 -b:v &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; -crf &lt;span class=&quot;token number&quot;&gt;41&lt;/span&gt; my-animation.webm&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;compare-the-difference&quot;&gt;Compare the difference &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#compare-the-difference&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The cost savings between a GIF and a video can be pretty significant.&lt;/p&gt;
&lt;img alt=&quot;File size comparison showing 3.7 MB for the gif, 551 KB for the mp4 and 341 KB for the webm.&quot; decoding=&quot;async&quot; height=&quot;188&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/LWzvOWaOdMnNLTPWjayt.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In this example, the initial GIF is 3.7 MB, compared to the MP4 version, which
is 551 KB, and the WebM version, which is only 341 KB!&lt;/p&gt;
&lt;h2 id=&quot;replace-the-gif-img-with-a-video&quot;&gt;Replace the GIF img with a video &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#replace-the-gif-img-with-a-video&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Animated GIFs have three key traits that a video needs to replicate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;They play automatically.&lt;/li&gt;
&lt;li&gt;They loop continuously (usually, but it is possible to prevent looping).&lt;/li&gt;
&lt;li&gt;They&#39;re silent.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Luckily, you can recreate these behaviors using the &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;video autoplay loop muted playsinline&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;/video&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;A &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element with these attributes plays automatically, loops endlessly,
plays no audio, and plays inline (that is, not full screen), all the hallmark
behaviors expected of animated GIFs! 🎉&lt;/p&gt;
&lt;p&gt;Finally, the &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; element requires one or more &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; child elements
pointing to different video files that the browser can choose from, depending on
the browser&#39;s format support. Provide both WebM and MP4, so that if a browser
doesn&#39;t support WebM, it can fall back to MP4.&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;video&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;autoplay&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;muted&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;playsinline&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;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;my-animation.webm&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;video/webm&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;source&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;my-animation.mp4&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;video/mp4&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;video&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;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://web.dev/codelab-replace-gifs-with-video&quot;&gt;Replace an animated GIF with a video&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Browsers don&#39;t speculate about which &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; is optimal, so the order of &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt;&#39;s matters. For example, if you specify an MP4 video first and the browser supports WebM, browsers will skip the WebM &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; and use the MPEG-4 instead. If you prefer a WebM &lt;code&gt;&amp;lt;source&amp;gt;&lt;/code&gt; be used first, specify it first! &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;effect-on-largest-contentful-paint-lcp&quot;&gt;Effect on Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/replace-gifs-with-videos/#effect-on-largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;It should be noted that while &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; elements are candidates for LCP, &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements without a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/video#attr-poster&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;poster&lt;/code&gt; image&lt;/a&gt; are not &lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;LCP candidates&lt;/a&gt;. The solution in the case of emulating animated GIFs is &lt;em&gt;not&lt;/em&gt; to add &lt;code&gt;poster&lt;/code&gt; attribute to your &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; elements, because that image will go unused.&lt;/p&gt;
&lt;p&gt;What does this mean for your website? The recommendation is to stick with using a &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt; instead of an animated GIF, but with the understanding that such media will not be a candidate for LCP, and the next largest candidate will be used instead. As GIFs and &lt;code&gt;&amp;lt;video&amp;gt;&lt;/code&gt;s are typically larger and so slower to download, moving to a different LCP candidate will likely even improve the site&#39;s LCP.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Preload critical assets to improve loading speed</title>
    <link href="https://web.dev/preload-critical-assets/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/preload-critical-assets/</id>
    <content type="html" mode="escaped">&lt;p&gt;When you open a web page, the browser requests the HTML document from a server, parses its contents, and submits separate requests for any referenced resources. As a developer, you already know about all the resources your page needs and which of them are the most important. You can use that knowledge to request the critical resources ahead of time and speed up the loading process. This post explains how to achieve that with &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&quot;how-preloading-works&quot;&gt;How preloading works &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#how-preloading-works&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Preloading is best suited for resources typically discovered late by the browser.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel.&quot; decoding=&quot;async&quot; height=&quot;509&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 701px) 701px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ad9PLq3DcQt9Ycp63z6O.png?auto=format&amp;w=1402 1402w&quot; width=&quot;701&quot; /&gt;
&lt;figcaption&gt;In this example, Pacifico font is defined in the stylesheet with a &lt;a href=&quot;https://web.dev/reduce-webfont-size/#defining-a-font-family-with-@font-face)&quot;&gt;&lt;code&gt;@font-face&lt;/code&gt;&lt;/a&gt; rule. The browser loads the font file only after it has finished downloading and parsing the stylesheet.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;By preloading a certain resource, you are telling the browser that you would like to fetch it sooner than the browser would otherwise discover it because you are certain that it is important for the current page.&lt;/p&gt;
&lt;figure&gt;
&lt;img alt=&quot;Screenshot of Chrome DevTools Network panel after applying preloading.&quot; decoding=&quot;async&quot; height=&quot;509&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 701px) 701px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/PgRbERrxLGfF439yBMeY.png?auto=format&amp;w=1402 1402w&quot; width=&quot;701&quot; /&gt;
&lt;figcaption&gt;In this example, Pacifico font is preloaded, so the download happens in parallel with the stylesheet.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;The critical request chain represents the order of resources that are prioritized and fetched by the browser. Lighthouse identifies assets that are on the third level of this chain as late-discovered. You can use the &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/uses-rel-preload/&quot; rel=&quot;noopener&quot;&gt;&lt;strong&gt;Preload key requests&lt;/strong&gt;&lt;/a&gt; audit to identify which resources to preload.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse&amp;#x27;s preload key requests audit.&quot; decoding=&quot;async&quot; height=&quot;97&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 745px) 745px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/BPUTHBNZFbeXqb0dVx2f.png?auto=format&amp;w=1490 1490w&quot; width=&quot;745&quot; /&gt;
&lt;p&gt;You can preload resources by adding a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag with &lt;code&gt;rel=&amp;quot;preload&amp;quot;&lt;/code&gt; to the head of your HTML document:&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;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;script&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;critical.js&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 browser caches preloaded resources so they are available immediately when needed. (It doesn&#39;t execute the scripts or apply the stylesheets.)&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; After implementing preloading, many sites, including &lt;a href=&quot;https://medium.com/reloading/preload-prefetch-and-priorities-in-chrome-776165961bbf&quot;&gt;Shopify, Financial Times and Treebo, saw 1-second improvements&lt;/a&gt; in user-centric metrics such as &lt;a href=&quot;https://web.dev/tti/&quot;&gt;Time to Interactive&lt;/a&gt; and &lt;a href=&quot;https://web.dev/fcp/&quot;&gt;First Contentful Paint&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Resource hints, for example, &lt;a href=&quot;https://web.dev/preconnect-and-dns-prefetch&quot;&gt;&lt;code&gt;preconnect&lt;/code&gt;&lt;/a&gt;and &lt;a href=&quot;https://web.dev/link-prefetch&quot;&gt;&lt;code&gt;prefetch&lt;/code&gt;&lt;/a&gt;, are executed as the browser sees fit. The &lt;code&gt;preload&lt;/code&gt;, on the other hand, is mandatory for the browser. Modern browsers are already pretty good at prioritizing resources, that&#39;s why it&#39;s important to use &lt;code&gt;preload&lt;/code&gt; sparingly and only preload the most critical resources.&lt;/p&gt;
&lt;p&gt;Unused preloads trigger a Console warning in Chrome, approximately 3 seconds after the &lt;code&gt;load&lt;/code&gt; event.&lt;/p&gt;
&lt;img alt=&quot;Chrome DevTools Console warning about unused preloaded resources.&quot; decoding=&quot;async&quot; height=&quot;228&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/z4FbCezjXHxaIhq188TU.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; &lt;code&gt;preload&lt;/code&gt; is supported  in all modern browsers. &lt;div class=&quot;wdi-browser-compat&quot;&gt; &lt;span class=&quot;wdi-browser-compat__label&quot;&gt;Browser support&lt;/span&gt; &lt;ul class=&quot;wdi-browser-compat__items&quot;&gt; &lt;li class=&quot;wdi-browser-compat__item&quot;&gt; &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;chrome&quot;&gt; &lt;span class=&quot;visually-hidden&quot;&gt;Chrome 50, Supported&lt;/span&gt; &lt;/span&gt; &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt; 50 &lt;/span&gt; &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt; &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;firefox&quot;&gt; &lt;span class=&quot;visually-hidden&quot;&gt;Firefox 85, Supported&lt;/span&gt; &lt;/span&gt; &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt; 85 &lt;/span&gt; &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt; &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;edge&quot;&gt; &lt;span class=&quot;visually-hidden&quot;&gt;Edge ≤79, Supported&lt;/span&gt; &lt;/span&gt; &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;yes&quot; title=&quot;Supported&quot; aria-label=&quot;Supported&quot;&gt; ≤79 &lt;/span&gt; &lt;/li&gt;&lt;li class=&quot;wdi-browser-compat__item&quot;&gt; &lt;span class=&quot;wdi-browser-compat__icon&quot; data-browser=&quot;safari&quot;&gt; &lt;span class=&quot;visually-hidden&quot;&gt;Safari, Not supported&lt;/span&gt; &lt;/span&gt; &lt;span class=&quot;wdi-browser-compat__version&quot; data-compat=&quot;no&quot; title=&quot;Not supported&quot; aria-label=&quot;Not supported&quot;&gt;  &lt;/span&gt; &lt;/li&gt; &lt;/ul&gt; &lt;a class=&quot;wdi-browser-compat__link&quot; href=&quot;https://developer.mozilla.org/docs/Web/HTML/Link_types/preload#browser_compatibility&quot; target=&quot;_blank&quot;&gt;Source&lt;/a&gt; &lt;/div&gt; &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;use-cases&quot;&gt;Use cases &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#use-cases&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; At the time of writing, Chrome has an open &lt;a href=&quot;https://bugs.chromium.org/p/chromium/issues/detail?id=788757&quot;&gt;bug&lt;/a&gt; for preloaded requests that are fetched sooner than other higher priority resources. Until this is resolved, be wary of how preloaded resources can &amp;quot;jump the queue&amp;quot; and be requested sooner than they should. &lt;/div&gt;&lt;/aside&gt;
&lt;h3 id=&quot;preloading-resources-defined-in-css&quot;&gt;Preloading resources defined in CSS &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#preloading-resources-defined-in-css&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Fonts defined with &lt;a href=&quot;https://web.dev/reduce-webfont-size/#defining-a-font-family-with-@font-face&quot;&gt;&lt;code&gt;@font-face&lt;/code&gt;&lt;/a&gt; rules or background images defined in CSS files aren&#39;t discovered until the browser downloads and parses those CSS files. Preloading these resources ensures they are fetched before the CSS files have downloaded.&lt;/p&gt;
&lt;h3 id=&quot;preloading-css-files&quot;&gt;Preloading CSS files &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#preloading-css-files&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are using the &lt;a href=&quot;https://web.dev/extract-critical-css&quot;&gt;critical CSS approach&lt;/a&gt;, you split your CSS into two parts. The critical CSS required for rendering the above-the-fold content is inlined in the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the document and non-critical CSS is usually lazy-loaded with JavaScript. Waiting for JavaScript to execute before loading non-critical CSS can cause delays in rendering when users scroll, so it&#39;s a good idea to use &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt; to initiate the download sooner.&lt;/p&gt;
&lt;h3 id=&quot;preloading-javascript-files&quot;&gt;Preloading JavaScript files &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#preloading-javascript-files&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Because browsers don&#39;t execute preloaded files, preloading is useful to separate fetching from &lt;a href=&quot;https://developer.chrome.com/docs/lighthouse/performance/bootup-time/&quot; rel=&quot;noopener&quot;&gt;execution&lt;/a&gt; which can improve metrics such as Time to Interactive. Preloading works best if you &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting&quot;&gt;split&lt;/a&gt; your JavaScript bundles and only preload critical chunks.&lt;/p&gt;
&lt;h2 id=&quot;how-to-implement-rel=preload&quot;&gt;How to implement rel=preload &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#how-to-implement-rel=preload&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The simplest way to implement &lt;code&gt;preload&lt;/code&gt; is to add a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tag to the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; of the document:&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;head&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;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;preload&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;script&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;critical.js&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;head&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;Supplying the &lt;code&gt;as&lt;/code&gt; attribute helps the browser set the priority of the prefetched resource according to its type, set the right headers, and determine whether the resource already exists in the cache. Accepted values for this attribute include: &lt;code&gt;script&lt;/code&gt;, &lt;code&gt;style&lt;/code&gt;, &lt;code&gt;font&lt;/code&gt;, &lt;code&gt;image&lt;/code&gt;, and &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/link#Attributes&quot; rel=&quot;noopener&quot;&gt;others&lt;/a&gt;.&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; Take a look at the &lt;a href=&quot;https://docs.google.com/document/d/1bCDuq9H1ih9iNjgzyAL0gpwNFiEP4TZS-YLRp_RuMlc/edit&quot;&gt;Chrome Resource Priorities and Scheduling&lt;/a&gt; document to learn more about how the browser prioritizes different types of resources. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Omitting the &lt;code&gt;as&lt;/code&gt; attribute, or having an invalid value is equivalent to an &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/XMLHttpRequest&quot;&gt;XHR request,&lt;/a&gt; where the browser doesn&#39;t know what it is fetching so it can&#39;t determine the correct priority. It can also cause some resources, such as scripts, to be fetched twice. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Some types of resources, such as fonts, are loaded in &lt;a href=&quot;https://www.w3.org/TR/css-fonts-3/#font-fetching-requirements&quot; rel=&quot;noopener&quot;&gt;anonymous mode&lt;/a&gt;. For those you must set the &lt;code&gt;crossorigin&lt;/code&gt; attribute with &lt;code&gt;preload&lt;/code&gt;:&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;preload&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;ComicSans.woff2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;as&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;font&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;font/woff2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;crossorigin&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;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Fonts preloaded without the &lt;code&gt;crossorigin&lt;/code&gt; attribute will be fetched twice! &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; elements also accept a &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTML/Element/link#attr-type&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;type&lt;/code&gt; attribute&lt;/a&gt;, which contains the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/MIME_types&quot; rel=&quot;noopener&quot;&gt;MIME type&lt;/a&gt; of the linked resource. The browsers use the value of the &lt;code&gt;type&lt;/code&gt; attribute to make sure that resources get preloaded only if their file type is supported. If a browser doesn&#39;t support the specified resource type, it will ignore the &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; &lt;a href=&quot;https://web.dev/codelab-preload-web-fonts&quot;&gt;Improve the performance of a page by preloading web fonts&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;You can also preload any type of resource via the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers/Link&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;Link&lt;/code&gt; HTTP header&lt;/a&gt;:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Link: &amp;lt;/css/style.css&amp;gt;; rel=&amp;quot;preload&amp;quot;; as=&amp;quot;style&amp;quot;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;A benefit of specifying &lt;code&gt;preload&lt;/code&gt; in the HTTP Header is that the browser doesn&#39;t need to parse the document to discover it, which can offer small improvements in some cases.&lt;/p&gt;
&lt;h3 id=&quot;preloading-javascript-modules-with-webpack&quot;&gt;Preloading JavaScript modules with webpack &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#preloading-javascript-modules-with-webpack&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;If you are using a module bundler that creates build files of your application, you need to check if it supports the injection of preload tags. With &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; version 4.6.0 or later, preloading is supported through the use of &lt;a href=&quot;https://webpack.js.org/api/module-methods/#magic-comments&quot; rel=&quot;noopener&quot;&gt;magic comments&lt;/a&gt; inside &lt;code&gt;import()&lt;/code&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;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_&lt;span class=&quot;token comment&quot;&gt;/* webpackPreload: true */&lt;/span&gt;_ &lt;span class=&quot;token string&quot;&gt;&quot;CriticalChunk&quot;&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 are using an older version of webpack, use a third-party plugin such as &lt;a href=&quot;https://github.com/GoogleChromeLabs/preload-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;preload-webpack-plugin&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;effects-of-preloading-on-core-web-vitals&quot;&gt;Effects of preloading on Core Web Vitals &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#effects-of-preloading-on-core-web-vitals&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Preloading is a powerful performance optimization that has an effect on loading speed. Such optimizations can lead to changes in your site&#39;s &lt;a href=&quot;https://web.dev/vitals/&quot;&gt;Core Web Vitals&lt;/a&gt;, and it&#39;s important to be aware them.&lt;/p&gt;
&lt;h3 id=&quot;largest-contentful-paint-lcp&quot;&gt;Largest Contentful Paint (LCP) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#largest-contentful-paint-lcp&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Preloading has a powerful effect on &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;Largest Contentful Paint (LCP)&lt;/a&gt; when it comes to fonts and images, as both images and text nodes can be &lt;a href=&quot;https://web.dev/lcp/#what-elements-are-considered&quot;&gt;LCP candidates&lt;/a&gt;. Hero images and large runs of text that are rendered using web fonts can benefit significantly from a well-placed preload hint, and should be used when there are opportunities to deliver these important bits of content to the user faster.&lt;/p&gt;
&lt;p&gt;However, you want to be careful when it comes to preloading—and other optimizations! In particular, avoid preloading too many resources. If too many resources are prioritized, effectively none of them are. The effects of excessive preload hints will be especially detrimental to those on slower networks where bandwidth contention will be more evident.&lt;/p&gt;
&lt;p&gt;Instead, focus on a few high-value resources that you know will benefit from a well-placed preload. When preloading fonts, ensure that you&#39;re serving fonts in WOFF 2.0 format to reduce resource load time as much as possible. Since WOFF 2.0 has &lt;a href=&quot;https://caniuse.com/woff2&quot; rel=&quot;noopener&quot;&gt;excellent browser support&lt;/a&gt;, using older formats such as WOFF 1.0 or TrueType (TTF) will delay your LCP if the LCP candidate is a text node.&lt;/p&gt;
&lt;p&gt;When it comes to LCP and JavaScript, you&#39;ll want to ensure that you&#39;re sending complete markup from the server in order for the &lt;a href=&quot;https://web.dev/preload-scanner/&quot;&gt;browser&#39;s preload scanner&lt;/a&gt; to work properly. If you&#39;re serving up an experience that relies entirely on JavaScript to render markup and can&#39;t send server-rendered HTML, it would be advantageous to step in where the browser preload scanner can&#39;t and preload resources that would only otherwise be discoverable when the JavaScript finishes loading and executing.&lt;/p&gt;
&lt;h3 id=&quot;cumulative-layout-shift-cls&quot;&gt;Cumulative Layout Shift (CLS) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#cumulative-layout-shift-cls&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/cls/&quot;&gt;Cumulative Layout Shift (CLS)&lt;/a&gt; is an especially important metric where web fonts are concerned, and CLS has significant interplay with web fonts that use the &lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/@font-face/font-display&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;font-display&lt;/code&gt; CSS property&lt;/a&gt; to manage how fonts are loaded. To minimize web font-related layout shifts, consider the following strategies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Preload fonts while using the default &lt;code&gt;block&lt;/code&gt; value for &lt;code&gt;font-display&lt;/code&gt;.&lt;/strong&gt; This is a delicate balance. Blocking the display of fonts without a fallback can be considered a user experience problem. On one hand, loading fonts with &lt;code&gt;font-display: block;&lt;/code&gt; eliminates web font-related layout shifts. On the other hand, you still want to get those web fonts loaded as soon as possible if they&#39;re crucial to the user experience. Combining a preload with &lt;code&gt;font-display: block;&lt;/code&gt; may be an acceptable compromise.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Preload fonts while using the &lt;code&gt;fallback&lt;/code&gt; value for &lt;code&gt;font-display&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;fallback&lt;/code&gt; is a compromise between &lt;code&gt;swap&lt;/code&gt; and &lt;code&gt;block&lt;/code&gt;, in that it has an extremely short blocking period.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use the &lt;code&gt;optional&lt;/code&gt; value for &lt;code&gt;font-display&lt;/code&gt; without a preload.&lt;/strong&gt; If a web font isn&#39;t crucial to the user experience, but it is still used to render a significant amount of page text, consider using the &lt;code&gt;optional&lt;/code&gt; value. In adverse conditions, &lt;code&gt;optional&lt;/code&gt; will display page text in a fallback font while it loads the font in the background for the next navigation. The net result in these conditions is improved CLS, as system fonts will render immediately, while subsequent page loads will load the font immediately without layout shifts.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;CLS is a difficult metric to optimize for when it comes to web fonts. As always, experiment in the &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#lab-data&quot;&gt;lab&lt;/a&gt;, but trust your &lt;a href=&quot;https://web.dev/lab-and-field-data-differences/#field-data&quot;&gt;field data&lt;/a&gt; to determine if your font loading strategies are improving CLS or making it worse.&lt;/p&gt;
&lt;h3 id=&quot;responsiveness-metrics&quot;&gt;Responsiveness metrics &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#responsiveness-metrics&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://web.dev/fid/&quot;&gt;First Input Delay (FID)&lt;/a&gt; and &lt;a href=&quot;https://web.dev/inp/&quot;&gt;Interaction to Next Paint&lt;/a&gt; are two metrics that gauge responsiveness to user input. Since the lion&#39;s share of interactivity on the web is driven by JavaScript, preloading JavaScript that powers important interactions may help to keep your FID and INP metrics as low as they can possibly be. However, be aware that FID is a load responsiveness metric and INP observes interactions throughout the entire page lifecycle—including during startup. Preloading too much JavaScript during startup can carry unintended negative consequences if too many resources are contending for bandwidth.&lt;/p&gt;
&lt;p&gt;You&#39;ll also want to be careful about how you go about &lt;a href=&quot;https://web.dev/reduce-javascript-payloads-with-code-splitting/&quot;&gt;code splitting&lt;/a&gt;. Code splitting is an excellent optimization for reducing the amount of JavaScript loaded during startup, but interactions can be delayed if they rely on JavaScript loaded right at the start of the interaction. To compensate for this, you&#39;ll need to examine the user&#39;s intent, and inject a preload for the necessary chunk(s) of JavaScript before the interaction takes place. One example could be preloading JavaScript required for validating a form&#39;s contents when any of the fields in the form are focused.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/preload-critical-assets/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;To improve page speed, preload important resources that are discovered late by the browser. Preloading everything would be counterproductive so use &lt;code&gt;preload&lt;/code&gt; sparingly and &lt;a href=&quot;https://web.dev/fast#measure-performance-in-the-field&quot;&gt;measure the impact in the real-world&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author><author>
      <name>Milica Mihajlija</name>
    </author><author>
      <name>Jeremy Wagner</name>
    </author>
  </entry>
  
  <entry>
    <title>Serve modern code to modern browsers for faster page loads</title>
    <link href="https://web.dev/serve-modern-code-to-modern-browsers/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/serve-modern-code-to-modern-browsers/</id>
    <content type="html" mode="escaped">&lt;p&gt;Building websites that work well on all major browsers is a core tenet of an
open web ecosystem. However, this means additional work of ensuring that all of
the code you write is supported in each browser that you plan to target. If you
want to use new JavaScript language features, you need to transpile these
features to backwards-compatible formats for browsers that do not yet support
them.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://babeljs.io/docs/en&quot; rel=&quot;noopener&quot;&gt;Babel&lt;/a&gt; is the most widely used tool to compile code
that contains newer syntax into code that different browsers and environments
(such as Node) can understand. This guide assumes you are using Babel, so you
need to follow the &lt;a href=&quot;https://babeljs.io/setup&quot; rel=&quot;noopener&quot;&gt;setup instructions&lt;/a&gt; to
include it into your application if you haven&#39;t already. Select &lt;code&gt;webpack&lt;/code&gt;
in &lt;code&gt;Build Systems&lt;/code&gt; if you are using webpack as the module bundler in your app.&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; Fun fact: Lebab is a separate library that does the opposite of what Babel does. It converts older code into newer syntax. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;To use Babel to only transpile what is needed for your users, you
need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Identify which browsers you want to target.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;@babel/preset-env&lt;/code&gt; with appropriate browser targets.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt; to stop sending transpiled code to browsers that don&#39;t need it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;identify-which-browsers-you-want-to-target&quot;&gt;Identify which browsers you want to target &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/#identify-which-browsers-you-want-to-target&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Before you begin to modify how the code in your application is transpiled, you
need to identify which browsers access your application. Analyze which browsers
your users are currently using as well as those that you plan to target to make an
informed decision.&lt;/p&gt;
&lt;h2 id=&quot;use-babelpreset-env&quot;&gt;Use @babel/preset-env &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/#use-babelpreset-env&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Transpiling code usually results in a file that is larger in file size than
their original forms. By minimizing the amount of compilation that you do you
can reduce the size of your bundles to improve the performance of a web page.&lt;/p&gt;
&lt;p&gt;Instead of including specific plugins to selectively compile certain language
features you are using, Babel provides a number of presets that bundles plugins
together. Use &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env&quot; rel=&quot;noopener&quot;&gt;@babel/preset-env&lt;/a&gt;
to only include the transforms and polyfills needed for the browsers you plan on
targeting.&lt;/p&gt;
&lt;p&gt;Include &lt;code&gt;@babel/preset-env&lt;/code&gt; within the &lt;code&gt;presets&lt;/code&gt; array in your Babel
configurations file, &lt;code&gt;.babelrc&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;presets&quot;&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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 property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;&gt;0.25%&quot;&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;Use the &lt;code&gt;targets&lt;/code&gt; field to specify which browser versions you want to include
by adding an appropriate query to the &lt;code&gt;browsers&lt;/code&gt; field. &lt;code&gt;@babel/preset-env&lt;/code&gt;
integrates with browserslist, an open-source configuration shared between different
tools for targeting browsers. A full list of compatible queries is in the
&lt;a href=&quot;https://github.com/browserslist/browserslist#full-list&quot; rel=&quot;noopener&quot;&gt;browserslist documentation&lt;/a&gt;.
Another option is to use a &lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#browserslist-integration&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;.browserslistrc&lt;/code&gt;&lt;/a&gt; file to list the environments
you wish to target.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;&amp;quot;&amp;gt;0.25%&amp;quot;&lt;/code&gt; value tells Babel to only include the transforms
needed to support browsers that make up more than 0.25% of global
usage. This ensures your bundle does not contain unnecessary transpiled
code for browsers that are used by a very small percentage of users.&lt;/p&gt;
&lt;p&gt;In most cases, this is a better approach than using the following
configuration:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;targets&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;last 2 versions&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;quot;last 2 versions&amp;quot;&lt;/code&gt; value transpiles your code for the
&lt;a href=&quot;http://browserl.ist/?q=last+2+versions&quot; rel=&quot;noopener&quot;&gt;last two versions&lt;/a&gt; of every browser,
which means support is provided for discontinued browsers such as Internet Explorer.
This can unnecessarily increase the size of your bundle if you do not expect these
browsers to be used to access your application.&lt;/p&gt;
&lt;p&gt;Ultimately, you should select the appropriate combination of queries to only
target browsers that fit your needs.&lt;/p&gt;
&lt;h3 id=&quot;enable-modern-bugfixes&quot;&gt;Enable modern bugfixes &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/#enable-modern-bugfixes&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;@babel/preset-env&lt;/code&gt; groups multiple JavaScript syntax features into collections and enables/disables
them based on the target browsers specified. Although this works well, an entire collection of
syntax features is transformed when a targeted browser contains a bug with just a single feature.
This often results in more transformed code than is necessary.&lt;/p&gt;
&lt;p&gt;Originally developed as a &lt;a href=&quot;https://github.com/babel/preset-modules&quot; rel=&quot;noopener&quot;&gt;separate preset&lt;/a&gt;, the
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#bugfixes&quot; rel=&quot;noopener&quot;&gt;bugfixes option&lt;/a&gt; in &lt;code&gt;@babel/preset-env&lt;/code&gt;
solves this problem by converting modern syntax that is broken in some browsers to the closest
equivalent syntax that is not broken in those browsers. The result is nearly identical modern code
with a few small syntax tweaks that guarantee compatibility in all target browsers. To use this
optimization, make sure you have &lt;code&gt;@babel/preset-env&lt;/code&gt; 7.10 or later installed, then set the
&lt;a href=&quot;https://babeljs.io/docs/en/babel-preset-env#bugfixes&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;bugfixes&lt;/code&gt;&lt;/a&gt; property to &lt;code&gt;true&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token property&quot;&gt;&quot;presets&quot;&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;     &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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 property&quot;&gt;&quot;bugfixes&quot;&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;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 Babel 8, the &lt;code&gt;bugfixes&lt;/code&gt; option will be enabled by default.&lt;/p&gt;
&lt;h2 id=&quot;use-lessscript-type=modulegreater&quot;&gt;Use &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot;&amp;gt;&lt;/code&gt; &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/serve-modern-code-to-modern-browsers/#use-lessscript-type=modulegreater&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;JavaScript modules, or ES modules, are a relatively new feature supported in
&lt;a href=&quot;https://caniuse.com/#feat=es6-module&quot; rel=&quot;noopener&quot;&gt;all major browsers&lt;/a&gt;. You can use modules
to create scripts that can import and export from other modules, but you can
also use them with &lt;code&gt;@babel/preset-env&lt;/code&gt; to only target browsers that support
them.&lt;/p&gt;
&lt;p&gt;Instead of querying for specific browser versions or market share, consider
specifying &lt;code&gt;&amp;quot;esmodules&amp;quot; : true&lt;/code&gt; inside your &lt;code&gt;.babelrc&lt;/code&gt; file&#39;s &lt;code&gt;targets&lt;/code&gt; field.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token property&quot;&gt;&quot;presets&quot;&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 punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;         &lt;span class=&quot;token string&quot;&gt;&quot;@babel/preset-env&quot;&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 property&quot;&gt;&quot;targets&quot;&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 property&quot;&gt;&quot;esmodules&quot;&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;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;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;Many newer ECMAScript features compiled with Babel are already supported
in environments that support JavaScript modules. So by doing this, you
simplify the process of making sure that only transpiled code is used
for browsers that actually need it.&lt;/p&gt;
&lt;p&gt;Browsers that support modules ignore scripts with a &lt;code&gt;nomodule&lt;/code&gt; attribute.
Conversely, browsers that do not support modules ignore script elements with
&lt;code&gt;type=&amp;quot;module&amp;quot;&lt;/code&gt;. This means you can include a module as well as a compiled fallback.&lt;/p&gt;
&lt;p&gt;Ideally, the two version scripts of an application are included like this:&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&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;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;main.mjs&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;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;nomodule&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&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;compiled.js&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&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;script&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;Browsers that support modules fetch and execute &lt;code&gt;main.mjs&lt;/code&gt; and ignore &lt;code&gt;compiled.js&lt;/code&gt;.
The browsers that do not support modules do the opposite.&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; Module scripts are deferred by default. The &lt;code&gt;defer&lt;/code&gt; attribute is added to the &lt;code&gt;nomodule&lt;/code&gt; script for the same behavior. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;If you use webpack, you can set different targets in your configurations for two
separate versions of your application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A version only for browsers that support modules.&lt;/li&gt;
&lt;li&gt;A version that includes a compiled script which works in any legacy browser. This has a larger file size, since transpilation needs to support a wider range of browsers.&lt;/li&gt;
&lt;/ul&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Although this HTML approach can provide performance benefits, certain browsers have been found to double-fetch when specifying both module and nomodule scripts. Jason Miller&#39;s &lt;a href=&quot;https://jasonformat.com/modern-script-loading/&quot;&gt;Modern Script Loading&lt;/a&gt; explains this in more detail and covers a few options that can be used to circumvent this. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;em&gt;With thanks to Connor Clark and Jason Miller for their reviews.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Reduce JavaScript payloads with code splitting</title>
    <link href="https://web.dev/codelab-code-splitting/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/codelab-code-splitting/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses Chrome DevTools. &lt;a href=&quot;https://www.google.com/chrome&quot;&gt;Download Chrome&lt;/a&gt; if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Most web pages and applications are made up of many different parts. Instead of
sending all the JavaScript that makes up the application as soon as the first
page is loaded, splitting the JavaScript into multiple chunks
improves page performance.&lt;/p&gt;
&lt;p&gt;This codelab shows how to use &lt;strong&gt;code splitting&lt;/strong&gt; to improve the performance of a
simple application that sorts three numbers.&lt;/p&gt;
&lt;img alt=&quot;A browser window shows an application titled Magic Sorter with three fields for inputting numbers and a sort button.&quot; decoding=&quot;async&quot; height=&quot;504&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/1lb0XbGP6M4eShkmYaQW.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Since webpack is used in this application, any changes made to the code will trigger a new build which can take a few seconds. Once it completes, you should see your changes reflected in the application. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Like always, it&#39;s important to first measure how well a website performs before
attempting to add any optimizations.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Network panel showing 71.2 KB JavaScript bundle.&quot; decoding=&quot;async&quot; height=&quot;153&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/pyzLwutSzSx2qztQMXTM.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;71.2 KB worth of JavaScript just to sort a few numbers in a simple application.
What gives?&lt;/p&gt;
&lt;p&gt;In the source code (&lt;code&gt;src/index.js&lt;/code&gt;), the &lt;code&gt;lodash&lt;/code&gt; library is imported and used
in this application. &lt;a href=&quot;https://lodash.com/&quot; rel=&quot;noopener&quot;&gt;Lodash&lt;/a&gt; provides many useful utility
functions, but only a single method from the package is being used here.
Installing and importing entire third-party dependencies where only a small
portion of it is being utilized is a common mistake.&lt;/p&gt;
&lt;h2 id=&quot;optimize&quot;&gt;Optimize &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#optimize&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are a few ways the bundle size can be trimmed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a custom sorting method instead of importing a third-party library&lt;/li&gt;
&lt;li&gt;Use the built in &lt;code&gt;Array.prototype.sort()&lt;/code&gt; method to sort numerically&lt;/li&gt;
&lt;li&gt;Only import the &lt;code&gt;sortBy&lt;/code&gt; method from &lt;code&gt;lodash&lt;/code&gt; and not the entire library&lt;/li&gt;
&lt;li&gt;Download the code for sorting only when the user clicks the button&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Options 1 and 2 are perfectly appropriate methods to reduce the bundle size (and
would probably make the most sense for a real application). However, those are
not used in this tutorial for the sake of teaching 😈.&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; The concept of removing unused code is explored in further detail in a &lt;a href=&quot;https://web.dev/remove-unused-code&quot;&gt;separate guide&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Both options 3 and 4 help improve the performance of this application. The
next few sections of this codelab cover these steps. Like any coding
tutorial, always try to write the code yourself instead of copy and pasting.&lt;/p&gt;
&lt;h3 id=&quot;only-import-what-you-need&quot;&gt;Only import what you need &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#only-import-what-you-need&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A few files need to be modified to only import the single method from &lt;code&gt;lodash&lt;/code&gt;.
To begin with, replace this dependency in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;lodash&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^4.7.0&quot;&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 this:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;lodash.sortby&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^4.7.0&quot;&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;Now in &lt;code&gt;src/index.js&lt;/code&gt;, import this specific module:&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;./style.css&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; _ &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lodash&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; sortBy &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lodash.sortby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And update how the values are sorted::&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;highlight-line&quot;&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; values &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;input1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; input3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sortedValues &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 function&quot;&gt;sortBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sortedValues &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sortBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;  results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &amp;lt;h2&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sortedValues&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &amp;lt;/h2&gt;&lt;/span&gt;&lt;br /&gt;  &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Reload the application, open DevTools, and take a look at the &lt;strong&gt;Network&lt;/strong&gt; panel
once again.&lt;/p&gt;
&lt;img alt=&quot;Network panel showing 15.2 KB JavaScript bundle.&quot; decoding=&quot;async&quot; height=&quot;148&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/J8c1PhqMDOJKjoenzMCN.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;For this application, the bundle size was reduced by over 4X with very little
work, but there&#39;s still more room for improvement.&lt;/p&gt;
&lt;h3 id=&quot;code-splitting&quot;&gt;Code splitting &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#code-splitting&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;&lt;strong&gt;webpack&lt;/strong&gt;&lt;/a&gt; is one of the most popular open-source
module bundlers used today. In short, it &lt;em&gt;bundles&lt;/em&gt; all JavaScript modules (as
well as other assets) that make up a web application into static files that can
be read by the browser.&lt;/p&gt;
&lt;p&gt;The single bundle used in this application can be split into two separate
chunks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One responsible for the code that makes up our initial route&lt;/li&gt;
&lt;li&gt;A secondary chunk that contains our sorting code&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With the use of &lt;strong&gt;dynamic imports&lt;/strong&gt;, a secondary chunk can be &lt;em&gt;lazy loaded,&lt;/em&gt; or
loaded on demand. In this application, the code that makes up the chunk can be
loaded only when the user presses the button.&lt;/p&gt;
&lt;p&gt;Begin by removing the top-level import for the sort method in &lt;code&gt;src/index.js&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; sortBy &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;lodash.sortby&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And import it within the event listener that fires when the button is pressed:&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;highlight-line&quot;&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;submit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  e&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;preventDefault&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;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;lodash.sortby&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;default&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sortInput&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;/mark&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The &lt;code&gt;import()&lt;/code&gt; feature is part of a
&lt;a href=&quot;https://github.com/tc39/proposal-dynamic-import&quot; rel=&quot;noopener&quot;&gt;proposal&lt;/a&gt; (currently at stage
3 of the TC39 process) to include the capability to dynamically import a module.
webpack has already included support for this and follows the same syntax laid
out by the proposal.&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; Read more about how dynamic imports work in this &lt;a href=&quot;https://v8.dev/features/dynamic-import&quot;&gt;Web Updates article&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;&lt;code&gt;import()&lt;/code&gt; returns a promise and when it resolves, the selected
module is provided which is split out into a separate chunk. After the module is
returned, &lt;code&gt;module.default&lt;/code&gt; is used to reference the default
export provided by lodash. The promise is chained with another &lt;code&gt;.then&lt;/code&gt; that
calls a &lt;code&gt;sortInput&lt;/code&gt; method to sort the three input values. At the end of the
promise chain, .&lt;code&gt;catch()&lt;/code&gt; is used to handle cases where the promise is rejected
due to an error.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-state-bad-bg color-state-bad-text&quot;&gt;&lt;p class=&quot;cluster color-state-bad-text&quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot; role=&quot;img&quot; aria-label=&quot;Error sign&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 15v-2h2v2h-2zm0-10v6h2V7h-2z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Caution&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; In a production application, always handle dynamic import errors appropriately. A simple alert message similar to what is used here may not provide the best user experience to let the user know something has failed. &lt;/div&gt;&lt;/aside&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; You may see a linting error that says:  &lt;code&gt;bash Parsing error: &#39;import&#39; and &#39;export&#39; may only appear at the top level. &lt;/code&gt;  This is due to the fact that the dynamic import syntax is still in the proposal stage and has not been finalized. Although webpack already supports it, the settings for &lt;a href=&quot;https://eslint.org/&quot;&gt;ESLint&lt;/a&gt; (a JavaScript linting utility) used by Glitch has not been updated to include this syntax yet, but it still works! &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;The last thing that needs to be done is to write the &lt;code&gt;sortInput&lt;/code&gt; method at the
end of the file. This needs to be a function that &lt;em&gt;returns&lt;/em&gt; a function that
takes in the imported method from &lt;code&gt;lodash.sortBy&lt;/code&gt;. The nested function can then
sort the three input values and update the DOM.&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;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;sortInput&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;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;sortBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; values &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;      input1&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      input2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;      input3&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;valueAsNumber&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 keyword&quot;&gt;const&lt;/span&gt; sortedValues &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sortBy&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;values&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;    results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHTML &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;      &amp;lt;h2&gt;&lt;br /&gt;        &lt;/span&gt;&lt;span class=&quot;token interpolation&quot;&gt;&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;${&lt;/span&gt;sortedValues&lt;span class=&quot;token interpolation-punctuation punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&lt;br /&gt;      &amp;lt;/h2&gt;&lt;br /&gt;    &lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&quot;monitor&quot;&gt;Monitor &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#monitor&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Reload the application one last time and keep a close eye on the &lt;strong&gt;Network&lt;/strong&gt;
panel again. Only a small initial bundle is downloaded as soon as the app
loads.&lt;/p&gt;
&lt;img alt=&quot;Network panel showing 2.7 KB JavaScript bundle.&quot; decoding=&quot;async&quot; height=&quot;151&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/f1QZcSozkaA1rj52YWGV.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;After the button is pressed to sort the input numbers, the chunk that contains
the sorting code gets fetched and executed.&lt;/p&gt;
&lt;img alt=&quot;Network panel showing 2.7 KB JavaScript bundle followed by a 13.9 KB JavaScript bundle.&quot; decoding=&quot;async&quot; height=&quot;211&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/LPNj3JpAmzsGppwJl5fs.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Notice how the numbers still get sorted!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Code splitting and lazy loading can be extremely useful techniques to trim down
the initial bundle size of your application, and this can directly result in
much faster page load times. However, there are some important things that need
to be considered before including this optimization in your application.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-ui&quot;&gt;Lazy loading UI &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#lazy-loading-ui&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When lazy loading specific modules of code, it&#39;s important to consider how the
experience would be for users with weaker network connections. Splitting and
loading a very large chunk of code when a user submits an action can make it
seem like the application may have stopped working, so consider showing a
loading indicator of some sort.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-third-party-node-modules&quot;&gt;Lazy loading third-party node modules &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#lazy-loading-third-party-node-modules&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;It is not always the best approach to lazy load third-party dependencies in your
application and it depends on where you use them. Usually, third party
dependencies are split into a separate &lt;code&gt;vendor&lt;/code&gt; bundle that can be cached since
they don&#39;t update as often. Read more about how the
&lt;a href=&quot;https://webpack.js.org/plugins/split-chunks-plugin/&quot; rel=&quot;noopener&quot;&gt;SplitChunksPlugin&lt;/a&gt; can
help you do this.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-with-a-javascript-framework&quot;&gt;Lazy loading with a JavaScript framework &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#lazy-loading-with-a-javascript-framework&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Many popular frameworks and libraries that use webpack provide abstractions to
make lazy loading easier than using dynamic imports in the middle of your
application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://angular.io/guide/lazy-loading-ngmodules&quot; rel=&quot;noopener&quot;&gt;Lazy loading modules with Angular&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://reacttraining.com/react-router/web/guides/code-splitting&quot; rel=&quot;noopener&quot;&gt;Code splitting with React Router&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://router.vuejs.org/guide/advanced/lazy-loading.html&quot; rel=&quot;noopener&quot;&gt;Lazy loading with Vue Router&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Although it is useful to understand how dynamic imports work, always use the
method recommended by your framework/library to lazy load specific modules.&lt;/p&gt;
&lt;h3 id=&quot;preloading-and-prefetching&quot;&gt;Preloading and prefetching &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#preloading-and-prefetching&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Where possible, take advantage of browser hints such as &lt;code&gt;&amp;lt;link rel=&amp;quot;preload&amp;quot;&amp;gt;&lt;/code&gt;
or &lt;code&gt;&amp;lt;link rel=&amp;quot;prefetch&amp;quot;&amp;gt;&lt;/code&gt; to try and load critical modules even
sooner. webpack supports both hints through the use of magic comments in import
statements. This is explained in more detail in the
&lt;a href=&quot;https://web.dev/preload-critical-assets&quot;&gt;Preload critical chunks&lt;/a&gt; guide.&lt;/p&gt;
&lt;h3 id=&quot;lazy-loading-more-than-code&quot;&gt;Lazy loading more than code &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-code-splitting/#lazy-loading-more-than-code&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Images can make up a significant part of an application. Lazy loading those that
are below the fold, or outside the device viewport, can speed up a website. Read
more about this in the
&lt;a href=&quot;https://web.dev/use-lazysizes-to-lazyload-images&quot;&gt;Lazysizes&lt;/a&gt; guide.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Remove unused code</title>
    <link href="https://web.dev/codelab-remove-unused-code/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/codelab-remove-unused-code/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses Chrome DevTools. &lt;a href=&quot;https://www.google.com/chrome&quot;&gt;Download Chrome&lt;/a&gt; if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;In this codelab, improve the performance of the following application by
removing any unused and unneeded dependencies.&lt;/p&gt;
&lt;img alt=&quot;App screenshot&quot; decoding=&quot;async&quot; height=&quot;567&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/A6WweLPrgyud8VNCP3Dc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-remove-unused-code/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Since webpack is used in this application, any changes made to the code will trigger a new build which can take a few seconds. Once it completes, you should see your changes reflected in the application. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;It&#39;s always a good idea to first measure how well a website performs before
adding optimizations.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Go ahead and click on your favorite kitten! Firebase&#39;s
&lt;a href=&quot;https://firebase.google.com/products/realtime-database/&quot; rel=&quot;noopener&quot;&gt;Realtime Database&lt;/a&gt; is
used in this application which is why the score updates in real-time and is
synchronized with every other person using the application. 🐈&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Original bundle size of 992 KB&quot; decoding=&quot;async&quot; height=&quot;169&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/GnvBzXKQwy2az8Gyxl6D.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Almost 1 MB worth of JavaScript is being shipped to load this simple application!&lt;/p&gt;
&lt;p&gt;Take a look at the project warnings in DevTools.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click on the &lt;strong&gt;Console&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Make sure that &lt;code&gt;Warnings&lt;/code&gt; is enabled in the levels dropdown next to the
&lt;code&gt;Filter&lt;/code&gt; input.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Warnings filter&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;244&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/DMdUUxzxNMEGZ6HsTd3P.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;Take a look at the displayed warning.&lt;/li&gt;
&lt;/ul&gt;
&lt;img alt=&quot;Console warning&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;295&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/QGn9dHsaWNjTpMCwc0Rc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Firebase, which is one of the libraries used in this application, is being a
good samaritan by providing a warning to let developers know to not import its
entire package but only the components that are used. In other words, there are
unused libraries that can be removed in this application to make it load
faster.&lt;/p&gt;
&lt;p&gt;There are also instances when a particular library is used, but where there may be
a simpler alternative. The concept of removing &lt;strong&gt;unneeded libraries&lt;/strong&gt; is
explored later in this tutorial.&lt;/p&gt;
&lt;h2 id=&quot;analyzing-the-bundle&quot;&gt;Analyzing the bundle &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-remove-unused-code/#analyzing-the-bundle&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;There are two main dependencies in the application:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://firebase.google.com/&quot; rel=&quot;noopener&quot;&gt;Firebase&lt;/a&gt;: a platform that provides a number of
useful services for iOS, Android or web applications. Here its &lt;a href=&quot;https://firebase.google.com/products/realtime-database/&quot; rel=&quot;noopener&quot;&gt;Realtime
Database&lt;/a&gt; is used to
store and sync the information for each kitten in real time.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://momentjs.com/&quot; rel=&quot;noopener&quot;&gt;Moment.js&lt;/a&gt;: a utility library that makes it easier to
handle dates in JavaScript. The birth date of each kitten is stored in the
Firebase database, and &lt;code&gt;moment&lt;/code&gt; is used to calculate its age in weeks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;How can just two dependencies contribute to a bundle size of almost 1 MB? Well,
one of the reasons is that any dependency can in turn have their own
dependencies, so there are a lot more than just two if every depth/branch of the
dependency &amp;quot;tree&amp;quot; is considered. It&#39;s easy for an application to become large
relatively quickly if many dependencies are included.&lt;/p&gt;
&lt;p&gt;Analyze the bundler to get a better idea of what is going. There are a number of
different community-built tools that can help do this, such as
&lt;a href=&quot;https://www.npmjs.com/package/webpack-bundle-analyzer&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;webpack-bundle-analyzer&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The package for this tool is already included in the app as a &lt;code&gt;devDependency&lt;/code&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 string-property property&quot;&gt;&quot;devDependencies&quot;&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 comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token string-property property&quot;&gt;&quot;webpack-bundle-analyzer&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^2.13.1&quot;&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;This means that it can be used directly in the webpack configuration file.
Import it at the very beginning of &lt;code&gt;webpack.config.js&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;path&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; BundleAnalyzerPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;webpack-bundle-analyzer&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;BundleAnalyzerPlugin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now add it as a plugin at the very end of the file within the &lt;code&gt;plugins&lt;/code&gt; array:&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BundleAnalyzerPlugin&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;When the application reloads, you should see a visualization of the entire
bundle instead of the app itself.&lt;/p&gt;
&lt;img alt=&quot;Webpack Bundle Analyzer&quot; decoding=&quot;async&quot; height=&quot;468&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/QhYbNr23tGbcHwFZGKIQ.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Not as cute as seeing some kittens 🐱, but incredibly helpful nonetheless.
Hovering over any of the packages shows its size represented in three
different ways:&lt;/p&gt;
&lt;div class=&quot;table-wrapper&quot;&gt;
  &lt;table&gt;
    &lt;thead&gt;
      &lt;tr&gt;
        &lt;th&gt;&lt;strong&gt;Stat size&lt;/strong&gt;&lt;/th&gt;
        &lt;th&gt;Size before any minification or compression.&lt;/th&gt;
      &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Parsed size&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;
          Size of actual package within the bundle after it has been compiled.
          Version 4 of webpack (which is used in this application) minifies the
          compiled files automatically which is why this is smaller than the stat
          size.
        &lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td&gt;&lt;strong&gt;Gzipped size&lt;/strong&gt;&lt;/td&gt;
        &lt;td&gt;
          Size of package after it has been compressed with gzip encoding. This
          topic is covered in a separate guide.
        &lt;/td&gt;
      &lt;/tr&gt;
    &lt;/tbody&gt;
  &lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;With the webpack-bundle-analyzer tool, it is easier to identify unused or
unneeded packages that make up a large percentage of the bundle.&lt;/p&gt;
&lt;h2 id=&quot;removing-unused-packages&quot;&gt;Removing unused packages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-remove-unused-code/#removing-unused-packages&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The visualization shows that the &lt;code&gt;firebase&lt;/code&gt; package consists of a &lt;em&gt;lot&lt;/em&gt; more
than just a database. It includes additional packages such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;firestore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auth&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;storage&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;messaging&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;functions&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are all amazing services provided by Firebase (and refer to the
&lt;a href=&quot;https://firebase.google.com/docs/web/setup#use_firebase_services&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt;
to learn more), but none of them are being used in the application, so there&#39;s
no reason to have them all imported.&lt;/p&gt;
&lt;p&gt;Revert the changes in &lt;code&gt;webpack.config.js&lt;/code&gt; to see the application again:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove &lt;code&gt;BundleAnalyzerPlugin&lt;/code&gt; in the list of plugins:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token literal-property property&quot;&gt;plugins&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;BundleAnalyzerPlugin&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;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;And now remove the unused import from the top of the file:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;path&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; BundleAnalyzerPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;webpack-bundle-analyzer&#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;BundleAnalyzerPlugin&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The application should load normally now. Modify &lt;code&gt;src/index.js&lt;/code&gt; to update the
Firebase imports.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; firebase &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; firebase &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/app&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/database&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/ins&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now when the app reloads, the DevTools warning does not show. Opening the
DevTools &lt;strong&gt;Network&lt;/strong&gt; panel also shows a &lt;em&gt;nice&lt;/em&gt; reduction in bundle size:&lt;/p&gt;
&lt;img alt=&quot;Bundle size reduced to 480 KB&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;152&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/8agHvjw7351Yj8U1rIla.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;More than half the bundle size was removed. Firebase provides many different
services and gives developers the option to only include those that are actually
needed. In this application, only &lt;code&gt;firebase/database&lt;/code&gt; was used to store and sync
all of the data. The &lt;code&gt;firebase/app&lt;/code&gt; import, which sets up the API surface for
each of the different services, is always required.&lt;/p&gt;
&lt;p&gt;Many other popular libraries, such as &lt;code&gt;lodash&lt;/code&gt;, also allow developers to
selectively import different parts of their packages. Without doing much work,
updating library imports in an application to only include what is being used
can result in significant performance improvements.&lt;/p&gt;
&lt;p&gt;Although the bundle size has been reduced by quite a bit, there&#39;s still more
work to do! 😈&lt;/p&gt;
&lt;h2 id=&quot;removing-unneeded-packages&quot;&gt;Removing unneeded packages &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-remove-unused-code/#removing-unneeded-packages&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Unlike Firebase, importing parts of the &lt;code&gt;moment&lt;/code&gt; library cannot be done as
easily, but maybe it can be removed entirely?&lt;/p&gt;
&lt;p&gt;The birthday of each cute kitten is stored in &lt;strong&gt;Unix&lt;/strong&gt; format (milliseconds) in
the Firebase database.&lt;/p&gt;
&lt;img alt=&quot;Birthdates stored in Unix format&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;236&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 560px) 560px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/D1ufo1PdyzW3wFSu9sE1.png?auto=format&amp;w=1120 1120w&quot; width=&quot;560&quot; /&gt;
&lt;p&gt;This is a timestamp of a particular date and time represented by the number of
milliseconds that have elapsed since January 1, 1970 00:00 UTC. If the current
date and time can be calculated in the same format, a small function to find the
age of each kitten in weeks can probably be constructed.&lt;/p&gt;
&lt;p&gt;Like always, try not to copy and paste as you follow along here. Begin by
removing &lt;code&gt;moment&lt;/code&gt; from the imports in &lt;code&gt;src/index.js&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; firebase &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/app&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;firebase/database&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; moment &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;moment&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/del&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;There is a Firebase event listener that handles value changes in our database:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;favoritesRef&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;value&quot;&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 parameter&quot;&gt;snapshot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&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;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Above this, add a small function to calculate the number of weeks from a
given date:&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;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;ageInWeeks&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token parameter&quot;&gt;birthDate&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;WEEK_IN_MILLISECONDS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;24&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; diff &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&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 keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Date&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 function&quot;&gt;getTime&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 operator&quot;&gt;-&lt;/span&gt; birthDate&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 keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;diff &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;WEEK_IN_MILLISECONDS&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 punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;In this function, the difference in milliseconds between the current date and
time &lt;code&gt;(new Date).getTime()&lt;/code&gt; and the birth date (the &lt;code&gt;birthDate&lt;/code&gt; argument, already
in milliseconds) is calculated and divided by the number of milliseconds in a
single week.&lt;/p&gt;
&lt;p&gt;Finally, all instances of &lt;code&gt;moment&lt;/code&gt; can be removed in the event listener by
leveraging this function instead:&lt;/p&gt;
&lt;pre&gt;
favoritesRef.on(&quot;value&quot;, (snapshot) =&gt; {
  const { kitties, favorites, names, birthDates } = snapshot.val();
  favoritesScores = favorites;

  kittiesList.innerHTML = kitties.map((kittiePic, index) =&gt; {
    &lt;s&gt;const birthday = moment(birthDates[index]);&lt;/s&gt;

    return `
      &amp;lt;li&amp;gt;
        &amp;lt;img src=${kittiePic} onclick=&amp;quot;favKittie(${index})&amp;quot;&amp;gt;
        &amp;lt;div class=&amp;quot;extra&amp;quot;&amp;gt;
          &amp;lt;div class=&amp;quot;details&amp;quot;&amp;gt;
            &amp;lt;p class=&amp;quot;name&amp;quot;&amp;gt;${names[index]}&amp;lt;/p&amp;gt;
            &lt;s&gt;&amp;lt;p class=&amp;quot;age&amp;quot;&amp;gt;${moment().diff(birthday, &#39;weeks&#39;)} weeks old&amp;lt;/p&amp;gt;&lt;/s&gt;
            &lt;strong&gt;&amp;lt;p class=&amp;quot;age&amp;quot;&amp;gt;${ageInWeeks(birthDates[index])} weeks old&amp;lt;/p&amp;gt;&lt;/strong&gt;
          &amp;lt;/div&amp;gt;
          &amp;lt;p class=&amp;quot;score&amp;quot;&amp;gt;${favorites[index]} ❤&amp;lt;/p&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/li&amp;gt;
    `})
});
&lt;/pre&gt;
&lt;p&gt;Now reload the application and take a look at the &lt;strong&gt;Network&lt;/strong&gt; panel once more.&lt;/p&gt;
&lt;img alt=&quot;Bundle size reduced to 225 KB&quot; class=&quot;screenshot&quot; decoding=&quot;async&quot; height=&quot;154&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ixTpGQBkJimzUmEFBMsR.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The size of our bundle was reduced by more than half again!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-remove-unused-code/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With this codelab, you should have a decent understanding of how to analyze a
particular bundle and why it can be so useful to remove unused or unneeded
packages. Before you begin optimizing an application with this technique, &lt;strong&gt;it&#39;s
important to know that this can be significantly more complex in larger
applications&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With regards to &lt;strong&gt;removing unused libraries&lt;/strong&gt;, try to find out which parts of a
bundle are being used and which parts are not. For a mysterious looking
package that looks like it is not being used anywhere, take a step back and check
which top-level dependencies might need it. Try to find a way to possibly
decouple them from each other.&lt;/p&gt;
&lt;p&gt;When it comes to &lt;strong&gt;removing unneeded libraries&lt;/strong&gt;, things can be a little more
complicated. It&#39;s important to work closely with your team and see if there is
potential to simplify parts of the codebase. Removing &lt;code&gt;moment&lt;/code&gt; in this
application may look like it would be the right thing to do every time, but what
if there were time zones and different locales that needed to be handled? Or
what if there were more complicated date manipulations? Things can get very
tricky when manipulating and parsing dates/times, and libraries like &lt;code&gt;moment&lt;/code&gt;
and &lt;a href=&quot;https://date-fns.org/&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;date-fns&lt;/code&gt;&lt;/a&gt; simplify this significantly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Everything is a tradeoff, and it&#39;s important to gauge whether it&#39;s even worth
the complexity and effort to roll out a custom solution instead of relying on a
third-party library.&lt;/strong&gt;&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Minify and compress network payloads</title>
    <link href="https://web.dev/reduce-network-payloads-using-text-compression/"/>
    <updated>2018-11-05T00:00:00Z</updated>
    <id>https://web.dev/reduce-network-payloads-using-text-compression/</id>
    <content type="html" mode="escaped">&lt;p&gt;There are two useful techniques that can be used to improve the performance of
your web page:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Minification&lt;/li&gt;
&lt;li&gt;Data compression&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Incorporating both of these techniques reduces payload sizes and in turn
improves page load times.&lt;/p&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-network-payloads-using-text-compression/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Lighthouse displays a failed audit if it detects any CSS or JS resources on your
page that can be minified.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse Minify CSS Audit&quot; decoding=&quot;async&quot; height=&quot;90&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/ZT9ESeCStegt0SklYbni.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;img alt=&quot;Lighthouse Minify JS Audit&quot; decoding=&quot;async&quot; height=&quot;112&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/vDaAnUSvQxmGcoasQj1k.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;It also audits for any uncompressed assets.&lt;/p&gt;
&lt;img alt=&quot;Lighthouse: Enable text compression&quot; decoding=&quot;async&quot; height=&quot;123&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/xfqzdLuu3w3lanxo5Ggc.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;minification&quot;&gt;Minification &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-network-payloads-using-text-compression/#minification&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Minification&lt;/strong&gt; is the process of removing whitespace and any code that is not
necessary to create a smaller but perfectly valid code file.
&lt;a href=&quot;https://github.com/terser-js/terser&quot; rel=&quot;noopener&quot;&gt;Terser&lt;/a&gt; is a popular JavaScript
compression tool and &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; v4 includes a plugin
for this library by default to create minified build files.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you&#39;re using webpack v4 or greater, you should be good to go
without doing any additional work. 👍&lt;/li&gt;
&lt;li&gt;If you are using an older version of webpack, install and include
&lt;code&gt;TerserWebpackPlugin&lt;/code&gt; into your webpack configuration settings. Follow
the &lt;a href=&quot;https://webpack.js.org/plugins/terser-webpack-plugin/&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt; to
learn how.&lt;/li&gt;
&lt;li&gt;If you are not using a module bundler, use &lt;code&gt;Terser&lt;/code&gt; as a CLI tool or
include it directly as a dependency to your application. The project
&lt;a href=&quot;https://github.com/terser-js/terser&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt; provides instructions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;data-compression&quot;&gt;Data compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-network-payloads-using-text-compression/#data-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Compression&lt;/strong&gt; is the process of modifying data using a compression algorithm.
&lt;a href=&quot;https://www.youtube.com/watch?v=whGwm0Lky2s&amp;amp;feature=youtu.be&amp;amp;t=14m11s&quot; rel=&quot;noopener&quot;&gt;Gzip&lt;/a&gt; is
the most widely used compression format for server and client interactions.
&lt;a href=&quot;https://opensource.googleblog.com/2015/09/introducing-brotli-new-compression.html&quot; rel=&quot;noopener&quot;&gt;Brotli&lt;/a&gt;
is a newer compression algorithm which can provide even better compression
results than Gzip.&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; Compressing files can significantly improve the performance of a webpage, but you rarely need to do this yourself. Many hosting platforms, CDNs and reverse proxy servers either encode assets with compression by default or allow you to easily configure them. Read the documentation for the tool that you are using to see if compression is already supported before attempting to roll out your own solution. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;There are two different ways to compress files sent to a browser:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamically&lt;/li&gt;
&lt;li&gt;Statically&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both approaches have their own advantages and disadvantages which is covered in
the next section. Use whichever works best for your application.&lt;/p&gt;
&lt;h2 id=&quot;dynamic-compression&quot;&gt;Dynamic compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-network-payloads-using-text-compression/#dynamic-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This process involves compressing assets on-the-fly as they get requested by the
browser. This can be simpler than compressing files manually or with a build
process, but can cause delays if high compression levels are used.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://expressjs.com/&quot; rel=&quot;noopener&quot;&gt;Express&lt;/a&gt; is a popular web framework for Node and
provides a &lt;a href=&quot;https://github.com/expressjs/compression&quot; rel=&quot;noopener&quot;&gt;compression&lt;/a&gt; middleware
library. Use it to compress any asset as it gets requested. Here is an example
of an entire server file that uses it correctly:&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; express &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;express&#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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; compression &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;compression&#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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compression&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;express&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;public&#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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; listener &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;	console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Your app is listening on port &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; listener&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;address&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;port&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;This compresses your assets using &lt;code&gt;gzip&lt;/code&gt;. If your web server supports it,
consider using a separate module like
&lt;a href=&quot;https://github.com/aickin/shrink-ray#readme&quot; rel=&quot;noopener&quot;&gt;shrink-ray&lt;/a&gt; to compress via
Brotli to achieve better compression ratios.&lt;/p&gt;
&lt;aside class=&quot;aside flow bg-quaternary-box-bg color-quaternary-box-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block &quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewbox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Code brackets&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M9.41 16.59L8 18l-6-6 6-6 1.41 1.41L4.83 12l4.58 4.59zm5.18-9.18L16 6l6 6-6 6-1.41-1.41L19.17 12l-4.58-4.59z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Use express.js to compress assets with &lt;a href=&quot;https://web.dev/codelab-text-compression&quot;&gt;gzip&lt;/a&gt; and &lt;a href=&quot;https://web.dev/codelab-text-compression-brotli&quot;&gt;Brotli&lt;/a&gt;. &lt;/div&gt;&lt;/aside&gt;
&lt;h2 id=&quot;static-compression&quot;&gt;Static compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/reduce-network-payloads-using-text-compression/#static-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Static compression  involves compressing and saving assets ahead of time. This
can make the build process take longer, especially if high compression levels
are used, but ensures that no delays happen when the browser fetches the
compressed resource.&lt;/p&gt;
&lt;p&gt;If your web server supports Brotli, use a plugin like
&lt;a href=&quot;https://github.com/mynameiswhm/brotli-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;BrotliWebpackPlugin&lt;/a&gt; with
webpack to compress your assets as part of your build step. Otherwise, use
&lt;a href=&quot;https://github.com/webpack-contrib/compression-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;CompressionPlugin&lt;/a&gt;
to compress your assets with gzip. It can be included just like any other plugin
in the webpack configurations file:&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;	&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;	&lt;span class=&quot;token literal-property property&quot;&gt;plugins&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;		&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;		&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CompressionPlugin&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;	&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Once compressed files are part of the build folder, create a route in your
server to handle all JS endpoints to serve the compressed files. Here is an
example of how this can be done with Node and Express for gzipped assets.&lt;/p&gt;
&lt;pre&gt;
const express = require(&#39;express&#39;);
const app = express();

&lt;strong&gt;app.get(&#39;*.js&#39;, (req, res, next) =&gt; {
	req.url = req.url + &#39;.gz&#39;;
	res.set(&#39;Content-Encoding&#39;, &#39;gzip&#39;);
	next();
});&lt;/strong&gt;

app.use(express.static(&#39;public&#39;));
&lt;/pre&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
  
  <entry>
    <title>Minify and compress network payloads with gzip</title>
    <link href="https://web.dev/codelab-text-compression/"/>
    <updated>2018-04-24T00:00:00Z</updated>
    <id>https://web.dev/codelab-text-compression/</id>
    <content type="html" mode="escaped">&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; This codelab uses Chrome DevTools. &lt;a href=&quot;https://www.google.com/chrome&quot;&gt;Download Chrome&lt;/a&gt; if you don&#39;t already have it. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;This codelab explores how both minifying and compressing the JavaScript
bundle for the following application improves page performance by reducing
the app&#39;s request size.&lt;/p&gt;
&lt;img alt=&quot;App screenshot&quot; decoding=&quot;async&quot; height=&quot;535&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Ga0pUShY7cQ0BDAPgPuh.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;measure&quot;&gt;Measure &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#measure&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-info-bg color-state-info-text&quot;&gt;&lt;div class=&quot; flow&quot;&gt; Since webpack is used in this application, any changes made to the code will trigger a new build which can take a few seconds. Once it completes, you should see your changes reflected in the application. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Before diving in to add optimizations, it&#39;s always a good idea to first analyze
the current state of the application.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;To preview the site, press &lt;strong&gt;View App&lt;/strong&gt;. Then press
&lt;strong&gt;Fullscreen&lt;/strong&gt;
&lt;img src=&quot;https://web.dev/images/glitch/fullscreen.svg&quot; alt=&quot;fullscreen&quot; style=&quot;padding: 4px 8px; opacity: .5; border: 1px solid #c3c3c3; border-radius: 5px; margin-top: 0;&quot; /&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This app, which was also covered in the &lt;a href=&quot;https://web.dev/remove-unused-code&quot;&gt;&amp;quot;Remove unused
code&amp;quot;&lt;/a&gt; codelab, lets you vote for your favorite
kitten. 🐈&lt;/p&gt;
&lt;p&gt;Now take a look at how large this application is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Press `Control+Shift+J` (or `Command+Option+J` on Mac) to open DevTools.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Network&lt;/strong&gt; tab.&lt;/li&gt;
&lt;li&gt;Select the &lt;strong&gt;Disable cache&lt;/strong&gt; checkbox.&lt;/li&gt;
&lt;li&gt;Reload the app.&lt;/li&gt;
&lt;/ol&gt;
&lt;img alt=&quot;Original bundle size in Network panel&quot; decoding=&quot;async&quot; height=&quot;186&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/Zzm8kiE2W29yGEZC7C2u.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Although a lot of progress was made in the &lt;a href=&quot;https://web.dev/remove-unused-code&quot;&gt;&amp;quot;Remove unused code&amp;quot;&lt;/a&gt;
codelab to trim this bundle size down, 225 KB is still quite large.&lt;/p&gt;
&lt;h2 id=&quot;minification&quot;&gt;Minification &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#minification&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Consider the following block of code.&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;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;soNice&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;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; counter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&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 keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&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;    console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;nice&#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;    counter&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 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;If this function is saved in a file of its own, the file size is around
&lt;strong&gt;112 B (bytes).&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If all whitespace is removed, the resulting code looks 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 keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;soNice&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;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; counter&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;counter&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&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;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nice&quot;&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;counter&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;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;The file size would now be around 83 B. If it gets further mangled by reducing
the length of variable name and modifying some expressions, the final code may
end up looking 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 keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;soNice&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;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&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;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;nice&quot;&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;i&lt;span class=&quot;token operator&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;The file size now reaches &lt;strong&gt;62 B&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;With each step, the code is becoming harder to read. However, the browser&#39;s
JavaScript engine interprets each of these in the exact same way. The
benefit of obfuscating code in this manner can help achieve smaller file
sizes. 112 B really was not much to begin with, but there was still a 50%
reduction in size!&lt;/p&gt;
&lt;p&gt;In this application, &lt;a href=&quot;https://webpack.js.org/&quot; rel=&quot;noopener&quot;&gt;webpack&lt;/a&gt; version 4 is used as a
module bundler. The specific version can be seen in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;devDependencies&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;webpack&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^4.16.4&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Version 4 already minifies the bundle by default during production mode. It uses
&lt;code&gt;TerserWebpackPlugin&lt;/code&gt; a plugin for &lt;a href=&quot;https://github.com/terser-js/terser&quot; rel=&quot;noopener&quot;&gt;Terser&lt;/a&gt;.
Terser is a popular tool used to compress JavaScript code.&lt;/p&gt;
&lt;p&gt;To get an idea of what the minified code looks like, go ahead and click
&lt;code&gt;main.bundle.js&lt;/code&gt; while still in the DevTools &lt;strong&gt;Network&lt;/strong&gt; panel. Now click the
&lt;strong&gt;Response&lt;/strong&gt; tab.&lt;/p&gt;
&lt;img alt=&quot;Minified response&quot; decoding=&quot;async&quot; height=&quot;249&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/uti2q15O2MtiEsegYoV9.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The code in its final form, minified and mangled, is shown in the response body.
To find out how large the bundle may have been if it was not minified, open
&lt;code&gt;webpack.config.js&lt;/code&gt; and update the &lt;code&gt;mode&lt;/code&gt; configuration.&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;production&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;none&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Reload the application and take a look at the bundle size again through the
DevTools &lt;strong&gt;Network&lt;/strong&gt; panel&lt;/p&gt;
&lt;img alt=&quot;Bundle size of 767 KB&quot; decoding=&quot;async&quot; height=&quot;129&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 700px) 700px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/H0lINRmM2gF6NHnzmkGM.png?auto=format&amp;w=1400 1400w&quot; width=&quot;700&quot; /&gt;
&lt;p&gt;That&#39;s a pretty big difference! 😅&lt;/p&gt;
&lt;p&gt;Make sure to revert the changes here before continuing.&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;ins class=&quot;highlight-line highlight-line-add&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;production&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/ins&gt;&lt;br /&gt;&lt;del class=&quot;highlight-line highlight-line-remove&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;none&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/del&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Including a process to minify code in your application depends on the tools
that you use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If webpack v4 or greater is used, no additional work needs to be done
since code is minified by default in production mode. 👍&lt;/li&gt;
&lt;li&gt;If an older version of webpack is used, install and include &lt;code&gt;TerserWebpackPlugin&lt;/code&gt;
into the webpack build process. The &lt;a href=&quot;https://webpack.js.org/plugins/terser-webpack-plugin/&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt;
explains this in detail.&lt;/li&gt;
&lt;li&gt;Other minification plugins also exist and can be used instead,
such as &lt;a href=&quot;https://github.com/webpack-contrib/babel-minify-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;BabelMinifyWebpackPlugin&lt;/a&gt;
and &lt;a href=&quot;https://github.com/roman01la/webpack-closure-compiler&quot; rel=&quot;noopener&quot;&gt;ClosureCompilerPlugin&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;If a module bundler is not being used at all, use &lt;a href=&quot;https://github.com/terser-js/terser&quot; rel=&quot;noopener&quot;&gt;Terser&lt;/a&gt;
as a CLI tool or include it directly as a dependency.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;compression&quot;&gt;Compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;aside class=&quot;aside flow bg-state-warn-bg color-state-warn-text&quot;&gt;&lt;p class=&quot;cluster &quot;&gt;&lt;span class=&quot;aside__icon box-block color-state-warn-text&quot;&gt;&lt;svg width=&quot;24&quot; height=&quot;24&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; role=&quot;img&quot; aria-label=&quot;Warning sign&quot; xmlns=&quot;http://www.w3.org/2000/svg&quot;&gt;   &lt;path fill-rule=&quot;evenodd&quot; clip-rule=&quot;evenodd&quot; d=&quot;M23 21L12 2 1 21h22zm-12-3v-2h2v2h-2zm0-4h2v-4h-2v4z&quot;&gt;&lt;/path&gt; &lt;/svg&gt;&lt;/span&gt;&lt;strong&gt;Warning&lt;/strong&gt;&lt;/p&gt;&lt;div class=&quot; flow&quot;&gt; Many hosting platforms, CDNs and reverse proxy servers either encode assets with compression by default or allow you to easily configure them. This means that you may rarely ever need to set up your server similar to how it is done in the compression section of this tutorial, but you can continue to read if you are interested in learning how compression works. &lt;/div&gt;&lt;/aside&gt;
&lt;p&gt;Although the term &amp;quot;compression&amp;quot; is sometimes loosely used to explain how code is
reduced during the minification process, it isn&#39;t actually compressed in the
literal sense.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Compression&lt;/strong&gt; usually refers to code that has been modified using a data
compression algorithm. Unlike minification which ends up providing perfectly
valid code, compressed code needs to be &lt;em&gt;decompressed&lt;/em&gt; before being used.&lt;/p&gt;
&lt;p&gt;With every HTTP request and response, browsers and web servers can add
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/HTTP/Headers&quot; rel=&quot;noopener&quot;&gt;headers&lt;/a&gt; to include
additional information about the asset being fetched or received. This can be
seen in the &lt;code&gt;Headers&lt;/code&gt; tab within the DevTools Network panel where three types
are shown:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;General&lt;/strong&gt; represents general headers relevant to the entire request-response
interaction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Response Headers&lt;/strong&gt; shows a list of headers specific to the actual response
from the server.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Request Headers&lt;/strong&gt; shows a list of headers attached to the request by the
client.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Take a look at the &lt;code&gt;accept-encoding&lt;/code&gt; header in the &lt;code&gt;Request Headers&lt;/code&gt;.&lt;/p&gt;
&lt;img alt=&quot;Accept encoding header&quot; decoding=&quot;async&quot; height=&quot;361&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/shmaD9cmjjFMITKL0TAW.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;&lt;code&gt;accept-encoding&lt;/code&gt; is used by the browser to specify which content
encoding formats, or compression algorithms, it supports. There are many
text-compression algorithms out there, but there are only three that are
supported here for the compression (and decompression) of HTTP network requests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.gzip.org/&quot; rel=&quot;noopener&quot;&gt;Gzip&lt;/a&gt; (&lt;code&gt;gzip&lt;/code&gt;): The most widely used compression
format for server and client interactions. It builds on top of the Deflate
algorithm and is supported in all current browsers.&lt;/li&gt;
&lt;li&gt;Deflate (&lt;code&gt;deflate&lt;/code&gt;): Not commonly used.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/google/brotli&quot; rel=&quot;noopener&quot;&gt;Brotli&lt;/a&gt; (&lt;code&gt;br&lt;/code&gt;): A newer compression
algorithm that aims to further improve compression ratios, which can result in
even faster page loads. It is supported in the
&lt;a href=&quot;https://caniuse.com/#feat=brotli&quot; rel=&quot;noopener&quot;&gt;latest versions of most browsers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The sample application in this tutorial is identical to the app completed in the
&lt;a href=&quot;https://web.dev/remove-unused-code&quot;&gt;&amp;quot;Remove unused code&amp;quot;&lt;/a&gt; codelab except for the fact that
&lt;a href=&quot;https://expressjs.com/&quot; rel=&quot;noopener&quot;&gt;Express&lt;/a&gt; is now used as a server framework. In the next
few sections, both static and dynamic compression is explored.&lt;/p&gt;
&lt;h2 id=&quot;dynamic-compression&quot;&gt;Dynamic compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#dynamic-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Dynamic&lt;/strong&gt; compression involves compressing assets on-the-fly as they get
requested by the browser.&lt;/p&gt;
&lt;h3 id=&quot;pros&quot;&gt;Pros &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#pros&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Creating and updating saved compressed versions of assets does not need to be
done.&lt;/li&gt;
&lt;li&gt;Compressing on-the-fly works especially well for web pages that are
dynamically generated.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons&quot;&gt;Cons &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#cons&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Compressing files at higher levels to achieve better compression ratios
takes longer. This can cause a performance hit as the user waits for assets to
compress before they are sent by the server.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;dynamic-compression-with-nodeexpress&quot;&gt;Dynamic compression with Node/Express &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#dynamic-compression-with-nodeexpress&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;server.js&lt;/code&gt; file is responsible for setting up the Node server that hosts
the application.&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;const&lt;/span&gt; express &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;express&#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;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&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;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;express&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;public&#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 keyword&quot;&gt;const&lt;/span&gt; listener &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;listen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;process&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PORT&lt;/span&gt;&lt;span class=&quot;token punctuation&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 punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Your app is listening on port &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; listener&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;address&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;port&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;All this currently does is import &lt;code&gt;express&lt;/code&gt; and use the &lt;code&gt;express.static&lt;/code&gt;
middleware to load all the static HTML, JS and CSS files in the
&lt;code&gt;public/&lt;/code&gt; directory (and those files are created by webpack with every build).&lt;/p&gt;
&lt;p&gt;To make sure all of the assets are compressed every time they&#39;re requested, the
&lt;a href=&quot;https://github.com/expressjs/compression&quot; rel=&quot;noopener&quot;&gt;compression&lt;/a&gt; middleware library can
be used. Begin by adding it as a &lt;code&gt;devDependency&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;devDependencies&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;compression&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^1.7.3&quot;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And import it into the server file, &lt;code&gt;server.js&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; express &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;express&#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&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; compression &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;compression&#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;/mark&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And add it as a middleware &lt;strong&gt;before&lt;/strong&gt; &lt;code&gt;express.static&lt;/code&gt; is mounted:&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;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;express&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;compression&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;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;express&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;public&#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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Now reload the app and take a look at the bundle size in the &lt;strong&gt;Network&lt;/strong&gt; panel.&lt;/p&gt;
&lt;img alt=&quot;Bundle size with dynamic compression&quot; decoding=&quot;async&quot; height=&quot;161&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/MMtTKWPKfht8RYd8BMYF.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;From 225 KB to 61.6 KB! In the &lt;code&gt;Response Headers&lt;/code&gt; now, a &lt;code&gt;content-encoding&lt;/code&gt;
header shows that the server is sending down this file encoded with &lt;code&gt;gzip&lt;/code&gt;.&lt;/p&gt;
&lt;img alt=&quot;Content encoding header&quot; decoding=&quot;async&quot; height=&quot;470&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/523FjNSQOK95lGzg0B6D.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h2 id=&quot;static-compression&quot;&gt;Static compression &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#static-compression&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The idea behind &lt;strong&gt;static&lt;/strong&gt; compression is to have assets compressed and saved
ahead of time.&lt;/p&gt;
&lt;h3 id=&quot;pros-2&quot;&gt;Pros &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#pros-2&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Latency due to high compression levels is not a concern anymore.
Nothing needs to happen on-the-fly to compress files as they can now be fetched directly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;cons-2&quot;&gt;Cons &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#cons-2&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Assets need to compressed with every build. Build times can increase
significantly if high compression levels are used.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;static-compression-with-nodeexpress-and-webpack&quot;&gt;Static compression with Node/Express and webpack &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#static-compression-with-nodeexpress-and-webpack&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Since static compression involves compressing files ahead of time, webpack
settings can be modified to compress assets as part of the build step.
&lt;a href=&quot;https://github.com/webpack-contrib/compression-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;CompressionPlugin&lt;/code&gt;&lt;/a&gt;
can be used for this.&lt;/p&gt;
&lt;p&gt;Begin by adding it as a &lt;code&gt;devDependency&lt;/code&gt; in &lt;code&gt;package.json&lt;/code&gt;:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;&quot;devDependencies&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;compression-webpack-plugin&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;^1.1.11&quot;&lt;/span&gt;&lt;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&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&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;Like any other webpack plugin, import it in the configurations file,
&lt;code&gt;webpack.config.js:&lt;/code&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;highlight-line&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;path&quot;&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; CompressionPlugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&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;&quot;compression-webpack-plugin&quot;&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;/mark&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;And include it within the &lt;code&gt;plugins&lt;/code&gt; array:&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;highlight-line&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;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;plugins&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&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;mark class=&quot;highlight-line highlight-line-active&quot;&gt;    &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CompressionPlugin&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;/mark&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;highlight-line&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;By default, the plugin compresses the build files using &lt;code&gt;gzip&lt;/code&gt;. Take a look
at the &lt;a href=&quot;https://github.com/webpack-contrib/compression-webpack-plugin&quot; rel=&quot;noopener&quot;&gt;documentation&lt;/a&gt;
to learn how to add options to use a different algorithm or include/exclude
certain files.&lt;/p&gt;
&lt;p&gt;When the app reloads and rebuilds, a compressed version of the main bundle is
now created. Open the Glitch Console to take a look at what&#39;s inside the
final &lt;code&gt;public/&lt;/code&gt; directory that&#39;s served by the Node server.&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; The &lt;code&gt;git.ignore&lt;/code&gt; file includes the &lt;code&gt;public/&lt;/code&gt; directory. Directories that contain build files are usually included here. Glitch also hides these files from the editor tree. &lt;/div&gt;&lt;/aside&gt;
&lt;ul&gt;
&lt;li&gt;Click the &lt;strong&gt;Tools&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Console&lt;/strong&gt; button.&lt;/li&gt;
&lt;li&gt;In the console, run the following commands to change into the &lt;code&gt;public&lt;/code&gt;
directory and see all of its files:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; public&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;img alt=&quot;Final outputted files in public directory&quot; decoding=&quot;async&quot; height=&quot;188&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/YQwCT87xMfMwWiH63lTS.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The gzipped version of the bundle, &lt;code&gt;main.bundle.js.gz&lt;/code&gt;, is now saved here as
well. &lt;code&gt;CompressionPlugin&lt;/code&gt; also compresses &lt;code&gt;index.html&lt;/code&gt; by default.&lt;/p&gt;
&lt;p&gt;The next thing that needs to be done is tell the server to send these gzipped
files whenever their original JS versions are being requested. This can be done
by defining a new route in &lt;code&gt;server.js&lt;/code&gt; before the files are served with
&lt;code&gt;express.static&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;
const express = require(&#39;express&#39;);
const app = express();

&lt;strong&gt;app.get(&#39;*.js&#39;, (req, res, next) =&gt; {
  req.url = req.url + &#39;.gz&#39;;
  res.set(&#39;Content-Encoding&#39;, &#39;gzip&#39;);
  next();
});&lt;/strong&gt;

app.use(express.static(&#39;public&#39;));

//...
&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;app.get&lt;/code&gt; is used to tell the server how to respond to a GET request for a
specific endpoint. A callback function is then used to define how to handle this
request. The route works like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Specifying &lt;code&gt;&#39;*.js&#39;&lt;/code&gt; as the first argument means that this works for every
endpoint that is fired to fetch a JS file.&lt;/li&gt;
&lt;li&gt;Within the callback, &lt;code&gt;.gz&lt;/code&gt; is attached to the URL of the request and the
&lt;code&gt;Content-Encoding&lt;/code&gt; response header is set to &lt;code&gt;gzip&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Finally, &lt;code&gt;next()&lt;/code&gt; ensures that the sequence continues to any callback
that may be next.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once the app reloads, take a look at the &lt;code&gt;Network&lt;/code&gt; panel once more.&lt;/p&gt;
&lt;img alt=&quot;Bundle size reduction with static compression&quot; decoding=&quot;async&quot; height=&quot;176&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/admin/b7xYRsSdNhWX5Lc8zE51.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Just like before, a significant reduction in bundle size!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/codelab-text-compression/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This codelab covered the process of minifying and compressing source code.
Both these techniques are becoming a default in many of the tools
available today, so it&#39;s important to find out whether your toolchain already
supports them or if you should begin applying both processes yourself.&lt;/p&gt;
</content>
    <author>
      <name>Houssein Djirdeh</name>
    </author>
  </entry>
</feed>
