Slide 1

Slide 1 text

JavaScript Frameworks & SEO What, Why and How v Modern

Slide 2

Slide 2 text

@JecelynYeen Software Architect Google Developer Expert - Angular - Web Technologies Director - NG-MY 2019 - Women Who Code KL

Slide 3

Slide 3 text

- What is SEO? - How does Googlebot works? - Technical SEO for modern frameworks - Best Practices - Resources

Slide 4

Slide 4 text

4 What is SEO?

Slide 5

Slide 5 text

- Content - Strategy - Technical SEO

Slide 6

Slide 6 text

SEO without Content & Strategy =

Slide 7

Slide 7 text

7 How does Googlebot works?

Slide 8

Slide 8 text

How a page get into Google Search?

Slide 9

Slide 9 text

Crawl Queue Crawler Processing Index

Slide 10

Slide 10 text

Wait….What about them?

Slide 11

Slide 11 text

Slide 12

Slide 12 text

Some crawlers might not run JavaScript...

Slide 13

Slide 13 text

Googlebot run JavaScript

Slide 14

Slide 14 text

Crawl Queue Crawler Index Processing Render Queue Renderer

Slide 15

Slide 15 text

Sometimes it can take up to a week before the render is complete

Slide 16

Slide 16 text

Over 130 trillions documents on the web Data from July 2016

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

Crawl Queue Crawler Index Processing Render Queue Renderer Ranking

Slide 19

Slide 19 text

- Crawling - Rendering - Indexing

Slide 20

Slide 20 text

20 Technical SEO for JS Frameworks

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Use proper title & meta tags

Slide 23

Slide 23 text

No content

Slide 24

Slide 24 text

No content

Slide 25

Slide 25 text

NG-MY 2019: July 06-07 Title tag & Meta tags are essential for SEO

Slide 26

Slide 26 text

Meta tags for social medias

Slide 27

Slide 27 text

- 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

Slide 28

Slide 28 text

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’ }); ... }

Slide 29

Slide 29 text

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) {}

Slide 30

Slide 30 text

Duplicated Content - /speakers/jecelyn - /speakers/Jecelyn - /speakers/8 - /speakers?id=8 Which one to show in search result?

Slide 31

Slide 31 text

Set canonical url for duplicate content

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

Use with caution!

Slide 34

Slide 34 text

/api/speakers blocked in robots.txt

Slide 35

Slide 35 text

Rich result - Make your website shine!

Slide 36

Slide 36 text

Structured Data schema.org { "@context": "http://schema.org", "@type": "Article", "headline": "Cook Weisswurst", "name": "How to Cook Weisswurst", "image": { "@type": "ImageObject", "url": "https://www.wikihow.com/images/...jpg", ... }, ... }

Slide 37

Slide 37 text

Test with search.google.com/test/rich-results

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Server Side Rendering (SSR)

Slide 42

Slide 42 text

➔ Angular -> Angular Universal ➔ React -> Next.js ➔ Vue -> Nuxt.js

Slide 43

Slide 43 text

Dynamic Rendering https://developers.google.com/search/docs/guides/dynamic-rendering

Slide 44

Slide 44 text

Switching between client side rendered and pre-rendered content for specific user agents

Slide 45

Slide 45 text

User Browser Web Server HTML + JS for client side rendering (Not a bot) Request with browser user agent

Slide 46

Slide 46 text

Googlebot Crawler Web Server HTML + JS for client side rendering Dynamic render Complete static html (I am a bot) Request with Googlebot user agent

Slide 47

Slide 47 text

Dynamic Rendering - It is a workaround! - Tools - github.com/GoogleChrome/puppeteer - github.com/GoogleChrome/rendertron - prerender.io/ - Codelabs: goo.gle/rendertron-codelab

Slide 48

Slide 48 text

Static Rendering

Slide 49

Slide 49 text

Static rendering happens at build-time at build time to produce static files. Get meaningful content onto the user's screen faster

Slide 50

Slide 50 text

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/

Slide 51

Slide 51 text

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/

Slide 52

Slide 52 text

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();

Slide 53

Slide 53 text

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/

Slide 54

Slide 54 text

Static Rendering Solution - Webpack - npmjs.com/package/prerender-spa-plugin - github.com/GoogleChromeLabs/prerender-loader - General - github.com/chybie/prerender-xs

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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)

Slide 57

Slide 57 text

Video series: goo.gle/js-seo-videos

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

59 What else can go wrong? (Best Practices)

Slide 60

Slide 60 text

Oops, errors!

Slide 61

Slide 61 text

No content

Slide 62

Slide 62 text

Handle errors properly.

Slide 63

Slide 63 text

Redirect to 404 fetch('/api/speakers/jane-doe') .then(res => res.json) .then(speaker => { if (!speaker.exists) window.location.href = '/404'; });

Slide 64

Slide 64 text

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' }); });

Slide 65

Slide 65 text

Googlebot is stateless…

Slide 66

Slide 66 text

Which means… No Service Workers local storage, session storage, IndexedDB, Web SQL, Cookies or Cache API

Slide 67

Slide 67 text

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'; }

Slide 68

Slide 68 text

Googlebot does not click on stuffs

Slide 69

Slide 69 text

Which means… Expect Googlebot to decline user permission requests. Handle feature detection fallback.

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

Fix Search-related JavaScript problems goo.gle/search-js-troubleshooter

Slide 73

Slide 73 text

73 Tools & Resources

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

No content

Slide 76

Slide 76 text

Mobile friendly test - Screenshot - Loading issues - Rendered HTML https://search.google.com/test/mobile-friendly

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

SEO Audits - HTTP header responses - Correct meta tags, hreflang & descriptive link text - Tap targets sizing - Checking robots.txt - Coming soon: Structured data

Slide 81

Slide 81 text

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/

Slide 82

Slide 82 text

Thank you! Follow @JecelynYeen slides: speakerdeck.com/chybie/js-seo Instagram me! @ngmykia