Yes, here are 4 ways to handle SEO with Vue (even without Node SSR)

Why do everyone think SSR with Node is the only solution, when it comes to SEO with frontend frameworks?

Back in 2014 when SSR was not a thing, people were already asking “how to handle SEO with AngularJS?”.

Now, I often is see “how to handle SEO with Vue?”, and the answers are always: “use Nuxt” or “use SSR”.

Not everyone can have a Node server for their project. And there may be a lot of reasons for that: shared webhost, no root access…

But a better question is “how to handle SEO in a SPA (Single Page Application)”, and my answer is: SSR is not the only solution.

So here are 4 ways to handle SEO in 2021 with an SPA.

PS: I’ll use Vue as an example, but they all work for most frameworks.

1. SEO on the client side with Google crawlers

React, Vue, Svelte… All these are frontend frameworks initially used to create SPAs, aka websites/webapps with CSR (Client Side Rendering).

What does this mean? It means the rendering is done in the browser. Therefore, the HTML sent to the browser & search engine crawlers is empty!

No HTML content = No SEO.

Usually, you have a basic index.html file with hard-coded title and meta tags.

Basic SPA entry point (index.html file)

This is how a SPA / CSR usuallly works:

  1. An initial request to whatever server to get the HTML file above
  2. Server returns the static HTML file
  3. Browser loads, executes and renders CSS & JS
  4. During client navigation, AJAX requests are done to the API server
  5. The API server returns data (usually JSON)
  6. The browser updates the current page
SPA/CSR rendering lifecycle

In 2015 Google said they could parse JS,horray 🎉 (or not).https://developers.google.com/search/blog/2015/10/deprecating-our-ajax-crawling-scheme.

SEO with client side rendering has it’s drawbacks:

  • Only Google seems to do it right for now
  • Does not work on social media crawlers (Facebook, Twitter, LinkedIn…)
  • UX: Rendering is slower for users because initial data is fetched on client
  • Based on some “strict” rules

Here’s what Google says about it: https://developers.google.com/search/docs/guides/javascript-seo-basics

Rememer, you need to handle SEO tags (title, meta…) on the client side! You can use or for that (personally, I prefer ).

As you can see, it’s easy to setup.

You don’t need a particular server or anything, but it’s not the best way and not optimized for social media (SMO).

Especially if your content must be sharable. That’s why SSR was invented!

2. SEO with Node-based Server Side Rendering (SSR)

So SSR aka Sever Side Rendering, is a “new” concept that came with frontend frameworks. It’s based on Isomorphic programming which means the same app and code is executed on backend context and frontend context.

It was brought by Meteor JS. It’s only possible because Node uses JS.

But SSR is not so new.

It’s acatually a bad chosen name because, Server Side Rendering is what classic backend languages do since day 1.

Any backend language that renders HTML as a response to a browser request, is server side rendering.

But this “new” SSR is based on hydration, that’s what makes it special: https://ssr.vuejs.org/guide/hydration.html.

Anyway, in this method, we’ll be talking about the “new” kind of SSR that was created for frontend frameworks.

Because your app is executed on the backend, the server returns your component tree as an HTML string to the browser.

This only happens on first load. After loading, the SPA comes in, and navigation would be client-side-only like as usual.

What does this mean? Since each initial request is done by a Node server that sends HTML, this even works for social media crawlers or any other crawler.

Just like a regular monolithic app with PHP/Python/Ruby On Rails etc.

Initial browser request to a Node-based SSR server

After that, it works like a regular SPA after hydration I talked about earlier.

After the initial load, all requests go directly from the client to the API server, no need to go through the rendering server again

SSR with Vue can be done in 2 ways, DIY or with a framework on top of Vue:

You have similar stuff on React & Svelte.

Of course, SEO with Node-based SSR has it’s drawbacks:

You need… A Node server! Don’t worry, you only need it for the initial HTML rendering, not for your API.

Your API could be handled by any other server/backend language.

But, what if I told you that you could acheive a similar result using “regular” server side rendering (with PHP/Python/Ruby on Rails etc)?

Yes, it’s possible, let’s see how!

3. SEO using “classic” Server Side Rendering (SSR)

So, based on what we learnt in 1 & 2, we can acheive something similar with a any backend language.

What did we learn?

  • Google crawler can parse JavaScript
  • Social media crawlers can’t, therefore they can’t read title & meta tags
  • We need data in the initial request for faster rendering

To solve this, we need to do 4 actions with any type of backend:

  1. Use a backend router that mirrors the frontend router, so that the initial response can render content based on the url asked
  2. In the backend reponse, we will only generate title & meta tags since our backend can’t execute frontend code
  3. We will store some initial data in a variable on the window object so that the SPA can access it at runtime on the client
  4. On the client, you check if there’s data on the window object. If there is, you have nothing to do. If there isn’t, you do a request to the API server.

Example: let’s say I have a Vue app with 4 routes:

  • Home: /
  • About: /about
  • Posts: /posts/:id
  • Private pages: /private/:page

On my backend (Laravel in this case), I’ll have the same routes.

Backend routes mirroring

Remember, this is just an example. In real life I would have controllers of course 😅, this is just to show you the concept.

Let’s see the what the view “seoView” contains.

Backend view used as response for the initial request

That’s pretty much it for the backend, nothing more. You only need a single “view” file that takes title, meta, initialData or whatever parameters you need for SEO/SMO and that’s it.

The “window.initialData = @ json($state)” is also very important here, but not mandatory for SEO. It’s for performance/UX purposes. It’s just for you to have initial data in the frontend, to avoid an initial AJAX request to your API server.

Here’s how to use it for the /posts/:id route for example:

In a nutshell: you check if initialData exists, use it if does, or get it from the API Server if it doesn’t.

This could be done in any other lifecyle hook or method. Another way to use it could be to store the initial data in your Vuex state for example.

In most cases, the title and meta tags are the most important to render from the backend, for the rest, Google can parse and crawl your JavaScript.

Of course, SEO with classic SSR has it’s drawbacks:

  • You have to mirror each route were you need SEO on the backend
  • You have to pass “the same data” to the frontend and to APIs, sometimes if feels like duplicating stuff

But all things considered, this technique works damn well and I use it in production for a very big app. Actually carrefour.fr, a Fortune 40 company in France also uses this technique with Vue JS and Sympfony (PHP).

There are some cases where, you don’t need “dynamic” rendering from the server for each request. That’s where JAMStack come’s in.

4. JAMStack aka Static Site Generation aka Prerendering

This is my the method I love the most, but it isn’t meant for all situations.

So what is JAMStack? Well it’s a fancy word for something that existed before that we called: static websites.

When the web was created, we only did pure HTML files that always returned the same content. That’s what we refer to as “static content”.

It was a bit cumbersome, that’s when they invented “dynamic websites” which is what we previously called: server side rendering.

But! Somewhere in 2008/2009, something came out and got popular in 2011/2012: Jekyll, the Static Site Generator.

Basically it was a Ruby app, that would generate static files from route definitions and data you would give to it at build-time.

That’s what we refer to as: prerendering.

It was only static files so… It was fast. Really fast.

That meant, each time you needed to update your website with fresh content, you had to prerender the website again.

No biggie. CI/CD is your friend.

So what’s JAMStack then? JavaScript API Markup.

JAMStack is the concept of prerendering, but automated and modernized.

It’s an architecture solely based on the fact that you will prerender markup with initial data, that markup would use JavaScript to bring interaction and eventually more data from APIs (yours and/or others).

In a JAMStack architecture, you would usually use a frontend framework to prerender your static files that would then turn to an SPA.

It’s mostly based on the fact that you would rebuild pages on-the-fly anytime data changes in your APIs, through webhooks with CI/CD.

So it’s really nice, but not great for websites/webapps that have daily updates with a lot of pages.

Why? Because all pages are regenerated each time.

It’s the fastest, most SEO-friendly and “cheapest” method.

You only need your API server, a static host (Netlify, Vercel, S3, Firebase Hosting, etc…), and a CI/CD system for rebuilds which you most likely already have to handle tests or deployment.

Prerendering tools

  • VuePress/VitePress: /

Any other SSG (static site generator) would be good but, you won’t have hydration with those not Vue-driven.

APIs: You can create your own API but, usually when you do JAMStack, it’s for content-drive websites/webapps. That’s why we often use what we call: Headless CMSs.

A headless CMS, is a CMS that can render HTTP APIs as a response.

There are many of them: Strapi, Directus (Node), WordPress (yep it can), Cockpit CMS (PHP), Contentful, Dato, Prismic (hosted)…

You can find more here: https://jamstack.org/headless-cms

Conclusion: What’s the best SEO method then?

There isn’t a silver bullet. It depends on your stack, budget, team, type of app and some other parameters.

In a nutshell, I would say:

  • If you don’t care a lot about it: an optimized SPA with Vue meta is fine
  • If you can use Node: do Node-based SSR
  • If you can’t use Node: do classic SSR with initial data rendering
  • If you don’t have daily page updates or too many pages: JAMStack

That’s it. Remember: there’s never ONLY ONE WAY to do something.

Tanks for reading.

PS: If you want some time-to-time Vue/Frontend news, signup to my newsletter: https://maisonfutari.com

Yes, here are 4 ways to handle SEO with Vue (even without Node SSR) was originally published in ITNEXT on Medium, where people are continuing the conversation by highlighting and responding to this story.

Translate »