Getting Started With ReactJS+Babel+webpack

Getting Started With ReactJS+Babel+webpack

gameblog2.gif

How to set up React⚛️, webpack💠 and Babel〽️

  • [x] how to install and configure webpack

    • [x] Source-map Tool and
  • [x] Webpack-dev-server.
  • [x] how to install and configure Babel
  • [x] how to install and configure Scss to css
  • [x] how to install React
  • [x] how to include the resulting bundle into an HTML page
  • [x] how to install and configure webpack dev server

Setting up the project

To start off create a directory for the project:

mkdir webpack-react-tutorial && cd $_

Create a minimal directory structure for holding the code:

mkdir -p src

Initialize the project by running:

npm init -y

and you’re good to go.

Setting up webpack 💠

Webpack 💠 it's an incredibly powerful (and complex) tool. You can get by without touching a single line of configuration, but there will be a time for some custom setup of sort. Sooner or later you may want to learn webpack. Why not starting now?

Learning webpack is valuable not only for working with React, but for configuring every frontend project as well. Here webpack will ingest raw React components for producing JavaScript code that (almost) every browser can understand.

Configuring Webpack features in React project:

  • [x] Avoid Global Modules

  • [x] ES6 import/export

  • [x] Default Exports

  • [x] Importing npm Modules (dependencies)

    ⚠️ Warning: Always go through documents for Dependencies installation for bash Commands as they get updated with dependency updates.

  • [x] Configuring webpack.config.js (for development and Production)

  • [x] Setting up Babel with Webpack

  • [x] One Component per File (Ease up the complex Structure of app)

  • [x] Source Maps with Webpack (Helps in Detecting Errors in complex component structure)

  • [x] Webpack Dev Server

  • [x] ES6 class properties (Transforming Bindingthisinside constructor )

Let's install webpack and webpack-cli by running:

npm i webpack webpack-cli --save-dev

Now add the webpack command inside package.json:

"scripts": {
  "build": "webpack --mode production"
}

At this point there is no need to define a configuration file for webpack. Older webpack versions would automatically look for a configuration file. Since version 4 that is no longer the case.

In the next section we'll install and configure Babel for transpiling our code.

  • 📌. Click here for dependencies installation for React ⚛️

Giving Entry point and output folder path to save bundle.js

const path = require('path');
module.exports = {
  // app entry point
  entry: './src/app.js',
  // output point
  output: {
    path: path.resolve(__dirname, 'public'),
    filename: 'bundle.js',
  }
}

Setting up a development environment and devTool

To make our lives a little easier. It quickly becomes a hassle to manually run npm run build every time you want to compile your code.

There are a couple of different options available in webpack that help you automatically compile your code whenever it changes:

  1. Webpack's Watch Mode
  2. Webpack-dev-server

1. Webpack's Watch Mode:

2 Source-map Tool and Webpack-dev-server:

It's a little development server similar to Live server. webpack-dev-server comes with some nice to have features specific to web:

  1. For example, is going to speed up the process between changing our application files and actually seeing those changes reflected in the browser.

Steps to configure dev-server on React

  1. Adding devServer- provides you with a simple web server and the ability to use live reloading. Let's set it up:

Let's set it up:

    npm install --save-dev webpack-dev-server

Change your configuration file webpack.config.js to tell the dev server where to look for files:

  devServer: {
      contentBase: path.resolve(__dirname, 'public'),
    };

final Version of webpack.config.js files

// app.js -> First up we have to let it know where the entry point is where does our application kick-off for us
// We also have to tell it where to output the final bundle file. So we're creating that one big javascript file that contains everything our app needs to run.

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

  // Webpack Developer Tool - for pointing out errors/console.log.out's in a complex components             structure using browser console
  devtool: 'cheap-module-eval-source-map',
  // webpack development server
  devServer: {
    contentBase: path.resolve(__dirname, 'public'),
  },
};

// A loader :
// - lets you customize the behavior of web pack when it loads a given file.
// - So for example anytime web package sees a .js file we will run it through BABEL

and update in package.json file:

    "scripts": {
      "dev-server": "webpack-dev-server --open"
    }

Setting Source-map DevTool Using source maps

    devtool: 'inline-source-map',

or even use devtool: 'cheap-module-eval-source-map' for pointing out errors/console.log.out's in a complex components structure using browser console

  devtool: 'cheap-module-eval-source-map',

Configuring up 〽️ Babel

React components are mostly written in modern JavaScript syntax. Take the class keyword for example. Stateful React components can be declared as classes, or as an arrow (or regular functions). But older browsers don't understand ECMAScript 2015, thus we need some kind of transformation. That transformation is called transpiling.

Webpack per-se doesn’t know how to transform JavaScript. Instead, it relies on loaders: think of them as of transformers A webpack loader takes something as the input and produces an output, called bundle.

  • babel-loader is the webpack loader responsible for talking to Babel. This allows us to run babbel under certain conditions in our case we specify a rule we said whenever. Babel on the other hand must be configured to use presets.

    We need two of them:

  • babel preset env for compiling modern Javascript ES6 down to ES5

  • babel preset-react for compiling JSX and other stuff down to Javascript.

Let's pull in the dependencies with:

npm i @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev

Next up configure Babel. Create a new file named .babelrc inside the project folder with the following code:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

At this point we're ready to define a minimal webpack configuration. Create a file named webpack.config.js and fill it like so:

module.exports = {
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },
    ],
  },
};

The configuration is quite minimal. For every file with a js or jsx extension Webpack pipes the code through babel-loader. With this in place we're ready to write a React.

Configuring Babel Plugin transform class property

  • Babel’s Transform Class Properties Plugin:

Babel

Babel is a powerful tool for writing next generation JavaScript. It’s widely used to compile code written with newer and experimental JavaScript features (as well as JSX in React apps) into syntax browsers can understand.

Developers no longer need to wait for recently added features to get adopted by browsers or for promising new features to go through the lengthy TC39 process, where each proposal must get approved to move through various stages before finally getting added to the next ECMAScript spec. Thanks to a whole host of Babel presets and plugins, we can now write the JavaScript of tomorrow, today.

In this post, we’ll go over a particularly useful Babel plugin for your React apps and how you can use it to write cleaner, more concise code.

Class Properties Transform

If you’ve ever written a React app, you may have seen something along the lines of:

constructor(props) {
  super(props);
  this.state = { ...some initial state... }

  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
  this.someHandler = this.someHandler.bind(this);
}

Whoa! That’s a lot of handlers.*

And what a drag it is to have to individually bind the this context to each of them just so they can be passed down as props and invoked somewhere further down the component tree. How many times have you forgotten to do this tedious task and gotten an error message saying “this.setState is not a function”? How many times have you looked at a piece of code like the one above and thought to yourself, “There’s gotta be a better way…”

Well, guess what? There is, thanks to Babel’s Class Properties Transform plugin…

According to the documentation, this plugin will transform class properties in such a way that you can define class properties using property initializer syntax (ie. by using the = assignment operator).

In JavaScript, current class syntax only allows for you to define methods inside of a class, nothing else.

class Cat {
  constructor(name, breed) {
    this.name = name;
    this.breed = breed;
  }
  getBreed() {
    return this.name + ' is a ' + this.breed;
  }
}

Any properties you want on an instance of an object created with a class need to be defined inside of the special constructor method, whereas any other methods defined in the class — like the getBreed() method in the example above — will live on that instance’s prototype.

But with Babel’s Class Properties Transform plugin, you no longer have to follow these rules, and instead can do something like this:

class Cat {
  name = 'Chairman Meow';
  breed = 'Sphynx';

  getBreed = function () {
    return this.name + ' is a ' + this.breed;
  };
}

In this version, the ‘name’ and ‘breed’ properties as well as the getBreed() method will live on the instance, whereas before getBreed() was on the prototype.

So how does this tie into React and not having to bind the this context to every handler I want to pass down as a prop?

refer this article on How it Works and What it Means for your React Apps.

Writing React components:

We'll build a super simple React form with a single text input. Before touching any code let's pull in React:

npm i react react-dom

A question I get a lot is "should I install react and react-dom as dev dependencies or not?". It doesn’t matter for the final result. webpack will still produce your bundle.

Now create a minimal directory structure for holding the component:

mkdir -p src/js/components/

Next up let's create a React component that:

has its own state renders an HTML form Create the component in src/js/components/Form.js:

import React, { Component } from "react";
import ReactDOM from "react-dom";

class Form extends Component {
  constructor() {
    super();

    this.state = {
      value: ""
    };

    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    const { value } = event.target;
    this.setState(() => {
      return {
        value
      };
    });
  }

  render() {
    return (
      <form>
        <input
          type="text"
          value={this.state.value}
          onChange={this.handleChange}
        />
      </form>
    );
  }
}

export default Form;

const wrapper = document.getElementById("container");
wrapper ? ReactDOM.render(<Form />, wrapper) : false;

And now it's time to wire things up. webpack expects the entry point in src/index.js. Create the file and place an import directive into it for requiring your React component:

import Form from "./js/components/Form";

With this in place we're ready to create our bundle by running:

npm run build

Give webpack a second and see the bundle come to life in dist/main.js. Now let's bring our experiment to life by including the bundle into an HTML page.