React, Babel + Eslint Configuration

If you want to configure your npm package to have JavaScript static code analysis then you will need to configure some form of js linter. For the purposes of this demo I will use eslint.

Before We Begin:

Packages:

Package Installations:

npm install --save-dev babel
npm install --save-dev babel-core
npm install --save-dev babel-loader
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-eslint //OPTIONAL
npm install --save-dev eslint
npm install --save-dev eslint-loader
npm install --save-dev eslint-plugin-react
npm install --save-dev uglifyjs-webpack-plugin

Webpack.config.js:

Webpack 3 Plugins

Add “NoEmitOnErrorsPlugin” to ensure that emitting doesn’t occur if errors are encountered.

Add “UglifyJsPlugin” to minimize your js

Add “AggressiveMergingPlugin” to get more aggressive chunk merging.

Don’t forget the loaders for babel and eslint.

const UglifyJsPlugin = require('uglifyjs-webpack-plugin');

#Under module.exports add
plugins: [
    	new webpack.NoEmitOnErrorsPlugin(),
    	new UglifyJsPlugin(),
    	new webpack.optimize.AggressiveMergingPlugin()
],
module: {
    	loaders: [
			{
				enforce: "pre",
				test: /\.jsx?$/,
				exclude: /(node_modules|thirdparty)/,
				loader: "eslint-loader",
			},
			{
				test: /\.jsx?$/,
				exclude: /(node_modules)/,
				loader: "babel-loader",
				query: {
					presets: ["es2015","react"],
				}
			},
    	]
}


.eslintrc

You can set anything in your .eslintrc file. Here are just some that I use. All the rules starting with “react” are from “eslint-plugin-react” package.

{
    "parser": "babel-eslint",
    "env": {
        "browser": true,
        "mocha": true,
        "es6": true
    },
    "globals": {
        "require": true
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "new-cap": 0, //disabled 
        "strict": 0, //disabled 
        "semi": [2, "always"], //semi-colon required
        "no-underscore-dangle": 0, //no underscores before and after off
        "no-use-before-define": 1, //Make sure you define then use
        "eol-last": 0, //File doesn't need a newline at end
	"no-trailing-spaces": [2, { skipBlankLines: true }],
        "no-unused-vars": [1, {"vars": "all", "args": "none"}],
        "quotes": [
            2,
            "double"
        ],
        "jsx-quotes": [2, "prefer-double"], //Must use double quotes
        "react/jsx-boolean-value": 1, //warning when no value is set for boolean
        "react/jsx-no-undef": 2, //error: undeclared variables
        "react/jsx-uses-react": 1, //Warn: Prevent incorrectly unused
        "react/jsx-uses-vars": 1, //Warn: Prevent unused variables
        "react/no-did-mount-set-state": 0, //Off: Prevent setState in componentDidMount
        "react/no-did-update-set-state": 0, //Off: Prevent setState in componentDidUpdate
        "react/no-multi-comp": 1, //Warn: Prevent only one component per file
        "react/no-unknown-property": 1, //Warn: Prevent unknown DOM
        "react/react-in-jsx-scope": 1, //Warn: Prevent missing React
        "react/self-closing-comp": 1 //Warn: Prevent extra closing tags
    }
}

.eslintignore

Use this file to ignore any files or folders.

app/folder/**

.babelrc

This is the config file for babel.

{
 "presets": [ "es2015" ]
}

Package.json

If you want to run eslint from npm then you have to modify your package.json with the following line. –ext is what extension you want to test against.

If you want a third party to run reports on your eslint then add to the end “-f checkstyle > eslint.xml

"scripts": {
    "eslint": "eslint app --ext .jsx --ext .js"
}

Django: React Website

In this tutorial I will demonstrate how to create a Django + React website using Django 2.0. You must have Eclipse installed before you continue. If you have it already installed and configured you can continue on. We will require Postgres 9.4, nodejs before you continue. You can get Nodejs from here. You can get Postgres 9.4 from here.

Pip Django Install:
pip install django
pip install django-webpack-loader
Django Version:

If you are not sure what version you are running do the following

python -c "import django; print(django.get_version())"
Eclipse Create Project:

 

 

 

 

 

 

Eclipse Setup Project:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Eclipse Django DB Settings:

 

 

 

 

 

 

 

 

 

 

 

 

 

Eclipse Django Setup Successful:

Once you click “Finish” your project will look like the following.

 

 

 

Folder Structure:
  • Under djangoApp project.
  • folder: static
  • folder: djangoApp
    • folder: templates
      • file: index.html
      • folder: base
        • file: base.html
  • folder: assets
    • folder: bundles
    • folder: js
      • file: index.jsx
Node:

Inside the djangoApp application do the following

npm init
npm install --save-dev jquery react react-dom webpack webpack-bundle-tracker babel-loader babel-core babel-preset-es2015 babel-preset-react
npm install create-react-class --save
webpack.config.js:
var path = require('path')
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')

module.exports = {
    //the base directory (absolute path) for resolving the entry option
    context: __dirname,
    //the entry point we created earlier. Note that './' means 
    //your current directory.
    entry: {
		"index": [path.resolve(__dirname, "./assets/js/index.jsx")],
	},
	output: {
		path: path.resolve('./assets/bundles/'),
		filename: "[name]-[hash].js",
	},
    plugins: [
        //tells webpack where to store data about your bundles.
        new BundleTracker({filename: './webpack-stats.json'}), 
        //makes jQuery available in every module
        new webpack.ProvidePlugin({ 
            $: 'jquery',
            jQuery: 'jquery',
            'window.jQuery': 'jquery' 
        })
    ],
    module: {
        loaders: [
		{
			test: /\.jsx?$/,
			exclude: /(node_modules)/,
			loader: 'babel-loader',
			query: {
				presets: ['react','es2015']
			}
		}
        ]
    }
}
djangoApp\Settings.py:

Installed Apps

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'webpack_loader',
]

Add/Edit the following template directive

TEMPLATES = [
 {
    'BACKEND': 'django.template.backends.django.DjangoTemplates',
    'DIRS': [os.path.join(BASE_DIR, 'djangoApp', 'templates'),],
    'APP_DIRS': True,
    'OPTIONS': {
        'context_processors': [
            'django.template.context_processors.debug',
            'django.template.context_processors.request',
            'django.contrib.auth.context_processors.auth',
            'django.contrib.messages.context_processors.messages',
        ],
    },
},]

Add the following static directive

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'assets'),
]

Modify DATABASES

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'YOUR_DB_NAME',
        'USER': 'YOUR_USER',
        'PASSWORD': 'YOUR_PASSWORD',
        'HOST': 'localhost',
        'PORT': 5432
    }
}

Webpack Loader

WEBPACK_LOADER = {
    'DEFAULT': {
        'BUNDLE_DIR_NAME': 'bundles/',
        'STATS_FILE': os.path.join(BASE_DIR, 'webpack-stats.json'),
    }
}
djangoApp\views.py:

We will create our index page view. Notice the third dict. Those are variables passed to the template to make our site dynamic

from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {'title': 'Index Page', 'script_name': 'index'})
djangoApp\urls.py:

Add the following imports

from django.conf.urls import url
#This is the index view we created above
from djangoApp.views import index

urlpatterns = [
    url(r'^$', index, name='index'),
    path('admin/', admin.site.urls),
]
djangoApp\templates\base\base.html:

Let’s setup our base template and setup our blocks that the other templates will inherit from.

<html>
	<head>
		<title>{% block title %}{% endblock %}</title>
	</head>
	<body>
		{% block content %}
		{% endblock %}
	</body>
</html>
djangoApp\templates\index.html:

The important parts here are the extends otherwise your base.html template won’t be inherited. As well the {% with %} and title variable makes our template dynamic and allows us to incorporate react in our site.

{% extends "base/base.html"  %}
{% load render_bundle from webpack_loader %}
{% load staticfiles %}
{% block title %}
	{{title}}
{% endblock %}
{% block content %}
	<div id="container"></div>
	{% with script=script_name %}
		{% render_bundle script 'js' %}
	{% endwith %} 
{% endblock %}
assets\js\index.jsx:

This is our react class.

var React = require('react');
var ReactDOM = require('react-dom');
var createReactClass = require('create-react-class');

var App = createReactClass({
    render: function() {
        return (
            <h1>
            React App Page
            </h1>
        )
    }
});

ReactDOM.render(<App />, document.getElementById('container'));
Database Setup/Migration:

For this tutorial we used postgres. At this time please make sure you create your djangoApp db and user you specified in the settings.py file. Then run the following commands in order.

#Migrates the auth
python manage.py migrate auth
#migrates the rest
python manage.py migrate
#Create the user for accessing the django admin ui
#This will ask you for user names and passwords. Don't make it the same as in your settings.py file.
python manage.py createsuperuser
Start Server:
webpack -p
python manage.py runserver

Your site is now running at http://localhost:8000.

Your admin site is now running at http://localhost:8000/admin/.

 

References:

I used this video as a guideline to get the project started. However some didn’t work right and needed to adjust and made adjustments to require just one template, etc.