How to setup a project without Create React App

Create React App is a great way to quickly get started with React development. But it completely hides the build config which makes it difficult to extend.

You can “eject”, but it is overwhelming to work with the big webpack config it generates – even though it has describing comments.

Instead, we are going to setup a React project from scratch to get a deep understanding and full control.

What we are going to do

We are going to set up a simple React project from scratch using the following tools:

  • webpack for building
  • babel for transpiling React and ES6
  • npm for running the app and dependency management

Set up a new NPM project

Let’s start by creating a new NPM project:

mkdir react-starter
cd react-starter
npm init

npm init  will ask you a bunch of questions. Just press enter for the defaults. If you want, you can later change the config it generates by editing package.json that is created by this command.

Create a JavaScript source code file

Next, we are going to create our minimal React app and HTML file.

import React from "react";
import ReactDOM from "react-dom";

class HelloMessage extends React.Component {
  render() {
    return <div>Hello {this.props.name}</div>;
  }
}

var mountNode = document.getElementById("app");
ReactDOM.render(<HelloMessage name="Jane" />, mountNode);

src/app.js

 

<!DOCTYPE html>
<html>
    <head>
        <title>React starter app</title>
    </head>
    <body>
        <div id="app"></div>
        <script src="bundle.js"></script>
    </body>
</html>

dist/index.html

We have created two directories: src  and dist.

  • src is the directory will contain our source files
  • dist is the directory we will configure webpack to put the compiled JavaScript files. To keep things simple, we put the index.html file straight in the dist folder because it’s static and don’t need to go through webpack.

Create the webpack config file

Our webpack config file looks like this:

const webpack = require('webpack');
const path = require('path');

const config = {
    entry: './src/app.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                exclude: /node_modules/,
                use: 'babel-loader'
            }
        ]
    }
};
module.exports = config;

webpack.config.js

It contains the following:

  1. The file src/app.js that we created previously is the entry point
  2. The file dist/bundle.js is the output file.
  3. The module section describes how webpack should transpile the code. It uses the babel-loader for all files that has a .js or a .jsx extension. In the next step we will configure babel-loader.

Add babel config

Babel is a highly configurable tool to transpile JavaScript. We are going to use a subset of babels features: transpiling ES6 and React JSX.

Our webpack config uses babel-loader to run babel which uses the regular babel config file.

We configure babel like this in the file .babelrc:

{
  "presets": ["es2015", "react"]
}

 .babelrc

Now we have all the files we need

This is an overview of the files and folders we have created:

.
├── package.json
├── dist
│   └── index.html
├── src
│   └── app.js
└── webpack.config.js

2 directories, 4 files

Add dependencies

Before we run the application we must add NPM dependencies:

npm install --save-dev webpack
npm install --save-dev babel-loader
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015
npm install --save-dev babel-preset-react
npm install --save react
npm install --save react-dom

Our dependencies are now installed and our package.json file is updated with dependency information.

Run it

We are going to use NPM to start the build with webpack. Add this to the script area in package.json:

  "scripts": {
    "dist": "webpack"
  },

Let’s run it and see what happens:

npm run dist

It works!

Now open up the file index.html in your browser. If you are on a mac, you can do it with this command: open dist/index.html

Now we see “Hello, Jane” in the browser. It is rendered through React and built with webpack/babel! It feels good to have 100% control on how the app is built!

The code is available on GitHub.

What’s next

We have created a good starting point for further development. These are suggestions on what to do next:

  • Make an optimized production build
  • Improve the development experience. We don’t want to run npm run dist  every time we change the code
  • Build less/sass/css with webpack

I write posts about React/webpack/Redux almost every week. Enter your email below to get updates when new posts are published!

  • Hi, I’m snow. Few days ago I received your email, sorry I’m too busy recently. I like all of your frontend articles, 😀

    • jakoblind

      Hi Snow! Glad you still like my articles 🙂

  • Vijay Pawar

    nice