JS SEO

JS SEO

Javascript Frameworks & SEO

1a73ecdb082f212bf8d81eb9a3a53e29?s=128

Jecelyn Yeen

October 22, 2019
Tweet

Transcript

  1. JavaScript Frameworks & SEO What, Why and How v Modern

  2. @JecelynYeen Software Architect Google Developer Expert - Angular - Web

    Technologies Director - NG-MY 2019 - Women Who Code KL
  3. - What is SEO? - How does Googlebot works? -

    Technical SEO for modern frameworks - Best Practices - Resources
  4. 4 What is SEO?

  5. - Content - Strategy - Technical SEO

  6. SEO without Content & Strategy =

  7. 7 How does Googlebot works?

  8. How a page get into Google Search?

  9. Crawl Queue Crawler Processing Index

  10. Wait….What about them?

  11. <body> <div id="app"></div> <script src="runtime.js"></script> <script src="polyfills.js"></script> <script src="main.js"></script> </body>

  12. Some crawlers might not run JavaScript...

  13. Googlebot run JavaScript

  14. Crawl Queue Crawler Index Processing Render Queue Renderer

  15. Sometimes it can take up to a week before the

    render is complete
  16. Over 130 trillions documents on the web Data from July

    2016
  17. Googlebot is now evergreen (announced in May 2019) goo.gle/evergreen-googlebot

  18. Crawl Queue Crawler Index Processing Render Queue Renderer Ranking

  19. - Crawling - Rendering - Indexing

  20. 20 Technical SEO for JS Frameworks

  21. Helping Googlebot - Links your pages to each other -

    Googlebot doesn’t click on stuffs, use links! - Do not use hash URLs (/#products) - Exclude low quality / thin content - Create a sitemap
  22. Use proper title & meta tags

  23. None
  24. None
  25. <title>NG-MY 2019: July 06-07</title> <meta name="description" content="NG-MY 2019. Angular Malaysia

    conference. First in Southeast Asia."> Title tag & Meta tags are essential for SEO
  26. <meta property="og:url" content="https://2019.ng-my.org/" /> <meta property="og:description" content="NG-MY 2019..."> <meta property="og:type"

    content="website" /> <meta property="og:title" content="..." /> <meta property="og:image" content="img.png" /> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:image" content="img.png"> Meta tags for social medias
  27. - Angular Title & Meta Service (built in) angular.io/api/platform-browser/Meta -

    Vue (3rd party) github.com/declandewet/vue-meta - React (3rd party) github.com/nfl/react-helmet
  28. export class SpeakerPageComponent { } Example: Angular Set page title

    Update meta tag Inject title & meta services constructor(private title: Title, private meta: Meta) {} ngOnInit() { this.title.setTitle(‘title’); this.meta.updateTag({ name: 'description', content: ‘desc…’ }); this.meta.updateTag({ name: 'twitter:image', content: ‘imgurl’ }); ... }
  29. ngOnInit() { this.meta.updateTag({ name: 'robots', content: ‘noindex’ }); ... }

    export class HiddenPageComponent { } Exclude content from Index Set page title Inject title & meta services constructor(private title: Title, private meta: Meta) {}
  30. Duplicated Content - /speakers/jecelyn - /speakers/Jecelyn - /speakers/8 - /speakers?id=8

    Which one to show in search result?
  31. Set canonical url for duplicate content <link rel="canonical" href="your_url">

  32. Use robots.txt to prevent crawling User-agent: Googlebot Disallow: /private Everything

    under /private will not be crawled. *will not crawl, but might be indexed
  33. Use with caution!

  34. /api/speakers blocked in robots.txt

  35. Rich result - Make your website shine!

  36. Structured Data schema.org <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "Article",

    "headline": "Cook Weisswurst", "name": "How to Cook Weisswurst", "image": { "@type": "ImageObject", "url": "https://www.wikihow.com/images/...jpg", ... }, ... } </script>
  37. Test with search.google.com/test/rich-results

  38. None
  39. Find out more developers.google.com/search/docs/gui des/search-gallery

  40. Mobile page speed matters to SEO Page Ranking https://webmasters.googleblog.com/2018/01/usi ng-page-speed-in-mobile-search.html

  41. Server Side Rendering (SSR)

  42. ➔ Angular -> Angular Universal ➔ React -> Next.js ➔

    Vue -> Nuxt.js
  43. Dynamic Rendering https://developers.google.com/search/docs/guides/dynamic-rendering

  44. Switching between client side rendered and pre-rendered content for specific

    user agents
  45. User Browser Web Server HTML + JS for client side

    rendering (Not a bot) Request with browser user agent
  46. Googlebot Crawler Web Server HTML + JS for client side

    rendering Dynamic render Complete static html (I am a bot) Request with Googlebot user agent
  47. Dynamic Rendering - It is a workaround! - Tools -

    github.com/GoogleChrome/puppeteer - github.com/GoogleChrome/rendertron - prerender.io/ - Codelabs: goo.gle/rendertron-codelab
  48. Static Rendering

  49. Static rendering happens at build-time at build time to produce

    static files. Get meaningful content onto the user's screen faster
  50. Static Prerendering cli build --prod Generate files to dist/ Open

    browser Browse & Save each route as .html Deploy all files to server Generate static html pages = Prerendering Local serve dist/
  51. Static Prerendering cli build --prod Generate files to dist/ Program

    Puppeteer Browse & Save each route as .html Deploy all files to server Automate with Puppeteer Local serve dist/
  52. Puppeteer - Programmable Chrome Browser const puppeteer = require('puppeteer'); (async

    () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); })(); const fs = require('fs').promises; await fs.writeFile('food.html', html, 'utf-8'); await browser.close(); await page.goto('https://ng-my.org/food', { waitUntil: 'networkidle2'}); const html = await page.content();
  53. Static Prerendering cli build --prod Generate files to dist/ Program

    Puppeteer Browse & Save each route as .html Deploy all files to server Find an even easier library to help us! Local serve dist/
  54. Static Rendering Solution - Webpack - npmjs.com/package/prerender-spa-plugin - github.com/GoogleChromeLabs/prerender-loader -

    General - github.com/chybie/prerender-xs
  55. Prerendering // prerender-run.js const { prerenderer } = require('prerender-xs'); const

    path = require('path'); const minimalConfig = { routes: ['/', '/route1', '/route2/b'], // all the routes staticDir: path.join(__dirname, '/dist'), // where your SPA located } const data = await prerenderer(minimalConfig); // node prerender-run.js
  56. SSR / Dynamic (puppeteer, rendertron) Static (prerender-spa-plugin) - Rapid changing

    content that always change (e.g. news) - Require a server - Dynamic Rendering is a workaround - SSR increase complexity* - Predictable content (e.g. company site, event site) - Can host in cloud storage (S3, Firebase hosting)
  57. Video series: goo.gle/js-seo-videos

  58. You don’t need SEO if your pages are behind login

  59. 59 What else can go wrong? (Best Practices)

  60. Oops, errors!

  61. None
  62. Handle errors properly.

  63. Redirect to 404 fetch('/api/speakers/jane-doe') .then(res => res.json) .then(speaker => {

    if (!speaker.exists) window.location.href = '/404'; });
  64. No index when result not found fetch('/api/speakers/jane-doe') .then(res => res.json)

    .then(speaker => { if (!speaker.exists) this.meta.updateTag({ name: 'robots', content: 'noindex' }); });
  65. Googlebot is stateless…

  66. Which means… No Service Workers local storage, session storage, IndexedDB,

    Web SQL, Cookies or Cache API
  67. Page B won’t be indexed // script on page A

    userAgreesGDPRbutton.addEventListener('click', () => { writeCookies('gdpr_agreed', true); }); // script on page B if (!readCookies('gdpr_agreed') { window.location.href='/page-a'; }
  68. Googlebot does not click on stuffs

  69. Which means… Expect Googlebot to decline user permission requests. Handle

    feature detection fallback.
  70. Handle feature detection if ('geolocation' in navigator) { // load

    content once we get location info navigator.geolocation.getCurrentPosition(loadContent); } else { // load fallback content } Uh oh, feature supported but rejected
  71. Handle feature detection if ('geolocation' in navigator) { // load

    content once we get location info navigator.geolocation.getCurrentPosition( loadLocalContent, loadFallbackContent); } else { // load fallback content } Load fallback content
  72. Fix Search-related JavaScript problems goo.gle/search-js-troubleshooter

  73. 73 Tools & Resources

  74. - cards-dev.twitter.com/validator - developers.facebook.com/tools/debug/sharing - search.google.com/test/mobile-friendly Useful validators

  75. None
  76. Mobile friendly test - Screenshot - Loading issues - Rendered

    HTML https://search.google.com/test/mobile-friendly
  77. https://search.google.com/test/mobile-friendly

  78. https://search.google.com/search-console/about

  79. https://developers.google.com/web/tools/lighthouse

  80. SEO Audits - HTTP header responses - Correct meta tags,

    hreflang & descriptive link text - Tap targets sizing - Checking robots.txt - Coming soon: Structured data
  81. Useful resources & references - Headless Chrome: an answer to

    server-side rendering JS sites (link) - Prerendering explained (link) - Get started with dynamic rendering (link) - Google search resources (link) - Rendering on the web (link) - Javascript SEO video series (link) - Technical SEO demystified (link) Office-hours hangouts with the webmaster teams - https://www.google.com/webmasters/connect/
  82. Thank you! Follow @JecelynYeen slides: speakerdeck.com/chybie/js-seo Instagram me! @ngmykia