I managed to distil my problem into the following code. It works fine with local dev server, but breaks when deployed to Netlify.
The source repo can be found here (branch destilled-netlify-problem
)
The branch is deployed here
I have a primitive Gatsby SPA with client-side routing via Reach Router.
It has two pages, /app/
and /app/team/:teamName
.
The App page should always render a red background, while the Team page should always render a green background
Ant that's it - here is all the relevant code:
// src/pages/app.tsx
import React, { FC } from 'react'
import { RouteComponentProps, Router } from '@reach/router'
import { css } from '@emotion/core'
import { sharedCss } from '../styles'
const appCss = css`
background-color: red;
`
const teamCss = css`
background-color: green;
`
const AppPage: FC<RouteComponentProps> = () => <div css={[appCss, sharedCss]}>App</div>
const TeamPage: FC<RouteComponentProps> = () => <div css={[teamCss, sharedCss]}>Team</div>
const App = () => (
<Router>
<AppPage path="/app/" default />
<TeamPage path="/app/team/:teamName/" />
</Router>
)
export default App
gatsby-node.js
as suggested in Gastsby docs
// /gagsby-node.js
exports.onCreatePage = async ({ page, actions }) => {
const { createPage } = actions
if (page.path.match(/^\/app/)) {
page.matchPath = '/app/*' // eslint-disable-line no-param-reassign
createPage(page)
}
}
Netlify _redirects file - the redirects seem to work as intended
// src/static/_redirects
/app/team/* /app 200
The first load of the Team page renderes the TeamPage
component (the word "Team" is visible) but on red background instead of green - somehow appCss
gets applied instead of teamCss
. Refreshing with f5 fixes this, turning background green. But hard-refreshing with ctrl+f5 loads the broken version again.
I noticed that when the broken page is loading, the word "App" flashes first, before changing to "Team", indicating the AppPage component got rendered first - I suppose that has something to do with the redirect. I guess Emotion doesn't handle the transition well. Is there something I can do, ideally to load TeamPage
right away?
I solved the problem by simply wrapping one of the components in an extra div. This turned out to be sufficient to keep Emotion from confusing the two layouts. The homepage flashing persists, but that's good enough for me for now.
EDIT: Although the empty div solved the problem in the distilled example, I ran into similar css problems deeper in the component tree in my real app. The following hack worked for me, and although not optimal,I am going to settle with it for now. I simply added the following into my Homepage component:
// This is a hack to circumvent a problem with emotion. I need to first mount
// nothing, otherwise wrong css gets applied when redirected via netlify _redirects
const [show, setShow] = useState(false)
useEffect(() => {
setTimeout(() => setShow(true), 1)
}, [])
if (!show) return null
This way Homepage never gets commited, which prevents emotion from carrying over it's styles