Create a new React application the easy way.

Creating a new React application can be a pretty daunting task. Sure, technically you can just include the JavaScript file from the CDN at the top of your page and be on your way. But as you start to explore the React ecosystem and see examples online, you'll soon be pining for extra tooling. E.g., working with React is a lot more joyful and productive when used with JSX, and you'll want to take advantage of NPM modules, and include a testing framework, and add Less or Sass for your CSS preprocessing, and...

Pretty soon you're stuck configuring a complex set of tools, among which are a dizzying array of choices and options. It's hard to know where to even start!

Introducing create-react-app

Several months ago Facebook created a new tool called create-react-app to address this problem. Its goal is to "Create React apps with no build configuration." To try it out, first make sure you have Node and NPM installed. Node is a JavaScript runtime that React's tools require, and NPM is a package manager to download third-party libraries for Node. You can get instructions for installing them here and here. After that's set up, use NPM to install create-react-app globally, like this:

npm install -g create-react-app

Let's create our fist React app!

To get started, simply change into the directory above where you want to create your new project, and type this:

create-react-app my-app

What just happened?

First, the script will create a new my-app subdirectory, along with a skeleton react project. Inside that project, it creates a file named package.json, which declares the project dependencies to NPM. If you open package.json in your favorite editor you might be surprised to see that there aren't a lot of packages listed given the amount of time NPM spent downloading. The reason for this is all of the needed modules are dependencies of the react-scripts module. You can see the child dependencies of react-scripts by typing this at the command line.

npm view react-scripts

Run the template app

Next, run the start script to start the development server. After the server starts, the script will open a browser window with your new pre-fab React application!

npm start

Delve into the project

The main file served up by the dev server is located in the public subdirectory, named index.html. If you take a peek at that file in your editor, you'll see it's pretty sparse. The only notable element in the body is a div tag with an ID of root. However, if you view the source HTML for the page being served up in your browser, you'll notice that it has some style information and it includes a JavaScript file named bundle.js.

Wait, where the heck did that come from?

Behind the scenes, create-react-app set up a tool called Webpack. The Webpack configuration files are buried in the node_modules/config directory - there's one for development and one for production. Webpack is responsible for "compiling" your application, and does so using a set of modules and plugins. The insertion of the JavaScript file into index.html was done by a Webpack plugin called HtmlWebpackPlugin. Other things that Webpack can do are:

  • Run the development server.
  • Set up another tool called Babel which transpiles JSX files into standard ES5 JavaScript. 
  • Merge all of your JavaScript source files into a single "bundle" file.
  • Configure a Linter to analyze your code.
  • Monitor the source files for modifications, and automatically recompiles when necessary. 

When run in production mode (more on that in a sec), Webpack will also minify your JavaScript and CSS.Webpack can also compile your Sass files into CSS, but by default, create-react-app does not do this for you. More on that in a bit.

Try editing your JavaScript

If you take a peek in the project src folder, you'll see several JavaScript files which comprise the source code for the app. The "base" that bootstraps the application is in index.js. The only thing index.js does is render the App component into the div with the root ID. The App component is, as you'd expect, in the App.js file.

Go ahead and insert an h1 element in the top of the component, inside the first div.

After you save the file, your browser will automatically refresh and show the new header text. The Webpack configuration set the hot reload up for you.

class App extends Component { 
  render() { 
    return (
      <div className="App"> 
        <h1>HELLO REACT!</h1>

        <div className="App-header"> 
          <img src={this.props.logo} className="App-logo" alt="logo" /> 
          <h2>Welcome to React</h2> 
        </div> 

        <p className="App-intro"> 
          To get started, edit
          {' '}
          <code>src/App.js</code> and save to reload. 
        </p> 
      </div>
    ); 
  } 
}

Building for Production

This setup is great for development, but it has not been optimized for production use. Fortunately create-react-app includes a script that does the optimization for you. Shut down your development server by typing Ctrl-C, and at the command line, run:

npm run build

This script will create a subdirectory in your project named build, and will emit your application in an optimized form ready for production use. The script gives instructions for how to serve the built project using a static file server if you want to test it out.

Testing

Testing react applications is beyond the scope of this article, but create-react-app will set up all the needed modules and tooling to execute automated tests for your project. The default configuration uses Jest to run tests, Note that Jest runs in a node environment, and not in a headless browser like some other popular JavaScript test runners like Karma. If you need that functionality, you will need to set it up seperately.

The tools are configured to run any tests named with the .test.js or .spec.js suffix, or any JavaScript files under a directory named test, under the src directory. To execute the tests, simply run:

npm test

Jest comes with its own testing DSLs that are fully documented and should be familiar to anyone who has written unit tests with other popular testing frameworks. That said, it's straightforward to add dependencies for other assertion libraries if that's what you prefer - just add them as dependencies for your project, e.g.:

npm install chai --save-dev

Then import the library:

import expect from 'chai';

Customizing your Dependancies: Eject

This react-scripts list of dependencies should be an adequate baseline for most React projects. Adding new dependencies (e.g., Redux) can be easily accomplished by adding it to package.json or using npm install --save-dev. There may be some rare circumstances where you want more control over the dependencies. For example, react-script's dependency tree uses stable releases of modules, and you might prefer to use some more experimental versions. Or you might want to reduce the size of your JavaScript build by removing modules which you're certain you are not going to use. Perhaps you want finer grained control over the webpack configuration file.The create-react-app module created a script for this purpose called eject. It's a one-way operation; once you run the eject script, there is no going back.

npm eject

Will modify your package.json file, replacing the dependency on react-scripts with each individual module on which react-scripts depends. With the modified file you can pick and choose among available module versions or remove those you don't need.

Further Reading

The GitHub repo for create-react-app contains extensive documentation within its README files. The react-scripts subdirectory within the repo has a handy Users Guide which is also included as part of the react-scripts module in your project's node_modules directory.

Many projects will want to use some sort of CSS compiler to convert a language like Sass or Less to CSS. Unfortunately, create-react-app currently does not support this by default, although it has been discussed and may come at a future date. In the meantime, you can add it yourself by following Connor Elsea's excellent instructions in this Medium post. This will require you to run the eject script because you'll need to tweak your Webpack configuration a bit.