Проблема внешней маршрутизации с отображением на стороне сервера в приложении React/Node

#node.js #reactjs #server-side-rendering

Вопрос:

У меня очень странная проблема, если я запускаю свое приложение с визуализацией на стороне клиента, то все маршруты работают идеально. Однако, когда я переключаюсь на SSR, сначала он работает нормально http://localhost:8001 но когда я загружаю новый запрос get, нажав enter в строке поиска браузера, чтобы загрузить другой маршрут, например http://localhost:8001/covid затем я получаю эту ошибку… Это было сгенерировано с помощью приложения create-react-app

Ошибка типа [ERR_INVALID_CALLBACK]: Обратный вызов должен быть функцией. Получено неопределенным при обратном вызове (fs.js:160:9) в файле Object.ReadFile (fs.js:311:14) в D:RepoWhiteTigerCreateReactAppserver/server.js:37:8 на уровне.ручка [как handle_request] (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterlayer.js:95:5) в следующий (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterroute.js:137:13) на маршруте.отправка (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterroute.js:112:3) на Слое.обрабатывать [как handle_request] (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterlayer.js:95:5) в D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterindex.js:281:22 в параме (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterindex.js:354:14) в параме (D:RepoWhiteTigerCreateReactAppnode_modulesexpresslibrouterindex.js:365:14)

Вот мой файл NodeJS, в котором я загружаю приложение react, я прокомментировал строку, которую я использую для визуализации на стороне клиента

 import express from 'express';
import fs from 'fs';
import path from 'path';
import React from 'react';
import ReactDomServer from 'react-dom/server'

import App from '../src/components/App'
const PORT = 8001;

const app = express();

let indexPath = path.join(__dirname, '../build/index.html');
let buildPath = path.join(__dirname, '../build');

app.use(express.static(path.resolve(__dirname, '..', 'build')));

app.get('*', function (req, res) {
    
    console.log("response",indexPath);

    //SSR -------------------------
    fs.readFile(indexPath), 'utf-8', (err, data) => {
        if (err) {
            console.log('error from server.js', err);
            return res.status(500).send("Some error happened")
        }
        return res.send(data.replace(
            "<div id='root'></div>",
            `<div id="root">${ReactDomServer.renderToString(<App />)} </div>`));
    }
    //Client Render -----------------
    //res.sendFile(indexPath);   

});

app.listen(PORT, () => {
    console.log(`App launced on ${PORT}`);
});
 

This is wrapped up with a seperate server file which is the one I am calling. This calls the code above.

 require('ignore-styles')

require('@babel/register')({
    ignore: [/(node_module)/],
    presets: ['@babel/preset-env', '@babel/preset-react']
})

require('./server')
 

My react app has this entry point

 import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from "react-router-dom";

/* ./ means search local file system*/
import './assets/css/styles.css';
import './assets/css/utility.css';
import './assets/css/animate.min.css';
import './assets/css/call-now.css';
import './assets/css/Contact-Form-Clean.css';
import './assets/css/betternav.min.css';
import App from './components/App';
//when importing from a module the file extension is omitted. */
import '../node_modules/font-awesome/css/font-awesome.min.css';
import '../node_modules/bootstrap/dist/css/bootstrap.min.css';
import '../node_modules/bootstrap/dist/js/bootstrap.min.js';
import reportWebVitals from './reportWebVitals';

ReactDOM.hydrate(
  <React.StrictMode>
    <Router>
    <App />
    </Router>
  </React.StrictMode>,
  document.getElementById('root')
);    

reportWebVitals();
 

And my App component looks like this which has all the routes.. clearly something is not working or loading during SSR? :/

 import { React, Component } from 'react';
import { Switch, Route } from 'react-router-dom'
import '../assets/css/header.css';
import '../assets/css/footer.css';
import Header from './header';
import Footer from './footer';
import Body from './body';
import ClientPage from './clientPage'
import CovidPage from './covidPage'
import Commercial from './commercialPage'
import CarpetFloorPage from './carpetFloor'
import IndustrialConstructionPage from './industrialConstructionPage';
import SafeContractorPage from './safeContractor';
import ContactPage from './contactPage';
import IndustrialCommercialPage from './industrialCommercialPage';
import Popper from 'popper.js';
import BetterNav from '../utility/betternav'
import PageNotFound from './notFoundPage';

class App extends Component { 


  componentDidMount()
  {
    BetterNav();
  }

  render() {
    return (
      <div>
        <Header></Header>
        <Switch>          
          <Route exact path='/' component={Body} />          
          <Route path='/clients' component={ClientPage} />
          <Route path='/covid' component={CovidPage} />
          <Route path='/commercial' component={Commercial} />       
          <Route path='/carpet-floor' component={CarpetFloorPage} /> 
          <Route path='/industrial-construction' component={IndustrialConstructionPage} /> 
          <Route path='/safe-contractor' component={SafeContractorPage} />          
          <Route path='/contact' component={ContactPage} />
          <Route path='/industrial-commercial' component={IndustrialCommercialPage} />                     
          <Route component={PageNotFound} />
        </Switch>
        <Footer></Footer>
      </div>
    );
  }
  
}

export default App;
 

Since updating the code in server.js to

 app.get('*', function (req, res) {
    
    console.log("response",indexPath);

    //SSR -------------------------
    fs.readFile(indexPath, 'utf-8', (err, data) => {
        if (err) {
            console.log('error from server.js', err);
            return res.status(500).send("Some error happened")
        }
        return res.send(data.replace(
            "<div id='root'></div>",
            `<div id="root">${ReactDomServer.renderToString(<App />)} </div>`));
    })
    //Client Render -----------------
    //res.sendFile(indexPath);   

});
 

The app loads at first with
http://localhost:8001 no problem as usual. but when I go to
http://localhost:8001/covid
I get this error instead..

D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:3709 ошибка броска; ^

Ошибка типа: Не удается прочитать свойство «createElement» неопределенного в приложении.рендеринг (D:RepoWhiteTigerCreateReactAppsrccomponents/App.js:30:7) в processChild (D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:3450:18) при решении (D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:3270:5) в ReactDOMServerRenderer.рендеринг (D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:3753:22) в ReactDOMServerRenderer.читать (D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:3690:29) на объекте.renderToString (D:RepoWhiteTigerCreateReactAppnode_modulesreact-domcjsreact-dom-server.node.development.js:4298:27) в D:RepoWhiteTigerCreateReactAppserver/server.js:27:46 в FSReqCallback.readFileAfterClose [как завершенный] (внутренний/fs/read_file_context.js:63:3) ОШИБКА npm! код ELIFECYCLE npm ОШИБАЕТСЯ! ошибка 1 npm ОШИБКА! ssr-example@0.1.0 сср: node server/index.js нпм ОШИБАЕТСЯ! Статус выхода 1 npm ОШИБКА! npm err! Потерпел неудачу на ssr-example@0.1.0 сценарий сср.

Ответ №1:

Я думаю, что ваша проблема здесь:

 fs.readFile(indexPath), 'utf-8', (err, data) => {
    // ........ (Your code was here)
}
 

Измените его на:

 fs.readFile(indexPath, 'utf-8', (err, data) => {
    // ........ (Your code was here)
})
 

Вы только что пропустили скобку.

Комментарии:

1. Обновил его, но это вызвало совсем другую ошибку,, обновит билет.

2. На самом деле вы правы, вам нужен веб-пакет на стороне сервера.