Search code examples
htmlcssreactjssingle-page-applicationprerender

A class is repeated on other classes with react-spa-prerender


I use React SPA Prerender to optimize SEO, and i got this problem :

I have a class called HomeTitleContainer, specifically used for the Home.jsx file, which is the home page.

import { Container } from 'react-bootstrap';
import Link from '../immutable/nav/Link';
import './Home.css';

const Home = () => {
  
    return (
        <>
            <Container className="HomeTitleContainer">
                Ma Thématique
            </Container>
            <Container className="TableOfContentsLink">
                <p><Link link={'/cours'} internalLink={true} >- Des cours de mathématiques sur de nombreux sujets</Link></p>
                <p><Link link={'/bds-de-jpp'} internalLink={true} >- Des BDs de Jean-Petit</Link></p>   
                <p><Link link={'/jeux'} internalLink={true} >- Des petits jeux pour s'améliorer</Link></p>            
            </Container>
        </>
    );
}

export default Home;

Here is the corresponding css file, Home.css :

.HomeTitleContainer {
    position: relative;
    top: 30px;
    /* background-color: var(--front-color); */
    background-image: linear-gradient(to bottom right, var(--front-color), grey);    
    border-radius: 10px;
    color: var(--links-color);
    font-size: large;
    padding: 30px;
    width: calc(var(--window-width) * 3 / 4);
    box-shadow: 20px 20px 5px 5px var(--navbar-color);
    margin-bottom: 100px;
}

@media (min-width : 450px) {
    .HomeTitleContainer {
        width: calc(var(--window-width) * 1 / 2);
        top: 50px;
    }
}

This HomeTitleContainer class is not present anywhere else. But when i generate some html files according to my .rsp.json file, this class is present in all other generated html files.

To illustrate it, an example with the courses page...

All the pages have a table of content, so I use this file, GenericTableOfContents.jsx :

import { Container, Row, Col } from 'react-bootstrap';
import Link from '../immutable/nav/Link';

const GenericTableOfContents = ( {items, prefix, title} ) => {

    return (
        <>
            <p className="MainTitle">{title}</p>
            <Row>
                {
                    items.map(item => (
                        <Container key={item.id} className="TableOfContents">
                            <Col xs={12} md={12}>
                                <div key={item.id} className="TableOfContentsLink" >
                                    <Link link={`/${prefix}/${item.relativePath}`} internalLink={true} >
                                        <div>{item.title}</div>
                                    </Link>
                                </div>
                            </Col>
                        </Container>
                    ))
                }
            </Row>
        </>
    )

}

export default GenericTableOfContents;

You can see that the MainTitle and the TableOfContents classes should be one after the other. But in cours.html, this sample is present :

<p class="MainTitle">Tous les cours</p>
<div class="HomeTitleContainer container">
<div class="TableOfContents container"> ...

Eventhough it shouldn't have to be there, a div with the HomeTitleContainer class has been added.

Here is the .rsp.json :

{
    "port": 3000,
    "buildDirectory": "./build",
    "routes": [
        "/",
        "/cours",
        "/bds-de-jpp",
        "/jeux",
        "/liens"
    ]
}

Here is the routes file (AppRoutes.jsx):

import { Route, Routes } from 'react-router-dom';
import Home from './components/home/Home';
import CoursesTableOfContents from './components/courses/CoursesTableOfContents';
import ChaptersTableOfContents from './components/courses/ChaptersTableOfContents';
import GenericChapter from './components/courses/GenericChapter';
import PdfTableOfContents from './components/pdf-viewer/PdfTableOfContents';
import PDFViewerPage from './components/pdf-viewer/PDFViewerPage';
import GamesTableOfContents from './components/games/GamesTableOfContents';
import Links from './components/links/Links';
import VCard from './components/contact/VCard';
import Error from './components/immutable/Error';

const AppRoutes = ( {courseItems, pdfItems, gameItems} ) => {

    return  <Routes>
                {
                    process.env.NODE_ENV === 'development' ?
                        <Route exact path="/" element={<Home />} />
                            :   <Route exact path="/" element={<Home />} />
                }
                <Route path="/cours" element={<CoursesTableOfContents courseItems={courseItems} />} />
                {courseItems.map(courseItem => {
                    return  <Route 
                                key={courseItem.id}
                                path={`/cours/${courseItem.relativePath}`}
                                element={<ChaptersTableOfContents courseItem={courseItem} />} />
                
                })}
                {courseItems.map(courseItem => (
                    courseItem.chapters.map(chapter => {
                        return  <Route 
                                    key={chapter.id}
                                    path={`/cours/${courseItem.relativePath}/${chapter.relativePath}`}
                                    element={<GenericChapter chapter={chapter} courseItem={courseItem} />} />
                    })
                ))}
                <Route path="/bds-de-jpp" element={<PdfTableOfContents pdfItems={pdfItems} />} />
                {pdfItems.map(pdfItem => (
                    <Route 
                        key={pdfItem.id}
                        path={`/bds-de-jpp/${pdfItem.relativePath}`}
                        element={<PDFViewerPage pdfItem={pdfItem} />} />
                ))}
                <Route path="/jeux" element={<GamesTableOfContents gameItems={gameItems} />} />
                {gameItems.map(gameItem => (
                    <Route 
                        key={gameItem.id}
                        path={`/jeux/${gameItem.relativePath}`}
                        element={gameItem.component} />
                ))}
                <Route path="/liens" element={<Links />} />
                <Route path="/contact" element={<VCard />} />
                <Route path="*" element={<Error />} status={404} />
            </Routes>
}

export default AppRoutes;

Added in App.js :

    var courseItems = coursesResourceBuilder();
    var pdfItems = pdfResourceBuilder();
    var gameItems = gamesResourceBuilder();
    <div className="App" >     

            <div className={`${theme} ${font} CopyBook`}>
                <BrowserRouter>
                    <Header courseItems = {courseItems} pdfItems ={pdfItems} gameItems={gameItems} /> 
                        <Container className = {` RelativeContainer ${playMode ? "PlayMode" : ''}  ${isLoading ? "Blur" : ''} `} >                           
                            <AppRoutes courseItems={courseItems} pdfItems={pdfItems} gameItems={gameItems} />
                        </Container> 
                    <Footer /> 
                </BrowserRouter>
            </div> 

    </div>

And here is the url of the website :

https://ma-thematique.netlify.app

https://ma-thematique.netlify.app/cours

Can somebody can help me please ?


Solution

  • You can try to use Styled Components to avoid CSS from applying globally:

    import styled from 'styled-components';
    
    const HomeTitleContainer = styled.span`
      position: relative;
      top: 30px;
      background-image: linear-gradient(to bottom right, var(--front-color), grey);
      border-radius: 10px;
      color: var(--links-color);
      font-size: large;
      padding: 30px;
      width: calc(var(--window-width) * 3 / 4);
      box-shadow: 20px 20px 5px 5px var(--navbar-color);
      margin-bottom: 100px;
    
      @media (min-width: 450px) {
        width: calc(var(--window-width) * 1 / 2);
        top: 50px;
      }
    `;
    
    export default HomeTitleContainer;
    

    Then inside of your Home component:

    import { Container } from 'react-bootstrap';
    import Link from '../immutable/nav/Link';
    import './Home.css';
    import HomeTitleContainer from "./HomeTitleContainer";
    import React, {Fragment} from "react";
    
    const Home = () => (
      <Fragment>
        <Container>
          <HomeTitleContainer>
            Ma Thématique
          </HomeTitleContainer>
        </Container>
    
        <Container className="TableOfContentsLink">
          <p><Link link={'/cours'} internalLink={true} >- Des cours de mathématiques sur de nombreux sujets</Link></p>
          <p><Link link={'/bds-de-jpp'} internalLink={true} >- Des BDs de Jean-Petit</Link></p>   
          <p><Link link={'/jeux'} internalLink={true} >- Des petits jeux pour s'améliorer</Link></p>            
        </Container>
      </Fragment>
    )
    
    export default Home
    

    Can you try this and let us know what the result is?

    There are two things which attempt to solve the problem here:

    1. Using empty tag instead of a Fragment - A Fragment allow you to group children without adding extra nodes to the DOM and make your component structure and rendering logic more clear and concise. Empty tags, on the other hand, do not provide these benefits and can lead to additional, unnecessary DOM nodes. This can cause some unusual behavior, especially in older versions of react.
    2. Using a CSS file instead of styled-components. If you use a CSS file, the CSS will apply globally and if you are not careful enough, you can easily render a div with a class name that has defined properties in one of your CSS files.