📖 Summary
Recently my team started a project of a landing page and we chose to use Gatsby in order to have good SEO.
At a point in our project, the designers changed the mobile layouts to be a SPA, and the desktop ones still having different routes and pages.
Refer to that example:
Since Gatsby creates pages in build time, we don’t know if the environment is mobile or desktop, it’s difficult to think in a way to deal with that behavior.
🐛 Workaround
One quick way that our team thought to temporarily resolve that problem was to map
between sections and hide than in desktop screens.
And the biggest problem is: On the first load of the page the content takes almost a second to load because it’s not static anymore.
<div>
{
breakpoints.md
? pages.map((page) => renderPage(page))
: renderPage(selectedPageRef.current)
}
</div>
🚀 Goals
I would like to discuss about a solution that will change the behavior of the pages in desktop and mobile without killing the SEO of the application.
2
Answers
If you can’t solve by using
mediaqueries
and you must display two different components rather than the same styled. The workaround to solve this is to check what is thewindow
size at the rendered time and show one layout or another. It would create a minimum delay (insignificant if cached) before the header is shown but this is the only way I am able to guess.So, using Gatsby’s default structure in
<Layout>
component you should have something like that:So, in your
<Header>
component you should check yourwindow
size and render one component or another:As you can see, in the return I check if
window
is defined in a ternary chained condition. If thewindow
is not defined (i.e: isundefined
) it returns anull
. If it’s defined, it checks the current window’s width (currentWidth
) and there’s another ternary condition that displays the mobile or the desktop menu.As a best practice, chained ternaries are not the cleanest solution, they are difficult to read and maintain but for now, the solution works (and of course it must be refactored).
In this case,
useWindowWidth()
is a custom hook that calculates in everywindow
the size but you can use whatever you like. It looks like:Code provided by: https://usehooks.com/useWindowSize/
Note that it’s common in Gatsby’s projects to check if the
window
is!==
thanundefined
due to the point you argued. At the compilation/build point isn’t defined yet. You can check for further information about Debugging HTML Builds in their documentation.First, you can achieve the following with the help of CSS media query (hide the sidebar or transform it to be the top nav):
Then, you can set up a useMediaQuery hook (for example here is an implementation) to conditionally render the
About
andEvents
components in one of the two ways shown below:A) If most users are using desktop, you can defer the import of the other two components (About and Events) in mobile view with loadable-components:
The Index page will look something like this:
B) If most users are using mobile, you can include the two components in the main bundle at build time:
The Index page will look something like this:
Regarding SEO, the search engine will only see the main component (Home in route “/”, About in “/about”, etc) since
isMobile
defaults tonull
at build time in the above implementations.Regarding speed, the main components are statically rendered in the HTML. Only in mobile SPA view, other sections are needed to be loaded.