{"id":25055,"date":"2019-01-31T00:00:00","date_gmt":"2019-01-31T00:00:00","guid":{"rendered":"https:\/\/alienroad.com\/google-bilgi-bankasi\/dynamic-rendering-with-rendertron\/"},"modified":"2019-01-31T00:00:00","modified_gmt":"2019-01-31T00:00:00","slug":"dynamic-rendering-with-rendertron","status":"publish","type":"ar_kb","link":"https:\/\/alienroad.com\/google-bilgi-bankasi\/dynamic-rendering-with-rendertron\/","title":{"rendered":"Dynamic Rendering with Rendertron"},"content":{"rendered":"<p class=\"gargardate\">Thursday, January 31, 2019<\/p>\n<p>\n  Many frontend frameworks rely on JavaScript to show content. This can mean Google might take some<br \/>\n  time to index your content or update the indexed content.\n<\/p>\n<p>\n  <a href=\"https:\/\/www.youtube.com\/watch?v=PFwUbgvpdaQ\" class=\"external-link\">A workaround we discussed at Google I\/O<\/a><br \/>\n  this year is<br \/>\n  <a href=\"https:\/\/alienroad.com\/google-bilgi-bankasi\/dynamic-rendering-as-a-workaround\/\">dynamic rendering<\/a>. There are many<br \/>\n  ways to implement this. This blog post shows an example implementation of dynamic rendering using<br \/>\n  <a href=\"https:\/\/github.com\/GoogleChrome\/rendertron\" class=\"external-link\">Rendertron<\/a>, which is an<br \/>\n  open source solution based on headless Chromium.\n<\/p>\n<h2 id=\"which-sites-should-consider-dynamic-rendering\" tabindex=\"-1\">Which sites should consider dynamic rendering?<\/h2>\n<p>\n  Not all search engines or social media bots visiting your website can run JavaScript. Googlebot<br \/>\n  might take time to run your JavaScript and has<br \/>\n  <a href=\"https:\/\/alienroad.com\/google-bilgi-bankasi\/fix-javascript-problems\/\">some limitations<\/a>, for example.\n<\/p>\n<p>\n  Dynamic rendering is useful for content that changes often and needs JavaScript to display. Your<br \/>\n  site&#8217;s user experience (especially the time to<br \/>\n  <a href=\"https:\/\/developers.google.com\/web\/tools\/lighthouse\/audits\/first-meaningful-paint\" class=\"external-link\">first meaningful paint<\/a>)<br \/>\n  may benefit from considering hybrid rendering (for example,<br \/>\n  <a href=\"https:\/\/angular.io\/guide\/universal\" class=\"external-link\">Angular Universal<\/a>).\n<\/p>\n<h2 id=\"how-does-dynamic-rendering-work\" tabindex=\"-1\">How does dynamic rendering work?<\/h2>\n<p><img decoding=\"async\" alt=\"How dynamic rendering works\" src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-50773c34c222.png\" loading=\"lazy\"><\/p>\n<p>\n  <a href=\"https:\/\/alienroad.com\/google-bilgi-bankasi\/dynamic-rendering-as-a-workaround\/\">Dynamic rendering<\/a><br \/>\n  means switching between client-side rendered and pre-rendered content for specific user agents.\n<\/p>\n<p>\n  You will need a renderer to execute the JavaScript and produce static HTML. Rendertron is an open<br \/>\n  source project that uses<br \/>\n  <a href=\"https:\/\/developers.google.com\/web\/updates\/2017\/04\/headless-chrome\" class=\"external-link\">headless Chromium<\/a> to render.<br \/>\n  Single Page Apps often load data in the background or defer work to render their content.<br \/>\n  Rendertron has mechanisms to determine when a website has completed rendering. It waits until all<br \/>\n  network requests have finished and there is no outstanding work.\n<\/p>\n<p>This post covers:<\/p>\n<ol>\n<li>Take a look at a sample web app<\/li>\n<li>Set up a small <code>express.js<\/code> server to serve the web app<\/li>\n<li>Install and configure Rendertron as a middleware for dynamic rendering<\/li>\n<\/ol>\n<h2 id=\"the-sample-web-app\" tabindex=\"-1\">The sample web app<\/h2>\n<p>\n  <a href=\"https:\/\/kitten-corner.glitch.me\/\" class=\"external-link\">The &#8220;kitten corner&#8221; web app<\/a><br \/>\n  uses JavaScript to load a variety of cat images from an API and displays them in a grid.\n<\/p>\n<p><img decoding=\"async\"\n     src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-5c14bd6ff47f.png\" loading=\"lazy\"\n     alt=\"Cute cat images in a grid and a button to show more - this web app truly has it all!\" \/><\/p>\n<p>Here is the JavaScript:<\/p>\n<div><\/div>\n<p>\n  The web app uses modern JavaScript (ES6), which<br \/>\n  <a href=\"https:\/\/alienroad.com\/google-bilgi-bankasi\/fix-javascript-problems\/\">isn&#8217;t supported in Googlebot yet<\/a>. We can use the<br \/>\n  <a href=\"https:\/\/developer.chrome.com\/docs\/lighthouse\/overview\" class=\"external-link\">mobile-friendly test<\/a> to check if<br \/>\n  Googlebot can see the content:\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-c11335132871.png\" loading=\"lazy\"\n     alt=\"The mobile-friendly test shows that the page is mobile-friendly, but the screenshot is\n          missing all the cats! The headline and button appear but none of the cat pictures are\n          there.\" \/><\/p>\n<p>\n  While this problem is simple to fix, it&#8217;s a good exercise to learn how to setup dynamic rendering.<br \/>\n  Dynamic rendering will allow Googlebot to see the cat pictures without changes to the web app<br \/>\n  code.\n<\/p>\n<h2 id=\"set-up-the-server\" tabindex=\"-1\">Set up the server<\/h2>\n<p>\n  To serve the web application, let&#8217;s use<br \/>\n  <a href=\"https:\/\/expressjs.com\/\" class=\"external-link\"><code>express<\/code><\/a>, a <code>node.js<\/code><br \/>\n  library, to build web servers.\n<\/p>\n<p>\n  The server code looks like this (find the<br \/>\n  <a href=\"https:\/\/glitch.com\/edit\/#!\/kitten-corner?path=server.js:1:1\" class=\"external-link\">full project source code<\/a><br \/>\n  here):\n<\/p>\n<div><\/div>\n<p>\n  You can<br \/>\n  <a href=\"https:\/\/kitten-corner.glitch.me\/\" class=\"external-link\">try the live example<\/a> &#8211; you<br \/>\n  should see a bunch of cat pictures, if you are using a modern browser. To run the project from<br \/>\n  your computer, you need<br \/>\n  <a href=\"https:\/\/nodejs.org\/en\/\" class=\"external-link\"><code>node.js<\/code><\/a> to run the following<br \/>\n  commands:\n<\/p>\n<div><\/div>\n<p>\n  Then point your browser to<br \/>\n  <a href=\"https:\/\/alienroad.com\/\" class=\"external-link\"><code>https:\/\/alienroad.com<\/code><\/a>.<br \/>\n  Now it&#8217;s time to set up dynamic rendering.\n<\/p>\n<h2 id=\"deploy-a-rendertron-instance\" tabindex=\"-1\">Deploy a Rendertron instance<\/h2>\n<p>\n  Rendertron runs a server that takes a URL and returns static HTML for the URL by using headless<br \/>\n  Chromium. We&#8217;ll follow<br \/>\n  <a href=\"https:\/\/github.com\/GoogleChrome\/rendertron#deploying-to-google-cloud-platform\" class=\"external-link\">the recommendation from the Rendertron project<\/a><br \/>\n  and use<br \/>\n  <a href=\"https:\/\/console.cloud.google.com\/\" class=\"external-link\">Google Cloud Platform<\/a>.\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-c56edfd14d41.png\" loading=\"lazy\"\n     alt=\"The form to create a new Google Cloud Platform project.\" \/><\/p>\n<p>\n  Please note that you can get started with<br \/>\n  <a href=\"https:\/\/cloud.google.com\/free\/docs\/always-free-usage-limits\" class=\"external-link\">the usage tier that&#8217;s available without payment<\/a>;<br \/>\n  using this setup in production may incur costs according to the<br \/>\n  <a href=\"https:\/\/cloud.google.com\/pricing\/\" class=\"external-link\">Google Cloud Platform pricing<\/a>.\n<\/p>\n<ol>\n<li>\n    Create a new project in the<br \/>\n    <a href=\"https:\/\/console.cloud.google.com\/\" class=\"external-link\">Google Cloud console<\/a>. Take note<br \/>\n    of the &#8220;Project ID&#8221; below the input field.\n  <\/li>\n<li>\n    Install the <a href=\"https:\/\/cloud.google.com\/sdk\/docs\/quickstarts\" class=\"external-link\">Google Cloud SDK as described in the documentation<\/a><br \/>\n    and log in.\n  <\/li>\n<li>\n    Clone the Rendertron repository from GitHub with:<\/p>\n<div><\/div>\n<\/li>\n<li>\n    Run the following commands to install dependencies and build Rendertron on your computer:<\/p>\n<div><\/div>\n<\/li>\n<li>\n    Enable Rendertron&#8217;s cache by creating a new file called <code>config.json<\/code> in the<br \/>\n    rendertron directory with the following content:<\/p>\n<div><\/div>\n<\/li>\n<li>\n    Run the following command from the rendertron directory. Substitute<br \/>\n    <code><var>YOUR_PROJECT_ID<\/var><\/code> with your project ID from step 1.<\/p>\n<div><\/div>\n<\/li>\n<li>Select a region of your choice and confirm the deployment. Wait for it to finish.<\/li>\n<li>Enter the URL <code><var>YOUR_PROJECT_ID<\/var>.appspot.com<\/code>. You should see Rendertron&#8217;s<br \/>\n    interface with an input field and a few buttons.\n  <\/li>\n<\/ol>\n<p><img decoding=\"async\" src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-2c854b8f12f4.png\" loading=\"lazy\"\n     alt=\"Rendertron's UI after deploying to Google Cloud Platform\" \/><\/p>\n<p>\n  When you see the Rendertron web interface, you have successfully deployed your own Rendertron<br \/>\n  instance. Take note of your project&#8217;s URL (<code><var>YOUR_PROJECT_ID<\/var>.appspot.com<\/code>) as<br \/>\n  you will need it in the next part of the process.\n<\/p>\n<h2 id=\"add-rendertron-to-the-server\" tabindex=\"-1\">Add Rendertron to the server<\/h2>\n<p>\n  The web server is using <code>express.js<\/code> and Rendertron has an <code>express.js<\/code><br \/>\n  middleware. Run the following command in the directory of the <code>server.js<\/code> file:\n<\/p>\n<div><\/div>\n<p>\n  This command installs the rendertron-middleware from npm so we can add it to the server:\n<\/p>\n<div><\/div>\n<h2 id=\"configure-the-bot-list\" tabindex=\"-1\">Configure the bot list<\/h2>\n<p>\n  Rendertron uses the <code>user-agent<\/code> HTTP header to determine if a request comes from a bot<br \/>\n  or a user&#8217;s browser. It has a<br \/>\n  <a href=\"https:\/\/github.com\/GoogleChrome\/rendertron\/blob\/30446bd7caae87de9fcd8c8263b588c350130852\/middleware\/src\/middleware.ts#L24-L41\" class=\"external-link\">well-maintained list of bot user agents<\/a><br \/>\n  to compare with. By default this list does not include Googlebot, because Googlebot can execute<br \/>\n  JavaScript. To make Rendertron render Googlebot requests as well, add Googlebot to the list of<br \/>\n  user agents:\n<\/p>\n<div><\/div>\n<p>\n  Rendertron compares the <code>user-agent<\/code> header against this regular expression later.\n<\/p>\n<h2 id=\"add-the-middleware\" tabindex=\"-1\">Add the middleware<\/h2>\n<p>\n  To send bot requests to the Rendertron instance, we need to add the middleware to our<br \/>\n  <code>express.js<\/code> server. The middleware checks the requesting user agent and forwards<br \/>\n  requests from known bots to the Rendertron instance. Add the following code to server.js and don&#8217;t<br \/>\n  forget to substitute <code><var>YOUR_PROJECT_ID<\/var><\/code> with your Google Cloud Platform<br \/>\n  project ID:\n<\/p>\n<div><\/div>\n<p>\n  Bots requesting the sample website receive the static HTML from Rendertron, so the bots don&#8217;t need<br \/>\n  to run JavaScript to display the content.\n<\/p>\n<h2 id=\"testing-our-setup\" tabindex=\"-1\">Testing our setup<\/h2>\n<p>\n  To test if the Rendertron setup was successful, run the Mobile-Friendly Test again.\n<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/alienroad.com\/wp-content\/uploads\/kb-gorsel\/g-43c1cdc766c1.png\" loading=\"lazy\"\n     alt=\"The Mobile-Friendly Test shows that the page is mobile-friendly and the screenshot now has\n          all the missing cats!\" \/><\/p>\n<p>\n  Unlike the first test, the cat pictures are visible. In the HTML tab we can see all HTML the<br \/>\n  JavaScript code generated and that Rendertron has removed the need for JavaScript to display the<br \/>\n  content.\n<\/p>\n<h2 id=\"conclusion\" tabindex=\"-1\">Conclusion<\/h2>\n<p>\n  You created a dynamic rendering setup without making any changes to the web app. With these<br \/>\n  changes, you can serve a static HTML version of the web app to crawlers.\n<\/p>\n<p class=\"byline-author\">Posted by <a href=\"https:\/\/developers.google.com\/search\/blog\/authors\/martin-splitt\">Martin Splitt<\/a>, Open Web Unicorn<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Thursday, January 31, 2019 Many frontend frameworks rely on JavaScript to show content. This can mean Google might take some time to index your content or update the indexed content. A workaround we discussed at Google I\/O this year is dynamic rendering. There are many ways to implement this. This blog post shows an example [&hellip;]<\/p>\n","protected":false},"menu_order":82073,"template":"","meta":{"footnotes":""},"ar_kb_kategori":[665],"ar_kb_etiket":[],"class_list":["post-25055","ar_kb","type-ar_kb","status-publish","has-post-thumbnail","hentry","ar_kb_kategori-blog"],"_links":{"self":[{"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/ar_kb\/25055","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/ar_kb"}],"about":[{"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/types\/ar_kb"}],"version-history":[{"count":0,"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/ar_kb\/25055\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/media\/27188"}],"wp:attachment":[{"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/media?parent=25055"}],"wp:term":[{"taxonomy":"ar_kb_kategori","embeddable":true,"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/ar_kb_kategori?post=25055"},{"taxonomy":"ar_kb_etiket","embeddable":true,"href":"https:\/\/alienroad.com\/wp-json\/wp\/v2\/ar_kb_etiket?post=25055"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}