Let’s not wait and get to work.
First I will just give a short introduction to the ingredients that will be used.
React
It is a library for building user interfaces and it is maintained and developed by the Facebook community. For more information about React, you can check out the official documentation.
NodeJs
NodeJS is an open-source, cross-platform, Javascript runtime environment that executes Javascript outside the browser. For more information please check the official documentation.
Webpack
Webpack is an open-source Javascript module bundler and primary used for Javascript but it can transform any frontend asset like HTML, CSS, and images if corresponding loaders are included.
Babel
It is an open-source Javascript compiler that is mainly used for convert ECMAJavascript 2015+ into a backward-compatible version of Javascript.
Now you have a basic idea of all the ingredients that will be used in the boilerplate creation, now let’s start with the coding.
Create a directory for our boilerplate and create a package.json file.
mkdir react-node-boilerplate
cd react-node-boilerplate
yarn init
yarn init
will create a package.json
inside this directory. Now, let’s add all the required packages for this boilerplate.
yarn add react react-dom express nodemon wepback @babel/core @babel/preset-env @babel/plugin-transform-react-jsx @babel/preset-react babel-loader css-loader webpack webpack-cli webpack-dev-middleware webpack-hot-middleware mini-css-extract-plugin sass-loader css-loader node-sass file-loader express-static-gzip @babel/plugin-proposal-class-properties ejs
These packages I know will be needed for this boilerplate if something is missed will add that later.
Now, let’s set up our start-server script file. Create a directory bin
and www
file under that and put the below content inside that.
To create a directory and file run following commands:
mkdir bin
cd bin
touch www
www
file content:
var http = require('http')
var port = process.env.PORT || '3000'
var server = http.createServer()
server.listen(port, () => console.log('server listening on port', port))
Inside your package.json
add/replace your scripts
object with below content:
"scripts": {
"start": "NODE_ENV=development nodemon ./bin/www",
"start:prod": "NODE_ENV=production nodemon ./bin/www"
},
Here, you can see we are using nodemon to start our start because we don’t want to restart our server whenever we change a file. So, it monitors changes in the source code and restarts your server automatically, like a hot reloader.
Start your server by running the following command:
yarn start
You can see in the command line that your basic HTTP server is running.
Create entry point for our express application app.js
var express = require('express')
var path = require('path')
var expressStaticGzip = require("express-static-gzip");
var app = express()
var indexRouter = require('./routes/index') // This one is for our frontent application
var apiRouter = require('./routes/api') // This one is for our backend APIs
// view engine setup
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'ejs')
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(express.static(path.join(__dirname, 'public')));
app.use('/dist/bundle', expressStaticGzip(path.join(__dirname, 'dist/bundle'), {
enableBrotli: true,
orderPreference: ['br', 'gz'],
setHeaders: function (res, path) {
res.setHeader("Cache-Control", "public, max-age=31536000")
}
}));
// Using webpack for our development
if (process.env.NODE_ENV === "development") {
var webpack = require("webpack");
var webpackConfig = require("./webpack.config");
var compiler = webpack(webpackConfig);
app.use(
require("webpack-dev-middleware")(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath
})
);
app.use(require("webpack-hot-middleware")(compiler))
} else {
var webpack = require("webpack");
var webpackConfig = require("./webpack.config.prod");
var compiler = webpack(webpackConfig);
app.use(
require("webpack-dev-middleware")(compiler, {
noInfo: true,
publicPath: webpackConfig.output.publicPath
})
);
}
console.log('Coming here too indexroute', indexRouter, apiRouter)
// Route handler
app.use('/api/v1', apiRouter) // api route handler
app.use('/', indexRouter); // react handler
module.exports = app
Above code explanation
- Importing express module for creating APIs.
app
variable is the instance of the express module.- import routes file that we will be creating later in this article.
- Setup view engine using
app.set
function. - Next, we have defined our
/dist/bundle
route which is rendering the content of thedist/bundle
file. We are using theexpressStaticGzip
module for compressing our bundle file. - For the development of the react application and creating a production bundle file for it, we are using a webpack.
- At last, we have rendered our router handler that will be creating later in this article.
Let’s create webpack.config.js
, webpack.config.prod.js
and .babelrc
files for webpack configuration under your project directory.
webpack.config.js
for development mode.
var webpack = require('webpack')
var path = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
mode: 'development',
devtool: 'inline-source-map',
entry: [
'./client/index.js',
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
},
{
test: /\.(scss|css)$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
},
{ loader: 'sass-loader' }
]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist/bundle/',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development')
}
}),
new MiniCssExtractPlugin({
filename: "bundle.css",
})
]
}
.babelrc
config file:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
],
"plugins": [
"@babel/plugin-proposal-class-properties"
]
}
webpack.config.prod.js
for production mode:
var webpack = require('webpack')
var path = require('path')
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
mode: 'production',
devtool: 'inline-source-map',
entry: [
'./client/index.js',
],
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
},
{
test: /\.(scss|css)$/,
use: [
{ loader: MiniCssExtractPlugin.loader },
{
loader: 'css-loader',
},
{ loader: 'sass-loader' }
]
},
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
output: {
filename: 'bundle.js',
path: __dirname + '/dist/bundle/',
publicPath: '/static/'
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
new MiniCssExtractPlugin({
filename: "bundle.css",
})
]
}
We have created two webpack configuration files one is for development env and another one is the production env.
In webpack.production.js
file you can add plugins to reduce more size of the bundle file or other configuration according to your needs.
Now, create a client
directory for react application and put a sample component inside it.
Follow all the below-mentioned steps to create the sample react app.
mkdir client
cd client
touch index.js
mkdir components
mkdir scss
cd scss
touch index.scss
Put below code inside your index.js
file.
import React from 'react'
import ReactDOM from 'react-dom'
import App from './components/App'
import './scss/index.scss'
ReactDOM.render(
<div>
<App />
</div>
,
document.getElementById('root')
);
Put below code inside index.scss
file.
body {
margin: 10x;
}
h1 {
text-align: center;
color: gray;
margin-top: 50px;
}
Now create App.js
file inside the components
directory that we are importing under our index.js
file.
App.js
import React from 'react'
const App = () => {
return (
<div>
<h1>React-Node-Boilerplate</h1>
</div>
)
}
export default App
The sample code for our frontend is done. Now, will move on to create routes for rendering backend APIs and frontend bundle file.
Create a routes
directory and under that API
directory for creating and managing APIs.
mkdir routes
cd routes
touch index.js
mkdir api
cd api
touch index.js
Put below code inside routes/index.js
file, this router file is for rendering the frontend (react-application).
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('*', function(req, res, next) {
res.render('index', { title: 'React-Node-Boilerplate' })
});
module.exports = router
For rendering backend APIs, open routes/api/index.js
file and put below content inside it.
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function (req, res, next) {
res.json({ success: true, message: 'Welcome to Node APIs' });
});
module.exports = router;
We have created a home there, for now, please add routes according to your requirement inside this file.
Routing part is done too, so will move on creating views
that are for express templates. Create a views
directory and index.ejs
file inside it.
Execute below commands inside your terminal
mkdir views
cd views
touch index.ejs
Put below code inside index.ejs
file
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
<link rel="shortcut icon" href="https://cdn2.iconfinder.com/data/icons/nodejs-1/512/nodejs-512.png">
<link rel='stylesheet' href="/static/bundle.css" />
<meta content="width=device-width, initial-scale=1" name="viewport" />
<!-- Global site tag (gtag.js) - Google Analytics -->
</head>
<body>
<div id="root"></div>
<script src="/static/bundle.js"></script>
</body>
</html>
At last, replace your bin/www
code with below code:
#!/usr/bin/env node
var app = require('../app');
var http = require('http')
var port = process.env.PORT || '3000'
app.set('port', port);
var server = http.createServer(app)
server.listen(port, () => console.log('server listening on port', port))
Here, we are importing the whole app and passing it to the createServer()
function and it is returning an instance of the server under server variable and that is listening on to 3000
port.
We have set up everything that is needed for react-node-boilerplate. Now run yarn start
to see it working.
yarn start
Open http://localhost:3000/
in your browser to see your react application working in development mode.
Open http://localhost:3000/api/v1/
to see backend APIs of the application, right now we only have /
route which is rendering a JSON object {"success":true,"message":"Welcome to Node APIs"}
on the screen.
To start a production server run this command in your terminal:
yarn start:prod
In case if you facing any issues please check out the working application code here or you can ask me your questions on twitter.
I hope you must have enjoyed it. I write articles like this every week, you can check those out here mountainfirefly.dev.