React Development Environment without using CRA(create-react-app)

When creating a new React project, there is an option of using create-react-app which as per official site, offers a modern build setup with no configuration. It is very easy to use and with just one command npx create-react-app my-app, it will set up the environment for you to start writing code in few minutes.

But what if you need to have more control over module bundling and want to learn more about it? Also, CRA installs lots of node packages and you may not require all of them.

With that in mind, let's set up a simple React development environment with only few node packages. We will mainly use webpack as module bundler and Babel which is a transpiler to convert Javascript ES6 code in to backward compatible version of Javascript for current and older browsers.

  1. Create new project directory

    mkdir test-app
    cd test-app
    
  2. Initialize project using npm

    npm init -y
    
  3. You should have package.json file created with below contents.

    {
    "name": "test-app",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
    }
    
  4. Next step is to set up a webpack. According to official site, webpack is a static module bundler for modern JavaScript applications. It will bundle all the project Javascript files in to single file and include it as a script tag in the webpage to load the React application. For webpack, we need to install both webpack and webpack CLI. Let's install these as dev dependencies
    npm install --save-dev webpack webpack-cli
    
  5. The next step is to update scripts section in package.json to run webpack. Add below start script under scripts.
    "start": "webpack --mode development"
    
    Updated package.json should looks like below:
    {
    "name": "test-app",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
     "start": "webpack --mode development"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
    }
    
  6. Create new directory called src under project.
  7. Create new file called index.js inside src directory with below contents. For now, let's just add single console statement. We'll update it later to add some React code.
    console.log("Test App");
    
  8. Try running npm start. This will start webpack and create new directory called dist. Inside dist directory, there should be main.js containing project code. The code will not be minimized because we are running webpack command with development mode. Run below command to make sure that code is working. You should see "Test App" in the console.
    node dist/main.js
    
  9. Now that we have completed basic webpack setup, we can install packages which we need to run React application. The first package is called react which is a core package for React and second one is react-dom which allows entry in to browser's DOM to render React application. Run below command

    npm install react react-dom
    
  10. We will also need to install Babel and its related packages because not every browser can understand Javascript ES6 syntax. Babel is a transpiler which compiles the code written in ES6 to browser friendly version. In addition to babel core, we need to install babel-loader which allows to run Babel with webpack and two preset packages. The first preset package is called babel/preset-env which will compile Javascript ES6 code in to browser friendly format. The second package is called babel/preset-react which compiles React specific code. Run below command to install these.

    npm install --save-dev @babel/core @babel/preset-env @babel/preset-react babel-loader
    
  11. The next step is to make Babel and webpack works together. Create webpack.config.js under root directory. Add below code in webpack.config.js. The configuration tells webpack to use babel-loader for compiling all files with js extension. The files in node_modules directory will be ignored.
    module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                }
            }
        ]
    }
    }
    
  12. Create .babelrc under project directory for Babel specific configurations. Add below code in ./babelrc which will configure babel-loader to use babel/preset-env and babel/preset-react while compiling all the code.
    {
    "presets": [
        [
            "@babel/preset-env",
            {
                "targets": {
                    "node": "current"
                }
            }
        ],
        "@babel/react"
    ]
    }
    
  13. At this point we have completed setting up webpack and Babel to run React Application. Let's add some React code and run in browser. Replace code in index.js with below code.
    import React from 'react';
    import ReactDOM from 'react-dom';
    const App = () => {
      return <h4>Welcome to App</h4>;
    }
    ReactDOM.render(<App />, document.getElementById('root'));
    
  14. Create index.html inside src directory. Notice section with id 'root' under body which will mount the App we added in index.js
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Test App</title>
    </head>
    <body>
        <section id="root"></section>
    </body>
    </html>
    
  15. The final step of rendering React Application is to update webpack config so that it adds React Application code as script tag in index.html. For that, we will need to install html-webpack-plugin package as dev dependency.
    npm install --save-dev html-webpack-plugin
    
  16. Add html-webpack-plugin to webpack.config.js. We are setting the entry point as index.html which will tell webpack about where to put bundled code.
    const HtmlWebPackPlugin = require('html-webpack-plugin');
    const htmlPlugin = new HtmlWebPackPlugin({
    template: './src/index.html',
    filename: './index.html'
    });
    module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                }
            }
        ]
    },
    plugins: [htmlPlugin]
    }
    
  17. Let's verify the set up by running npm start which should start webpack in development mode and add index.html and index.js under dist directory. The index.html file should contain script tag for main.js. Lastly, run below command to see our app running in browser.
    open dist/index.html
    
  18. Let's do final step of creating development server. In the set up so far, every time we make changes, we'll need to run npm start to reflect those changes in browser. We can avoid that by installing webpack-dev-server package by running below command.
    npm install --save-dev webpack-dev-server
    
    We'll need to update start script in package.json to use webpack-dev-server instead of webpack to run the application. Update start script in package.json as below:
    "start": "webpack-dev-server --mode development --open"
    
    Final package.json should looks like below
    {
    "name": "test-app",
    "version": "1.0.0",
    "description": "Test App",
    "main": "index.js",
    "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --mode development --open"
    },
    "author": "<your name>",
    "license": "ISC",
    "devDependencies": {
    "@babel/core": "^7.17.8",
    "@babel/preset-env": "^7.16.11",
    "@babel/preset-react": "^7.16.7",
    "babel-loader": "^8.2.4",
    "html-webpack-plugin": "^5.5.0",
    "webpack": "^5.71.0",
    "webpack-cli": "^4.9.2",
    "webpack-dev-server": "^4.7.4"
    },
    "dependencies": {
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
    }
    }
    
  19. Running npm start now should start the webpack-dev-server and opens the web page in browser. If you make any changes to code, the page should get updated automatically to reflect those changes.

Thanks and Happy Coding!