praveenn77 / docusaurus-lunr-search

Local / Offline Search for docusaurus
https://praveenn77.github.io/docusaurus-lunr-search-demo/
MIT License
478 stars 80 forks source link

Documents aren't indexed when root is swizzled to add an authentication #119

Closed phwt closed 11 months ago

phwt commented 11 months ago

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!

praveenn77 commented 11 months ago

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"
phwt commented 11 months ago

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.

phwt commented 11 months ago

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?

praveenn77 commented 11 months ago

Indexing happens during build process, so yes you need to have some condition