š Try Recall with a 7 day free trial!
August 22, 2022
Michael Salim
@IAmMichaelSalimCreated using Midjourney - "japanese worker getting stressed in the office, black clothes, office setting, high stakes, monotone, high detail, 8k, --q 2 --ar 16:9"
Creating this blog section should be easy, right?
Well, hereās what happened:
The project is built on Next.js. It just happened that I had code lying around on my personal website for my own blog. Easy copy paste job right? Unfortunately, because these pages will be pre-rendered by Next.js, there were some issues.
For one, the whole project is currently server rendered. One assumption was on
the environment variable. The code is relying on the fact that ROOT_URL
can be
found. The problem is that the variable is not built in. This is so that we can
change the variable without rebuilding the docker image. This is problematic
since that functionality will be broken. Thereās also some guards preventing
this from happening.
After some thinking, I decided to remove that functionality. It just doesnāt bring enough benefit to offset the downside.
In the first place, how often am I going to change the ROOT_URL
? Probably
never. And a docker build is just a command away.
Recall uses GraphQL and Apollo for most of its queries. Getting it to work with SSR can be finicky. I use the next-with-apollo library to get this to play nicely.
All this was handled in the _app.tsx
file. For those that donāt know, changes
to this file is propagated to all your pages. Convenient if you have code that
needs to run everywhere.
Apollo was also initiated here. This suddenly became an issue since some pages will be SSR and some will be static. So what do we do with Apollo?
According to next-with-apollo
's documentation, any page with getInitialProps
or getDataFromTree
will be SSR.
So:
We canāt keep the logic in _app.tsx
anymore since we canāt change how that
renders depending on the page. Those that need SSR needs the getDataFromTree
prop. Meanwhile, static page need them gone.
There are 2 options:
ApolloProvider
without SSR. Then wrap another ApolloProvider
if we need the SSR capability (or the reverse). I tried it but there are
issues with multiple provider when doing SSR.I didnāt want to do the 3rd option. But I experimented with the first 2 along with other ideas. Those didnāt get anywhere. After a good night sleep, I decided to go ahead with it.
After some work, I did it! I just need to wrap a withApollo
or withApolloSSR
on every page.
Nope.
Each page can be rendered just fine when you open them directly. However,
navigating from a page to another page wasnāt working. Apollo complained that it
canāt find the ApolloProvider
. This is odd. But after debugging some more, I
decided that this is a lost cause.
So what now?
There was another option that dare not dream. Run another Next.JS instance. One for SSR, one for those that can be statically generated. I could redirect the request to the correct instance.
With no other options in mind, I started working on a proof of concept. It didnāt go well.
Running 2 next instance in a custom server was not a good fit. I donāt even want to think about all the other issues ā having to write in the correct place, having to handle the routing. What about development built?
Maybe I could build and export one of it? But it was too much work.
I was devastated. All this work for nothing. Is it time to call it quits and revert everything?
New feature to come:
ā Michael Salim (@IamMichaelSalim) August 21, 2022
Me: Oh, I can just copy this from another project. It's a 1 hour job.
Also me: Proceeds to unravel an issue 3 levels deep and now wondering if I should find a new career.#buildinpublic
The fact that this āblogā exists means that something went well š
I realized something:
I canāt get _app.tsx
to change. But what if i modify the getDataFromTree
method to be smart instead? Then that page can stay the same.
Diving deep into the next-with-apollo
package,
I found this line.
We want Apollo to be SSR when it runs in the server. So I just need to add a check for that.
As if by magic. Everything is solved.
After all thatā¦ Just a single line to patchš¤¦š»āāļø. Ok, there's a few more lines but they were trivial :)
There must be something to learn out of this. Well, thatās up to you to get something out of this!
Maybe think before you code? Or perhaps donāt work during the weekend š. Or maybe donāt sleep at 5am š¶
Like this kind of content? Why not see the reason I started writing TinyLog