{"id":2587,"date":"2024-06-07T09:32:51","date_gmt":"2024-06-07T15:32:51","guid":{"rendered":"https:\/\/frontendmasters.com\/blog\/?p=2587"},"modified":"2024-06-08T13:07:19","modified_gmt":"2024-06-08T19:07:19","slug":"playing-with-the-speculation-rules-api-in-the-console","status":"publish","type":"post","link":"https:\/\/frontendmasters.com\/blog\/playing-with-the-speculation-rules-api-in-the-console\/","title":{"rendered":"Playing with the Speculation Rules API in the Console"},"content":{"rendered":"\n<p>Improving the loading speed of web pages is often about making series of small incremental improvements: better CSS minification here, higher compression setting there, reducing JavaScript dependencies and so on. Rarely we see an opportunity that has the potential of altering &#8220;the game&#8221; completely. This post is about one such opportunity of not just making pages load 10% or even 50% faster, but rather make them appear to load immediately.<\/p>\n\n\n\n<p>At <a href=\"https:\/\/io.google\/2024\/\" target=\"_blank\" rel=\"noreferrer noopener\">the recent Google I\/O<\/a>, announcements around the re-invigoration of page prerendering made quite a splash among the web performance-minded developers. There is a <a href=\"https:\/\/developer.chrome.com\/docs\/web-platform\/prerender-pages\" target=\"_blank\" rel=\"noreferrer noopener\">blog post<\/a> that\u2019s a good start, providing an overview of the <a href=\"https:\/\/github.com\/WICG\/nav-speculation\/blob\/main\/triggers.md#speculation-rules\" target=\"_blank\" rel=\"noreferrer noopener\">Speculation Rules API<\/a> and some context of how we got here. This post is about trying out the new API in the good ol\u2019 console, just checking it out commitment-free, seeing-is-believing style.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is the Speculation Rules API?<\/h2>\n\n\n\n<p>Imagine if the browser didn&#8217;t have to fetch all the resources and render the new page when you click on a link to load a new page. Because&#8230; it had already done it! That&#8217;s what the Speculation Rules API is all about. It&#8217;s bit of JSON data you put inside a <code>&lt;script&gt;<\/code> tag with a special attribute that contains rules on pages you want to do this rendering ahead of time on. This information can be updated in real time as needed. The point is making new page loads feel instant. It&#8217;s a great tool for web performance and thus happy users.<\/p>\n\n\n\n<p>It&#8217;s as if you\u2019ve loaded a new page in a hidden iframe and then swapped with the original page when necessary. Except, there are no iframes involved, it\u2019s all done by the browser and comes with a nice API to boot.<\/p>\n\n\n\n<p><em>According to its <a href=\"https:\/\/wicg.github.io\/nav-speculation\/speculation-rules.html\" target=\"_blank\" rel=\"noreferrer noopener\">specification<\/a>, the Speculation Rules API is not yet a standard nor it is on the W3C standards track. However it\u2019s already publicly available in various Chromium browsers, totaling over 70% global reach (source: <a href=\"https:\/\/caniuse.com\/?search=speculationrules\" target=\"_blank\" rel=\"noreferrer noopener\">caniuse.com<\/a>)<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Potential Confusion with Prior \u201cPre\u201d Usage<\/h2>\n\n\n\n<p>There\u2019s a potential for confusion here because we have overused the \u201cpre\u201d prefix over the years. We have the <code>&lt;link&gt;<\/code>\u2019s rel attribute for example, with values <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Attributes\/rel\/preload\" target=\"_blank\" rel=\"noreferrer noopener\"><code>preload<\/code><\/a>, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Attributes\/rel\/prefetch\" target=\"_blank\" rel=\"noreferrer noopener\"><code>prefetch<\/code><\/a>, <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Attributes\/rel\/preconnect\" target=\"_blank\" rel=\"noreferrer noopener\"><code>preconnect<\/code><\/a>, which all do different things. Those will still exist.<\/p>\n\n\n\n<p class=\"learn-more\">One last thing before we begin: I\u2019m using a WordPress blog as a playground because many of us have seen or managed a blog at some point and it\u2019s familiar. However, if you want to use the new API without a care in the world, you can simply install <a href=\"https:\/\/wordpress.org\/plugins\/speculation-rules\/\" target=\"_blank\" rel=\"noreferrer noopener\">the existing WP plugin<\/a> created by WP\u2019s perf team.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Adventure Time<\/h2>\n\n\n\n<p>Let&#8217;s play with Speculation Rules API, all in the browser console, with no server-side changes necessary.<\/p>\n\n\n\n<p><strong>Step<\/strong>&nbsp;<strong>1)<\/strong>&nbsp;Load a web page, e.g.&nbsp;<a href=\"https:\/\/phpied.com\/\">https:\/\/phpied.com<\/a><\/p>\n\n\n\n<p><strong>Step<\/strong>&nbsp;<strong>2)<\/strong>&nbsp;Open the browser console and add a new class name to three links of your choosing. In this case the class name is&nbsp;<code>prerenderosa<\/code>&nbsp;and the links of my choosing are the links to the latest 3 blogposts.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">document<\/span>.querySelectorAll(<span class=\"hljs-string\">'.entry a&#91;rel=bookmark]'<\/span>)\n  .slice(<span class=\"hljs-number\">0<\/span>, <span class=\"hljs-number\">3<\/span>)\n  .forEach(<span class=\"hljs-function\"><span class=\"hljs-params\">e<\/span> =&gt;<\/span> e.classList.add(<span class=\"hljs-string\">'prerenderosa'<\/span>)\n);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Step<\/strong>&nbsp;<strong>3)<\/strong>&nbsp;Set up the speculation rules JavaScript object:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> pre = {\n  <span class=\"hljs-string\">\"prerender\"<\/span>: &#91;{\n    <span class=\"hljs-string\">\"source\"<\/span>: <span class=\"hljs-string\">\"document\"<\/span>, <span class=\"hljs-comment\">\/\/ optional, since Chrome 121<\/span>\n    <span class=\"hljs-string\">\"where\"<\/span>: {\n      <span class=\"hljs-string\">\"and\"<\/span>: &#91;\n        <span class=\"hljs-comment\">\/\/ prerender pages where the link has the new class name<\/span>\n        { <span class=\"hljs-string\">\"selector_matches\"<\/span>: <span class=\"hljs-string\">\".prerenderosa\"<\/span> }, \n      ]\n    },\n    <span class=\"hljs-string\">\"eagerness\"<\/span>: <span class=\"hljs-string\">\"immediate\"<\/span>, <span class=\"hljs-comment\">\/\/ be eager!<\/span>\n  }]\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p><strong>Step<\/strong>&nbsp;<strong>4)<\/strong>&nbsp;Add the speculations rules to the page, using a&nbsp;<code>script<\/code>&nbsp;element.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> spec = <span class=\"hljs-built_in\">document<\/span>.createElement(<span class=\"hljs-string\">'script'<\/span>);\nspec.type = <span class=\"hljs-string\">\"speculationrules\"<\/span>;\nspec.append(<span class=\"hljs-built_in\">JSON<\/span>.stringify(pre)); \n<span class=\"hljs-built_in\">document<\/span>.body.append(spec);<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>And that&#8217;s it! Pages are prerendered. Clicking on any of the 3 links shows the page loaded immediately.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"debugging\">Debugging<\/h2>\n\n\n\n<p>How do we know things worked as expected and what happened exactly? DevTools to the rescue. Open the Application tab and find &#8220;Speculative loads&#8221; in the menu. This is where you can inspect the results.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"side-track-aligning-the-planets\">Prerendering Prerequisites<\/h3>\n\n\n\n<p><\/p>\n\n\n\n<p>There are&nbsp;<a href=\"https:\/\/developer.chrome.com\/docs\/web-platform\/prerender-pages#chrome-limits\" target=\"_blank\" rel=\"noreferrer noopener\">conditions to be met<\/a>&nbsp;before&nbsp;the prerendering can happen. Most importantly you need to check if any&nbsp;extensions have disabled prefetching. This is common with ad-blocking&nbsp;extensions. This means disable the setting for all sites, not just&nbsp;disable the extension on the current page. For example in uBlock Origin,&nbsp;unselect the option called \u201cDisable pre-fetching\u201d. <a href=\"https:\/\/www.debugbear.com\/blog\/chrome-extensions-website-performance#chrome-extensions-breaking-page-pre-rendering\">Research by DebugBear<\/a> into extensions that harm performance points to two other additional popular extensions (where &#8220;popular&#8221; means over 1 million installs):&nbsp;Windscribe and Privacy Badger.<\/p>\n\n\n\n<p>Luckily, DevTools provides a link to the extension management area as well as the preload settings (they were off by default for me).<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"639\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=1024%2C639&#038;ssl=1\" alt=\"Speculative loads view in devtools\" class=\"wp-image-2590\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=1024%2C639&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=300%2C187&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=768%2C480&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=1536%2C959&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/2-disabled.png?resize=2048%2C1279&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Below is the view you see when you click on \u201cPreload pages settings\u201d link. Note that the &#8220;standard&#8221; preload setting is good enough, no need for the &#8220;extended&#8221;. <\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"381\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/fq0HUBis.png?resize=1024%2C381&#038;ssl=1\" alt=\"Preload settings in chrome:\/\/settings\/performance\" class=\"wp-image-2658\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/fq0HUBis.png?resize=1024%2C381&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/fq0HUBis.png?resize=300%2C112&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/fq0HUBis.png?resize=768%2C286&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/fq0HUBis.png?w=1434&amp;ssl=1 1434w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>You may notice that the toggle is off and\u00a0disabled so you cannot turn it on. This is a sign that possibly an extension is preventing it. In this case you should be able to see a little puzzle icon. Mouse over that icon should reveal who&#8217;s disabling the setting.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"174\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/puzzle.png?resize=1024%2C174&#038;ssl=1\" alt=\"Preload settings in chrome:\/\/settings\/performance\" class=\"wp-image-2640\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/puzzle.png?resize=1024%2C174&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/puzzle.png?resize=300%2C51&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/puzzle.png?resize=768%2C130&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/puzzle.png?w=1510&amp;ssl=1 1510w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Note that prerendering won\u2019t work if the link is opened in a new browser window\/tab (e.g. with&nbsp;<code>target=\"_blank\"<\/code>). But the benefit of the downloaded resources of the new page (scripts, styles, images) still exists. And support for&nbsp;<a href=\"https:\/\/github.com\/WICG\/nav-speculation\/blob\/main\/triggers.md#window-name-targeting-hints\">window targets<\/a>&nbsp;is coming soon.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"back-to-debugging\">Next Steps in Debugging<\/h3>\n\n\n\n<p>Now let&#8217;s see what happens every step of the way. First we load a page and pop open the new &#8220;Speculative loads&#8221; and the console.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"841\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=1024%2C841&#038;ssl=1\" alt=\"Normal page load\" class=\"wp-image-2592\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=1024%2C841&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=300%2C246&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=768%2C631&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=1536%2C1261&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/1-start.png?resize=2048%2C1682&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Now we paste the generic code from above: the one that adds class names to three selected links and adds the&nbsp;<code>speculationrules<\/code>&nbsp;script element.<\/p>\n\n\n\n<p>Lo and behold: 3 pages are prerendered and ready.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"584\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=1024%2C584&#038;ssl=1\" alt=\"3 pages are prerendered and ready\" class=\"wp-image-2593\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=1024%2C584&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=300%2C171&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=768%2C438&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=1536%2C877&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/4-success.png?resize=2048%2C1169&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>You can click to the &#8220;Speculations&#8221; submenu to see which pages were prerendered.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"492\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=1024%2C492&#038;ssl=1\" alt=\"Details on the 3 pages\" class=\"wp-image-2594\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=1024%2C492&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=300%2C144&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=768%2C369&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=1536%2C738&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/3-ready.png?resize=2048%2C984&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>Also in the Network panel you can now pick which waterfall to explore: the original page or any of the preloaded ones.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"502\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=1024%2C502&#038;ssl=1\" alt=\"Subpages in network panel\" class=\"wp-image-2595\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=1024%2C502&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=300%2C147&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=768%2C376&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=1536%2C753&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/5-inspecting-after-prerender.png?resize=2048%2C1004&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<p>If you click on a link to a prerendered page, the load is immediate, because it&#8217;s just a swap.<\/p>\n\n\n\n<p>On the next page you can also see that the &#8220;Speculative loading status&#8221; is a success. This is the prerendered page. It doesn&#8217;t have any speculation of its own but was itself loaded speculatively.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"630\" src=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=1024%2C630&#038;ssl=1\" alt=\"Speculative success\" class=\"wp-image-2596\" srcset=\"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=1024%2C630&amp;ssl=1 1024w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=300%2C185&amp;ssl=1 300w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=768%2C473&amp;ssl=1 768w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=1536%2C946&amp;ssl=1 1536w, https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/6-prerendered-page.png?resize=2048%2C1261&amp;ssl=1 2048w\" sizes=\"auto, (max-width: 1000px) 100vw, 1000px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"everything-in-moderation\">Everything in Moderation<\/h2>\n\n\n\n<p>The snippet above had&nbsp;<code>\"eagerness\": \"immediate\"<\/code>&nbsp;speculation rule. But you have other options. Let&#8217;s try&nbsp;<code>moderate<\/code>. We keep everything the same, just change one setting:<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const<\/span> pre = {\n  <span class=\"hljs-string\">\"prerender\"<\/span>: &#91;{\n    <span class=\"hljs-string\">\"source\"<\/span>: <span class=\"hljs-string\">\"document\"<\/span>,\n    <span class=\"hljs-string\">\"where\"<\/span>: {\n      <span class=\"hljs-string\">\"and\"<\/span>: &#91;\n        { <span class=\"hljs-string\">\"selector_matches\"<\/span>: <span class=\"hljs-string\">\".prerenderosa\"<\/span> }, \n      ]\n    },\n    <span class=\"hljs-string\">\"eagerness\"<\/span>: <span class=\"hljs-string\">\"moderate\"<\/span>, <span class=\"hljs-comment\">\/\/ easy there tiger<\/span>\n  }]\n};<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Now nothing is prerendered, until you mouseover for 200ms over a link that is a prerendering candidate. And as you can see out of the three candidates for prerendering one is indeed prerendered, the other two are not.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/www.phpied.com\/files\/blogimages\/spec\/7%20moderate.png?ssl=1\" alt=\"Only one page preloaded after 200ms mouseover\"\/><\/figure>\n\n\n\n<p>This is much less aggressive and easy on your server.<\/p>\n\n\n\n<p>There\u2019s one more eagerness option: \u201cconservative\u201d. With it, the browser only prerenders on mouse\/pointer down. There\u2019s still an early start but the effect may not be the same.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"concerns\">Concerns?<\/h2>\n\n\n\n<p>If you\u2019re like me, you probably have a lot of questions for example:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Can I opt out analytics of prerendered-but-never-seen pages?<\/li>\n\n\n\n<li>What about performance measurements?<\/li>\n\n\n\n<li>Can I have an API to know when prerendering happens?<\/li>\n<\/ul>\n\n\n\n<p>I\u2019m happy to say that these concerns are all addressed (see&nbsp;<a href=\"https:\/\/developer.chrome.com\/docs\/web-platform\/prerender-pages#impact-on-analytics\">here<\/a>) and reportedly already supported by Google Analytics.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"go-forth-and-speculate\">Go forth and speculate!<\/h2>\n\n\n\n<p>As you can see, you can use the new goodness purely on the client-side. There are other options, naturally you can have the speculation rules server-generated and spit out in the HTML. Or you can also have an HTTP header that points to a separate JSON file with all the rules.<\/p>\n\n\n\n<p>But no matter how you do it, the results speak for themselves and the Speculation Rules API is definitely worth exploring.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This new API enables client-side prerendering, improving performance for users who are likely to visit a new page. <\/p>\n","protected":false},"author":26,"featured_media":2600,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"sig_custom_text":"","sig_image_type":"featured-image","sig_custom_image":0,"sig_is_disabled":false,"inline_featured_image":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[1],"tags":[70,186],"class_list":["post-2587","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-post","tag-performance","tag-speculation-rules"],"acf":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/frontendmasters.com\/blog\/wp-content\/uploads\/2024\/06\/pexels-photo-7911758.jpeg?fit=1300%2C1300&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2587","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/users\/26"}],"replies":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/comments?post=2587"}],"version-history":[{"count":15,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2587\/revisions"}],"predecessor-version":[{"id":2660,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/posts\/2587\/revisions\/2660"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media\/2600"}],"wp:attachment":[{"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/media?parent=2587"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/categories?post=2587"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/frontendmasters.com\/blog\/wp-json\/wp\/v2\/tags?post=2587"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}