I am getting a weird behaviour when I try to implement server side rendering on a react app.
...
Error: Element type is invalid: expected a string (for built-in components) or a
class/function (for composite components) but got: object.
You likely forgot to export your component from the file it's defined in,
or you might have mixed up default and named imports.
...
I realised that there is a general issue with render files with JSX extension. Here is what my code looks like.
./server/server.js
app.use('/*', (req, res, next) => {
const context = {};
const app = ReactDOMServer.renderToString(
<App />
);
console.log(app)
fs.readFile(path.resolve('./build/index.html'), 'utf-8', (err, data) => {
if (err) {
console.log(err);
return res.status(500).send("Some Error")
}
return res.send(
data.replace(
'<div id="root"></div>',
`<div id="root">${app}</div>`
)
)
})
})
./server/index.js
require("ignore-styles")
require("@babel/register")({
ignore: [/(node_module)/],
presets: ['@babel/preset-env', '@babel/preset-react']
})
require('./server')
./src/App.jsx
import './App.scss';
import React from 'react';
function App() {
return (
<div className='app'>
<p>Sample</p>
</div>
);
}
export default App;
./src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.scss';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter as Router } from "react-router-dom";
ReactDOM.hydrate(
<Router>
<React.StrictMode>
<App />
</React.StrictMode>
</Router>,
document.getElementById('root')
);
reportWebVitals();
And the error occurs when in ../server/server.js:17:30 which is when ReactDOMServer.renderToString is called. The issue is that the component are seen as an empty object after they are imported. I have a feeling it is an issue with babel but I am not sure.
I've encountered the same problem recently with a very similar setup. During SSR the components which had .js extension returned the expected React components, while the .jsx files returned {}.
In my case I changed the imports from
import App from './components/App'
to
import App from './components/App.jsx'
and it fixed the issue. After this modification both the server and client side render returns the expected components.