Skip to content

Example with navigation and digitalocean deployment instructions #1226

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions examples/with-navigation-digitalocean/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
logs
*.log
npm-debug.log*
.DS_Store

coverage
node_modules
build
cache
public/static
.env.*.local
112 changes: 112 additions & 0 deletions examples/with-navigation-digitalocean/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
# Razzle Basic Example

## How to use
Download the example [or clone the whole project](https://github.com/jaredpalmer/razzle.git):

```bash
curl https://codeload.github.com/jaredpalmer/razzle/tar.gz/master | tar -xz --strip=2 razzle-master/examples/with-navigation-digitalocean
cd with-navigation-digitalocean
```

Install it and run:

`Note:` If you cloned the whole razzle repository, cd into this example:

```bash
cd examples/with-navigation-digitalocean
```

```bash
yarn install
yarn start
```

## Idea behind the example

This is built off of the basic example provided. This example achieves how to setup a simple navigation tab that will load your pages in accordance with Server Side Rendering.

## For Digital Ocean
This tutorial is inspired by [this post](https://hackernoon.com/start-to-finish-deploying-a-react-app-on-digitalocean-bcfae9e6d01b), but hopefully is a bit easier to walk through.

First of all, we'll assume you've setup your ssh keys for authentication, and that you have any users setup if you wish to run your server from a non-root user. For now, we'll assume the server is run from the root user.

[How to Connect to Droplets with SSH](https://www.digitalocean.com/docs/droplets/how-to/connect-with-ssh/)

### 1) Install Node.js if you haven't already.

[This page](https://nodejs.org/en/download/package-manager/) outlines the many ways you can install node.js on your server. For our purposes we will grab the latest LTS (Long Term Support) binary release. In this case we're using 12.x, but you can check the latest LTS release [here](https://nodejs.org/en/download/).

Install nodejs:
```bash
# Using Ubuntu
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
sudo apt-get install -y nodejs

# Using Debian, as root
curl -sL https://deb.nodesource.com/setup_12.x | bash -
apt-get install -y nodejs
```

### 2) Install pm2

`pm2` provides persistence, so when you exit your terminal session it will still be running. With `node` and `npm` installed, you can install it via the following:

`npm install -g pm2`

### 3) Serve your app!

First, clone your project into your server:

`git clone <url-to-repository.git> [optional-name]` & `cd [your-project-directory]`

install, and build:

`npm install` & `npm run build`

Now tell pm2 to perpetually serve your website:

`pm2 start build/server.js`

You can also use these commands to know what processes are running, etc.
`pm2 list` & `pm2 show [index | process_name]`

Now you should be able to view your website via `[IP | Domain]:3000` (npm uses port 3000 to serve your site by default)

### 4) Extra -- You can use NGINX for a reverse proxy
From here you can do additional steps to make your site more secure, like using NGINX as a reverse proxy

`[sudo] apt-get install nginx`

Nginx works with your firewall, so you can setup SSL certificates (https) via this method. You can go [here](https://www.digitalocean.com/community/tutorials/how-to-install-an-ssl-certificate-from-a-commercial-certificate-authority) for setting up `https`.

For now we can just use `http`:

`[sudo] ufw allow 'Nginx HTTP'`

You can see the changes via `ufw app list`

#### Configure Nginx

Using the editor of your choice, edit `/etc/nginx/sites-enabled/default`

Modify or add the lines as shown bellow:
```bash
server {
...

root /root/your-project/build/; # point to your build dir

...

server_name my_project # (or example.com www.example.com)

...

location / {
...

proxy_pass http://localhost:3000
}
}
```

23 changes: 23 additions & 0 deletions examples/with-navigation-digitalocean/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "razzle-examples-with-navigation-digital-ocean",
"version": "3.0.0",
"license": "MIT",
"scripts": {
"start": "razzle start",
"build": "razzle build",
"test": "razzle test --env=jsdom",
"start:prod": "NODE_ENV=production node build/server.js"
},
"dependencies": {
"express": "^4.15.2",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router-dom": "^5.1.2"
},
"devDependencies": {
"razzle": "4.04",
"html-webpack-plugin": "$4.5.2",
"razzle-dev-utils": "4.0.4",
"babel-preset-razzle": "4.0.4"
}
}
Binary file not shown.
2 changes: 2 additions & 0 deletions examples/with-navigation-digitalocean/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
User-agent: *

9 changes: 9 additions & 0 deletions examples/with-navigation-digitalocean/public/test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eu scelerisque felis imperdiet proin fermentum leo vel orci porta. Faucibus interdum posuere lorem ipsum dolor sit. Nisl tincidunt eget nullam non nisi est sit. Non diam phasellus vestibulum lorem sed. Consectetur libero id faucibus nisl tincidunt eget nullam. Mollis nunc sed id semper risus. Diam maecenas sed enim ut sem viverra aliquet. Adipiscing commodo elit at imperdiet dui accumsan sit amet. Volutpat odio facilisis mauris sit amet massa vitae tortor. Pellentesque sit amet porttitor eget. Faucibus a pellentesque sit amet porttitor eget dolor morbi non. Id aliquet lectus proin nibh nisl. Nec feugiat in fermentum posuere urna nec tincidunt praesent. Ut aliquam purus sit amet. Praesent tristique magna sit amet purus gravida quis.

Laoreet sit amet cursus sit amet dictum sit. Pharetra pharetra massa massa ultricies mi quis hendrerit dolor magna. Velit aliquet sagittis id consectetur purus ut faucibus. Felis eget nunc lobortis mattis aliquam faucibus purus in massa. Viverra aliquet eget sit amet tellus cras adipiscing enim eu. Et ligula ullamcorper malesuada proin libero nunc consequat interdum varius. Aliquet enim tortor at auctor urna nunc id. Ante in nibh mauris cursus mattis. Fames ac turpis egestas maecenas pharetra convallis posuere. Aliquam purus sit amet luctus. In ante metus dictum at tempor commodo. Dolor morbi non arcu risus quis varius.

Pharetra convallis posuere morbi leo urna molestie at elementum eu. Cursus euismod quis viverra nibh cras pulvinar mattis. Est ante in nibh mauris cursus. Neque laoreet suspendisse interdum consectetur libero id faucibus nisl tincidunt. Massa tempor nec feugiat nisl pretium fusce id. Id donec ultrices tincidunt arcu non sodales. Et ultrices neque ornare aenean euismod elementum nisi quis. Cursus mattis molestie a iaculis at erat. Egestas quis ipsum suspendisse ultrices gravida. Senectus et netus et malesuada fames ac turpis egestas. Adipiscing diam donec adipiscing tristique risus nec feugiat in. Placerat in egestas erat imperdiet sed euismod nisi porta. Massa enim nec dui nunc mattis. Volutpat ac tincidunt vitae semper quis lectus nulla at.

Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Cras sed felis eget velit aliquet sagittis id consectetur purus. Nulla at volutpat diam ut venenatis. Purus ut faucibus pulvinar elementum integer enim neque volutpat ac. Diam volutpat commodo sed egestas. Condimentum mattis pellentesque id nibh tortor id aliquet lectus proin. Et leo duis ut diam quam nulla. Venenatis cras sed felis eget. Faucibus turpis in eu mi bibendum neque egestas congue. Adipiscing bibendum est ultricies integer quis auctor elit sed vulputate. Vitae auctor eu augue ut lectus arcu. Sem integer vitae justo eget magna fermentum iaculis eu non. Blandit volutpat maecenas volutpat blandit aliquam etiam. Diam vulputate ut pharetra sit amet aliquam id diam. Nunc pulvinar sapien et ligula ullamcorper malesuada. Netus et malesuada fames ac turpis egestas. Amet venenatis urna cursus eget nunc scelerisque. Etiam sit amet nisl purus.

Enim lobortis scelerisque fermentum dui faucibus in ornare quam. Viverra orci sagittis eu volutpat odio facilisis mauris sit. Eget dolor morbi non arcu risus. Nunc pulvinar sapien et ligula ullamcorper malesuada proin. Pretium nibh ipsum consequat nisl. Ultrices mi tempus imperdiet nulla malesuada. Risus nec feugiat in fermentum. Velit dignissim sodales ut eu sem integer vitae. At consectetur lorem donec massa. Turpis massa sed elementum tempus egestas sed sed risus pretium. Diam maecenas ultricies mi eget mauris. Ut venenatis tellus in metus vulputate eu scelerisque felis. Fringilla urna porttitor rhoncus dolor. In nibh mauris cursus mattis molestie a iaculis at erat. Dignissim cras tincidunt lobortis feugiat vivamus. Malesuada fames ac turpis egestas. Facilisi etiam dignissim diam quis enim lobortis scelerisque fermentum dui. Et sollicitudin ac orci phasellus. Eu non diam phasellus vestibulum.
13 changes: 13 additions & 0 deletions examples/with-navigation-digitalocean/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
body {
margin: 0;
padding: 0;
font-family: -apple-system,
BlinkMacSystemFont,
"Segoe UI",
Helvetica,
Arial,
sans-serif,
"Apple Color Emoji",
"Segoe UI Emoji",
"Segoe UI Symbol";
}
13 changes: 13 additions & 0 deletions examples/with-navigation-digitalocean/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import './App.css';
import Navigation from './components/Navigation/Navigation';
import AppRouting from './components/Navigation/AppRouting';

import React from 'react';
const App = () => (
<div>
<Navigation />
<AppRouting />
</div>
);

export default App;
10 changes: 10 additions & 0 deletions examples/with-navigation-digitalocean/src/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import App from './App';
import React from 'react';
import ReactDOM from 'react-dom';

describe('<App />', () => {
test('renders without exploding', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
});
});
16 changes: 16 additions & 0 deletions examples/with-navigation-digitalocean/src/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';
import { hydrate } from 'react-dom';
import App from './App';

import { BrowserRouter } from 'react-router-dom';

hydrate(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);

if (module.hot) {
module.hot.accept();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import React from 'react';
import { Route } from 'react-router-dom';
import home from '../../pages/home';
import page1 from '../../pages/page1';
import page2 from '../../pages/page2';

function AppRouting() {
return (
<div>
<Route exact path="/" component={home} />
<Route path="/page1" component={page1} />
<Route path="/page2" component={page2} />
</div>
);
}

export default AppRouting;
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';

import { Link } from 'react-router-dom';

function Navigation() {
return (
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/page1">page1</Link>
</li>
<li>
<Link to="/page2">page2</Link>
</li>
</ul>
);
}

export default Navigation;
27 changes: 27 additions & 0 deletions examples/with-navigation-digitalocean/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import express from 'express';

let app = require('./server').default;

if (module.hot) {
module.hot.accept('./server', function() {
console.log('🔁 HMR Reloading `./server`...');
try {
app = require('./server').default;
} catch (error) {
console.error(error);
}
});
console.info('✅ Server-side HMR Enabled!');
}

const port = process.env.PORT || 3000;

export default express()
.use((req, res) => app.handle(req, res))
.listen(port, function(err) {
if (err) {
console.error(err);
return;
}
console.log(`> Started on port ${port}`);
});
7 changes: 7 additions & 0 deletions examples/with-navigation-digitalocean/src/pages/home.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react';

function home() {
return <div>This is my sweet home page. Hello, World!</div>;
}

export default home;
16 changes: 16 additions & 0 deletions examples/with-navigation-digitalocean/src/pages/page1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React from 'react';

function page1() {
return (
<div>
Thanks for visiting my site, here is some cool info: My t-shirts come in
red, blue, and green.
<br />
<a href={process.env.PUBLIC_PATH + 'test.txt'} download="myDownload.txt">
download a t-shirt print here
</a>
</div>
);
}

export default page1;
12 changes: 12 additions & 0 deletions examples/with-navigation-digitalocean/src/pages/page2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';

function page2() {
return (
<div>
Here is some info about our company: This simple website is where it all
began :)
</div>
);
}

export default page2;
50 changes: 50 additions & 0 deletions examples/with-navigation-digitalocean/src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import App from './App';
import React from 'react';
import express from 'express';
import { renderToString } from 'react-dom/server';

import { StaticRouter } from 'react-router-dom';

const assets = require(process.env.RAZZLE_ASSETS_MANIFEST);

const server = express();

server
.disable('x-powered-by')
.use(express.static(process.env.RAZZLE_PUBLIC_DIR))
.get('/*', (req, res) => {
const context = {};
const markup = renderToString(
<StaticRouter context={context} location={req.url}>
<App />
</StaticRouter>
);

if (context.url) {
res.redirect(context.url);
} else {
res.status(200).send(
// prettier-ignore
`<!doctype html>
<html lang="">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charSet='utf-8' />
<title>Welcome to Razzle</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
${
assets.client.css
? `<link rel="stylesheet" href="${assets.client.css}">`
: ''
}
</head>
<body>
<div id="root">${markup}</div>
<script src="${assets.client.js}" defer crossorigin></script>
</body>
</html>`
);
}
});

export default server;