Documents aren't indexed when root is swizzled to add an authentication
phwt opened this issue · 4 comments
Hello, I've implemented an authentication that requires wrapping the root component with the authentication provider and checking access before displaying the content as shown below:
/src/theme/Root.tsx
import React from "react"
import App from "../components/App"
import { AuthProvider } from "..."
const Root = ({ children }) => (
<AuthProvider>
<App>{children}</App>
</AuthProvider>
)
export default Root
/src/components/App.tsx
import React, { useEffect } from "react"
import { useAuth } from "..."
const UnauthenticatedRedirect = () => {
useEffect(() => {
// Do some redirection
}, []);
return <>You are now being redirected</>
};
const App = ({ children }) => {
const { isAuthenticated } = useAuth()
if (isAuthenticated) {
return <>{children}</>
}
return <UnauthenticatedRedirect />
};
export default App
Basically, it will check if a user is authenticated before displaying the content, if not the user will be redirected to complete the sign-in first.
The authentication works fine but now the documents aren't being indexed.
docusaurus-lunr-search:: Start scanning documents in 8 threads
docusaurus-lunr-search:: Indexing time: 1.594s
docusaurus-lunr-search:: indexed 0 documents out of 95
After further investigation, I found that because in the App.tsx
the isAuthenticated
will always be false
during build and indexing which will result in children
not being returned and the page content cannot be indexed.
Workaround
A workaround is to render the children
during the build-time where the contents will be indexed. With the help of isBrowser
and npm_lifecycle_event
. I was able to make the indexing work while having the authentication check as in the code shown below:
import React, { useEffect } from "react"
import { useAuth } from "..."
import useIsBrowser from "@docusaurus/useIsBrowser"
const UnauthenticatedRedirect = () => {
useEffect(() => {
// Do some redirection
}, []);
return <>You are now being redirected</>
};
const App = ({ children }) => {
const { isAuthenticated } = useAuth()
const isBrowser = useIsBrowser()
// `!isBrowser` is added to prevent undefined `process` error when running in browser
const isBuildStage = !isBrowser && process.env.npm_lifecycle_event === "build"
if (isAuthenticated || isBuildStage) {
return <>{children}</>
}
return <UnauthenticatedRedirect />
};
export default App
But this is a workaround and not a solution as I found that the isBuildStage
is true
when the page is first loaded and later false
as intended. This makes the site's content briefly visible to the user before they are redirected. (I don't know why isBrowser
is false
and process
is not undefined on the first load).
Hope anyone can help me with this, thanks!
As mentioned here https://docusaurus.io/docs/advanced/ssg#useisbrowser useIsBrowser
will become true only after first render.
Alternatively you can usetypeof window !== 'undefined'
const isBuildStage = typeof window !== 'undefined' && process.env.npm_lifecycle_event === "build"
Or you can also just use process env alone with optional chanining
// This will work fine in browser as well
const isBuildStage = process?.env?.npm_lifecycle_event === "build"
Thanks for pointing out! Looks like this is a Docusaurus related issue rather than the plugin itself.
Will update and close the issue after I can get auth working with this great plugin.
Also, I was wondering is it possible to make auth work without conditionally rendering the root?
Or the content must always be visible (returned) for the indexing to work?
Indexing happens during build process, so yes you need to have some condition