Nikita Vlasenko
Nikita Vlasenko

Reputation: 4352

React: server side rendering, Invariant Violation: Invalid tag: <!doctype html>

I am trying to render the whole page in React only then sending it to the browser. I am getting the following error:

Invariant Violation: Invalid tag: <!doctype html>

The line that is producing this error is ReactDOMServer.renderToString(el);:

fs.readFile('./public/index.html',"utf8", function (err, data){
    /*res.writeHead(200, {'Content-Type': 'text/html','Content-Length':data.length});
    res.write(data);
    res.end();*/
    var el = React.createElement(data);
    console.log("React element was successfully created!");
-----> var html = ReactDOMServer.renderToString(el);
    res.send(html);
  });

The html file looks the following way:

<!DOCTYPE html>
<html lang="en">
 <head>
    <meta charset="utf-8">
    ...
    <title>React App</title>
 </head>
 <body>
<div id="root"></div>
<script type="text/javascript" src="bundle.js" charset="utf-8">
</script>
</body>
</html>

How to fix the error? Any suggestions would be greatly appreciated.

Update

I tried to do the following:

var mainData = prepareDataForScatterChart(result);
  const html = ReactDOMServer.renderToString(`<App 
  mainData=${mainData}/>`);
  fs.readFile('./public/index.html',"utf8", function (err, data){
  const document = data.replace(/<div id="app"><\/div>/, `<div 
  id="app">${html}</div>`);
  res.send(document);

The error is gone, but after I load the page there are errors that mean that the data was not passed to the App.

Update

I got it working on the server by adding babel-node, but browser still somehow is not getting the data. So, in the App I am printing out the mainData and it is there in the node console, but in browser it is shown as undefined. Here is the code that I am using now:

const html = ReactDOMServer.renderToString(<App mainData={mainData}/>);

Upvotes: 6

Views: 5360

Answers (2)

Will Brickner
Will Brickner

Reputation: 854

I'm using the streaming variant.

You can do this (working with express and react-dom, but should work with any stream):

function streamingRender(code, res, component) {
  res.status(code)
  res.write("<!DOCTYPE html>")
  renderToNodeStream(component).pipe(res)
}

Upvotes: 2

Adebowale Akinola
Adebowale Akinola

Reputation: 21

import React from 'react';
import { renderToString } from 'react-dom/server';
// import your app component containing the html structure.
import App from './App.jsx';
// Get your data as required.
const mainData = {}; 

res.send(
  renderToString(`<!DOCTYPE html>${<App mainData={mainData}/>}`)
);

Using fs to load a static html file and using replace() are unnecessary unless you have compelling reasons to do so.

Upvotes: 2

Related Questions