A notoriously murky area of single-page application (SPA) development is SEO. Depending on who you ask, search engine crawling of client-rendered content is either totally fine, fine as long as it’s synchronous or not at all fine.
Due to the confusion caused by all this conflicting advice, I regularly see the question “is my Vue SPA okay for SEO?” come up in places like the Vue.js Developers Facebook group, the Vue.js Forums and r/vuejs on Reddit.
In this article, we’ll challenge the popular opinions, do doing some basic tests and try to conclude with some sensible advice for building SEO-friendly SPAs.
The issue with client-rendered content
How Googlebot sees an SPA
The quintessential Vue.js SPA example is the Vue HackerNews Clone 2.0. This is an open source project provided by the Vue team to demonstrate the full capabilities of Vue and effective design patterns.
Removing server-side rendering
One of the key features of the Vue HackerNews Clone 2.0 is server-side rendering (SSR). This means, unlike a more basic SPA, the content for each page is rendered on the server and provided to the browser on each page load, just like it were static HTML.
While this test seems to satisfy any concern about client-rendered content, there are some reasons why you shouldn’t have full confidence in it:
- Just because a page can be indexed, doesn’t mean it will rank well
According to this video from Google developers Addy Osmani and Rob Dodson (released Nov 2017), Googlebot is currently based on Chrome 41. There are a lot of new APIs that have been released since version 41, and if you used any of them, presumably Googlebot would not be able to render and index your page.
You may think this is a trivial issue, as you would need to transpile or polyfill such features for older browsers anyway. The point, though, is that you shouldn’t have blind faith in your app being run correctly by every search crawler, just as you wouldn’t have blind faith in your app being run correctly by every browser.
Don’t forget the “O” in “SEO” stands for “optimization”. Being indexed be a search engine is not enough; we want our sites to rank well, too. Fetch As Google tells us how a page is seen, but not how the page compares to the competition.
What to do if SEO is critical
The bottom line is, if SEO is critical, you can’t rely on your SPA’s client rendering and must ensure content comes included in your pages. This doesn’t mean you need to abandon the SPA architecture, though. There are two techniques, server-side rendering and prerendering, that both can achieve the desired outcome.
SSR has its downsides, though:
- Your app will run on each request to the server, adding additional load and slowing responses. Caching can partially alleviate this.
- It’s complicated and time-consuming to implement SSR, so you’ll need more developer hours for the project.
- It only works well with a Node.js backend. SSR can be done with non-Node backends, for example, by using the PHP extension v8js, but such solutions are quite limited.
If you’re keen to implement server-side rendering in a Vue.js SPA, you should begin with the official guide: Vue.js Server-Side Rendering Guide. I’ve also written a guide on implementing SSR with Laravel and Vue.js: Server-Side Rendering With Laravel & Vue.js 2.5.
If you can’t use SSR for one of the above reasons, there is another way: prerendering. With this approach, you run the app with a headless browser in your development environment, snapshot the page output, and substitute your HTML files with this snapshot in the server’s response.
It’s pretty much the same concept as SSR, except it’s done pre-deployment, not on a live server. It’s typically performed with a headless browser like Chrome and can be incorporated into a build flow with Webpack, Gulp etc. The advantage of prerendering is that it doesn’t require a Node.js production server and doesn’t add load to your production server.
However, prerendering also has downsides:
- It doesn’t work well for pages that display changing data, for example, Vue HackerNews.
- It’s not appropriate for pages that have user-specific content e.g. an account page with a user’s personal details. However, these kinds of pages are less critical for SEO; you normally wouldn’t want an account page indexed anyway.
- You’ll need to prerender every route in the app individually, which could take a great amount of time for a large site.