1
votes

I have done most of the necessary setup of nginx with create-react-app according to https://prerender.io/documentation but I do have a few questions

But let me explain my project setup.

My folder structure

public /index.html src/ components containers
index.js(Container app)

src/index.js looks like

import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {ConnectedRouter} from 'react-router-redux';

import './index.css';
import './main.css';
import App from './containers/app';
import store, { history } from './store';

const target = document.querySelector('#root');

ReactDOM.render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <App />
        </ConnectedRouter>
    </Provider>,
    target
);

In my nginx I have specified the root as /path/to/project/public/index.html

Index.html

<body>
<noscript>
  You need to enable JavaScript to run this app.
</noscript>
<div id="root">
  My custom text
</div>
<!--
  This HTML file is a template.
  If you open it directly in the browser, you will see an empty page.

  You can add webfonts, meta tags, or analytics to this file.
  The build step will place the bundled scripts into the <body> tag.

  To begin the development, run `npm start` or `yarn start`.
  To create a production bundle, use `npm run build` or `yarn build`.
-->

Approach #1 - Nginx works fine and shows up the html on this page. The bundle is not there by default. Obviously, the webpack handles this part when we spin up yarn start or npm start. How can I add this bundle.js to index.html so that prerender.io service would find it and returns back generated html for the react page ? Or do I even need to do this way ?

Approach #2 - I started up project on port say 3001(yarn start) and then with my prerender server ON, I ran http://localhost:3000/http://localhost:3001

where http://localhost:3000 = Prerender.io server and http://localhost:3001 is where my project runs.

Now,

  1. It doesn't serves my static assets from project root i.e. http://localhost:3001 but rather from http://localhost:3000

  2. Second, in this case, I don't feel the need if nginx setup by me manually. All I needed was prerender server and my project already r running via yarn start.

  3. I feel point 2 works for local testing. point 1 will be applicable to actual deployment of pre-rendering.

Approach #3 - create-react-app itself has react-snapshot for pre-rendering, but it gives an error as well in my setup

index.js file

import React from 'react';
// import ReactDOM from 'react-dom';
import { render } from 'react-snapshot';
import {Provider} from 'react-redux';
import {ConnectedRouter} from 'react-router-redux';

import './index.css';
import './main.css';
import App from './containers/app';
import store, { history } from './store';

const target = document.querySelector('#root');

render(
    <Provider store={store}>
        <ConnectedRouter history={history}>
            <App />
        </ConnectedRouter>
    </Provider>,
    target
);

On running it gives error Syntax error: Unexpected token, expected , (15:14)

Is the thinking correct for approach #1 and #2. And what is the problem with simplest approach #3?

Update - nginx.conf file

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

    server {
        listen 8000;
        server_name localhost;

        root   /Users/vedant/Projects/myProject/build;
        index  index.html;

        location / {
            try_files $uri @prerender;
        }

        location @prerender {
            proxy_set_header X-Prerender-Token eNlgaUedb3xptcXiFlex;

            set $prerender 0;
            if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
                set $prerender 1;
            }
            if ($args ~ "_escaped_fragment_") {
                set $prerender 1;
            }
            if ($http_user_agent ~ "Prerender") {
                set $prerender 0;
            }
            if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") {
                set $prerender 0;
            }

            #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs
            resolver 8.8.8.8;

            if ($prerender = 1) {

                #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing
                set $prerender "service.prerender.io";
                rewrite .* /$scheme://$host$request_uri? break;
                proxy_pass http://$prerender;
            }
            if ($prerender = 0) {
                rewrite .* /index.html break;
            }
        }
    }


    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}
    include servers/*;
}

Update 2 -

I tried accessing http://localhost:8000/localhost:3001 where http://localhost:8000 is my nginx server.

But it gives me header and footer only. Tried adding <script> window.prerenderReady = false; </script> as well. But it is partially rendered.

1

1 Answers

0
votes

Approach #2 is correct for testing things locally. Seeing static assets requested from http://localhost:3000 is expected since you are accessing the Prerender server directly in your browser. Once you get the nginx config set up correctly, you would serve the prerendered page through nginx and those problems would go away.

Approach #1 should work in production since the bundle file will be included in the index.html, but locally you'll want to have your nginx just do a proxy_pass to your localhost webpack server. That way you'll get the injected bundle from npm start.