【问题标题】:Next js app with SSR is not pre-rendering HTML, so web-scrapers cannot access the contentNext js app with SSR is not pre-rendering HTML, so web-scrapers cannot access the content
【发布时间】:2022-12-19 09:55:20
【问题描述】:

I have a next.js app that uses server side rendering. When running the application both locally and in production (on vercel edge), the initial page response is returning what looks like a javascript bundle, and not the fully rendered HTML page. This means that all my SEO is made redundant, as the first response does not contain any of the <meta/> tags that I have defined. The page renders correctly in the browser, but I assume web scrapers only look at the initial response from the server.

Within the network tab, the first response with the "document" initiator contains the following:

<!DOCTYPE html>
<html>

<head>
  <style data-next-hide-fouc="true">
    body {
      display: none
    }
  </style><noscript data-next-hide-fouc="true">
    <style>
      body {
        display: block
      }
    </style>
  </noscript>
  <meta charSet="utf-8" />
  <meta name="viewport" content="width=device-width" />
  <meta name="next-head-count" content="2" /><noscript data-n-css=""></noscript>
  <script defer="" nomodule="" src="/_next/static/chunks/polyfills.js?ts=1665897162450"></script>
  <script src="/_next/static/chunks/webpack.js?ts=1665897162450" defer=""></script>
  <script src="/_next/static/chunks/main.js?ts=1665897162450" defer=""></script>
  <script src="/_next/static/chunks/pages/_app.js?ts=1665897162450" defer=""></script>
  <script src="/_next/static/chunks/pages/index.js?ts=1665897162450" defer=""></script>
  <script src="/_next/static/development/_buildManifest.js?ts=1665897162450" defer=""></script>
  <script src="/_next/static/development/_ssgManifest.js?ts=1665897162450" defer=""></script><noscript
    id="__next_css__DO_NOT_USE__"></noscript>
</head>

<body>
  <div id="__next"></div>
  <script src="/_next/static/chunks/react-refresh.js?ts=1665897162450"></script>
  <script id="__NEXT_DATA__"
    type="application/json">{"props":{"pageProps":{"properties":[{"propertyId":"OsDbKrOmE4wRRUMzalxG","propertyAvg":2.888888888888889,"landlordAvg":2.777777777777778,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FOsDbKrOmE4wRRUMzalxG-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-6214c8e0-4aec-11ed-b51b-75adb81e8353.png?alt=media\u0026token=2437767c-0877-470a-be6a-33f34c906a09","address":"312 Brooklands Road, Timperley, Manchester, UK"},{"propertyId":"NPwjd3YMPA8ddyzqBfmO","propertyAvg":3.888888888888889,"landlordAvg":4.111111111111112,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FNPwjd3YMPA8ddyzqBfmO-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-b8072400-4c4a-11ed-9e75-f5ca509826c3.png?alt=media\u0026token=28ef7da1-711a-485a-8282-ffa1940f767d","address":"1 Wharncliffe Road, Broomhall, Sheffield, UK"},{"propertyId":"rxabfAynk5CfTIPwdRN3","propertyAvg":3.5,"landlordAvg":3,"imageUrl":"https://firebasestorage.googleapis.com/v0/b/student-property-1577144888882.appspot.com/o/property-images%2FrxabfAynk5CfTIPwdRN3-ZkKIwuKwYua7ml8nEWOXYIV5tiK2-7a025420-4c24-11ed-bbda-e9dedbc50f17.jpg?alt=media\u0026token=1da2a00b-76d0-4371-a4e0-b0c77e995db2","address":"324 Grays Inn Road, London, UK"}]},"__N_SSP":true},"page":"/","query":{},"buildId":"development","isFallback":false,"gssp":true,"scriptLoader":[{"src":"https://maps.googleapis.com/maps/api/js?key=AIzaSyAyIxfU1kI6ODZLE80-_XXyK7tdmY3Gk50\u0026libraries=places","strategy":"afterInteractive"}]}</script>
</body>

</html>

I was under the impression that next js would render full HTML pages on the server before sending them to the browser. I am not sure if there is a way to configure a "production" build option within the next.config.js file to make this happen, or whether this is a bug within next itself?

The following is my _app.js file:

import React from 'react';
import Head from 'next/head';
import { ThemeProvider } from '@mui/material/styles';
import CssBaseline from '@mui/material/CssBaseline';
import theme from '../config/theme';
import { AppBar, Toolbar, Typography, Container, Box } from '@mui/material';
import { MapsHomeWork } from '@mui/icons-material';
import { Auth, RouteProtect, Link } from '../components';
import { AuthContextProvider } from '../context/authContext';



export const App = ({ Component, pageProps }) => {
  return (
    <AuthContextProvider>
      <Head>
        <meta property="og:locale" content="en_GB" />
        <meta property="og:site_name" content="Student Property Reviews" />
        <meta name="viewport" content="initial-scale=1, width=device-width" />
        <meta name="robots" content="index, follow" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <ThemeProvider theme={theme}>
        <CssBaseline />
        <Box>
          <AppBar position='static'>
            <Container maxWidth="xl">
              <Toolbar disableGutters>
                <Link href='/'>
                  <MapsHomeWork sx={{ display: { xs: 'flex', md: 'flex' }, mr: 1 }} />
                  <Typography
                    variant="h6"
                    sx={{
                      mr: 2,
                      display: { xs: 'none', sm: 'flex', md: 'flex' },
                      fontFamily: 'monospace',
                      fontWeight: 700,
                      letterSpacing: '.3rem',
                      color: 'inherit',
                      textDecoration: 'none',
                    }}
                    >
                    STUDENT PROPERTY REVIEW
                  </Typography>
                </Link>
                <Auth/>
              </Toolbar>
            </Container>
          </AppBar>
          <Container sx={{ marginBottom: '25px' }}>
            <RouteProtect>
              <Component {...pageProps} />
            </RouteProtect>
          </Container>
        </Box>
      </ThemeProvider>
    </AuthContextProvider>
  );
};

export default App;

Any help regarding this would be much appreciated!

【问题讨论】:

  • What does your _app looks like? You're most likely forcing client-side rendering somehow.
  • What would cause client-side rendering in _app? All that component does is return markup (using MUI components)
  • That's what I'm trying to understand. You must have some code that's causing it. Sharing the code for _app and the page you're rendering would help clarify it.
  • I will add it to the original post

标签: javascript next.js seo server-side-rendering vercel


【解决方案1】:

I figured this issue out. I had tried everything I thought I could, but when commenting out the &lt;AuthContextProvider/&gt; it seemed to work completely fine!

Within the auth context file, I was performing conditional rendering, depending on a loading state, which was causing SSR not to take place:

Previously:

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const provider = new GoogleAuthProvider();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user ? user : null);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  const login = () => {
    return signInWithRedirect(auth, provider);
  };

  const logout = async () => {
    setUser(null);
    await signOut(auth);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {!loading && children}
    </AuthContext.Provider>
  );
};

Now:

const AuthContext = createContext({});

export const useAuth = () => useContext(AuthContext);

export const AuthContextProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const provider = new GoogleAuthProvider();

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user ? user : null);
    });
    return () => unsubscribe();
  }, []);

  const login = () => {
    return signInWithRedirect(auth, provider);
  };

  const logout = async () => {
    setUser(null);
    await signOut(auth);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
};

【讨论】:

    【解决方案2】:

    Here is a similar use case - But even when I am not using any conditional rendering, my page source is still missing.

    Context -

        const { createContext, useState, useEffect, useMemo } = require('react')
    
    export const InternetConnectionStatusContext = createContext({
      isOnline: true,
    })
    
    export const InternetConnectionStatusProvider = ({ children }) => {
      const [isOnline, setOnline] = useState(true)
    
      // if (typeof navigator === 'undefined') {
      //   return null
      // }
    
      useEffect(() => {
        setOnline(navigator.onLine)
    
        window.addEventListener('online', () => {
          setOnline(true)
        })
    
        window.addEventListener('offline', () => {
          setOnline(false)
        })
    
        return () => {
          window.removeEventListener('online', () => {
            setOnline(true)
          })
    
          window.removeEventListener('offline', () => {
            setOnline(false)
          })
        }
      }, [navigator.onLine])
    
      const value = useMemo(() => ({ isOnline }))
    
      return (
        <InternetConnectionStatusContext.Provider value={value}>
          {children}
        </InternetConnectionStatusContext.Provider>
      )
    }
    

    【讨论】:

      【解决方案3】:

      Well, there are many reasons why there is no rendering HTML the most common problem is there is something that is blocking the rendering, I give an example using Redux-Persist blocks totally the rendering so when you right-click on the page and click on page source you will see not HTML rendering, so you need to check what packages are blocking the rendering because not all NPM packages are very friendly with NextJS and make these behaviors.

      【讨论】:

      • These are my dependencies: "@mui/icons-material": "^5.10.6", "@mui/material": "^5.10.6", "@vercel/og": "^0.0.18", "firebase": "^9.10.0", "lodash": "^4.17.21", "next": "12.3.1", "react": "18.2.0", "react-dom": "18.2.0", "react-material-ui-carousel": "^3.4.2", "react-places-autocomplete": "^7.3.0", "uuid": "^9.0.0"
      猜你喜欢
      • 2020-05-28
      • 2021-07-12
      • 2022-11-20
      • 1970-01-01
      • 2021-03-14
      • 2019-04-04
      • 1970-01-01
      • 2022-12-01
      • 2020-11-11
      相关资源
      最近更新 更多