This guide will help set up your django project to use ReactJS
- django-webpack-loader==0.4.1 ( Connects Django project with Webpack)
- django-cors-headers==2.0.2 (Allows us to easily customize CORS settings)
INSTALLED_APPS = [
...
'corsheaders',
'webpack_loader',
...
]Add CORS settings in your base settings:
# CORS CONFIGURATION
# ------------------------------------------------------------------------------
# https://github.com/ottoyiu/django-cors-headers#configuration
CORS_ORIGIN_ALLOW_ALL = TrueAdd Webpack loader settings for local and production settings.
Local:
# Webpack Loader by Owais Lane
# ------------------------------------------------------------------------------
# https://github.com/owais/django-webpack-loader
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'builds-dev/',
'STATS_FILE': os.path.join(str(ROOT_DIR), 'frontend', 'webpack', 'webpack-stats.dev.json')
}
}Production:
# Webpack Loader by Owais Lane
# ------------------------------------------------------------------------------
# https://github.com/owais/django-webpack-loader
WEBPACK_LOADER = {
'DEFAULT': {
'BUNDLE_DIR_NAME': 'builds/',
'STATS_FILE': os.path.join(ROOT_DIR, 'frontend', 'webpack', 'webpack-stats.production.json')
}
}Add CORS middleware according to these instructions. I personally split them up like below. This allows us to meet the criteria of both CORS and Whitenoise :).
In Base settings:
# MIDDLEWARE CONFIGURATION
# ------------------------------------------------------------------------------
SECURITY_MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
]
# This is required to go first! See: https://github.com/ottoyiu/django-cors-headers#setup
CORS_MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
]
DJANGO_MIDDLEWARE = [
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
MIDDLEWARE = SECURITY_MIDDLEWARE + CORS_MIDDLEWARE + DJANGO_MIDDLEWAREIn Production settings:
# Use Whitenoise to serve static files
# See: https://whitenoise.readthedocs.io/
WHITENOISE_MIDDLEWARE = ['whitenoise.middleware.WhiteNoiseMiddleware', ]
# CORS Needs to go first! See: https://github.com/ottoyiu/django-cors-headers#setup
MIDDLEWARE = SECURITY_MIDDLEWARE + CORS_MIDDLEWARE + WHITENOISE_MIDDLEWARE + DJANGO_MIDDLEWAREThis where our ReactJS project will live.
mkdir -p frontend
STATICFILES_DIRS = [
str(APPS_DIR.path('static')),
str(ROOT_DIR.path('frontend')),
]This will install all the Javascript libraries we will use
Run npm init and follow the instructions. Just fill in the information for your project.
These are webpack packages. To read more about Webpack visit here. For now, I am using Webpack v1 because Webpack v2 seems a bit unstable and has changed a bit.
npm install --save-dev webpack@1 webpack-dev-server@1 webpack-bundle-tracker
These are packages that allow us to write our code using new ES6 JS. To read more, visit here.
npm install --save-dev babel-cli babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 css-loader style-loader
- axios - Helpful to interact with an API
- lodash - Helpful extra methods that are missing in JS
- victory - Amazing library for charting
npm install --save-dev axios lodash victory
Main ReactJS and Redux:
npm install --save-dev react react-dom redux
ReactJS and Redux plugins:
NOTE: Sticking with react-router@3 and react-router-redux@4 because new versions are in beta and unstable.
npm install --save-dev prop-types react-bootstrap react-fontawesome react-router@3 react-router-redux@4 react-cookie redux-logger redux-thunk react-redux
To allow for hot reloading of React components:
npm install --save-dev react-hot-loader@next redux-devtools redux-devtools-dock-monitor redux-devtools-log-monitor
I choose to use the airbnb JS standards, since they have clearly stated it here
npm install --save-dev eslint eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-config-airbnb babel-eslint
npm install --save-dev karma mocha expect deepfreeze karma-mocha karma-webpack karma-sourcemap-loader karma-chrome-launcher karma-babel-preprocessor enzyme
This will help us bundle and compile all of our front-end stuff. To read more, visit here. In short, it bundles all JavaScript, JSX, etc. code for our project and manages our codebase to be split into bundles to be loaded in in our different environments.
mkdir -p frontend/webpack/
Create frontend/webpack/webpack.base.config.js. The contents should be:
module.exports = {
module: {
loaders: [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'stage-2', 'react']
}
}, {
test: /\.css$/,
loader: 'style-loader!css-loader'
}]
},
resolve: {
modulesDirectories: ['node_modules'],
extensions: ['', '.js', '.jsx']
}
};Create frontend/webpack/webpack.local.config.js. The contents should be:
var path = require('path');
var BundleTracker = require('webpack-bundle-tracker');
var webpack = require('webpack');
var config = require('./webpack.base.config.js');
config.entry = {
main: [
'webpack-dev-server/client?http://0.0.0.0:3000',
'webpack/hot/only-dev-server',
'react-hot-loader/patch',
path.join(__dirname, '../js/src/main/index')
]
};
config.devtool = 'inline-sourcemap';
config.output = {
path: path.join(__dirname, '../js/builds-dev/'),
filename: '[name]-[hash].js',
publicPath: 'http://0.0.0.0:3000/js/builds/',
};
config.plugins = [
new webpack.HotModuleReplacementPlugin(),
new BundleTracker({ filename: './frontend/webpack/webpack-stats.dev.json' }),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development'),
BASE_URL: JSON.stringify('http://0.0.0.0:8000/'),
}
})
];
config.module.loaders[0].query.plugins = ['react-hot-loader/babel'];
config.devServer = {
inline: true,
progress: true,
hot: true,
historyApiFallback: true,
host: '0.0.0.0',
port: 3000
};
module.exports = config;Create frontend/webpack/webpack.production.config.js. The contents should be:
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var config = require('./webpack.base.config.js');
config.entry = {
main: [
path.join(__dirname, '../js/src/main/index')
]
};
config.output = {
path: path.join(__dirname, '../js/builds/'),
filename: '[name]-[hash].min.js',
publicPath: '/js/builds/'
};
config.plugins = [
new BundleTracker({ filename: './frontend/webpack/webpack-stats.production.json' }),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
BASE_URL: JSON.stringify('http://0.0.0.0/'),
}
}),
new webpack.optimize.UglifyJsPlugin({
mangle: false,
sourcemap: false
})
];
module.exports = config;mkdir -p frontend/js/src/main
mkdir -p frontend/builds
mkdir -p frontend/builds-dev
touch frontend/js/src/main/index.jsx
touch frontend/builds/.gitkeep
touch frontend/builds-dev/.gitkeep
Hey Mike, thanks for this. Super handy.
I got the app setup and the
router.jsxloads successfully. However, I'm getting an error when saving changes into it. The hot reloading throws this:I made sure
CORS_ORIGIN_ALLOW_ALL = True, but it seems that it's not effective.Have you run into this or any idea why this might happen?