Use of Webpack for React and ES6 workflows (Part 6)

Keywords: Javascript Webpack React npm

This is the last article in the React and ECMAScript 2015 series, and we will continue to explore the use of React and Webpack.

Below are links to all the articles in this series:

Github source code for this article

React JS

What is Webpack?

just like JSPM Similarly, Webpack is a modular management solution for your front-end applications.

Use Webpack You can completely control your application resources in a convenient way.

Why is Webpack so popular? The main reasons are as follows:

  • Webpack uses npm as an external module source. If you want to add React to your project, just perform npm install react. This is an additional advantage because you already know how to add your favorite libraries to your project.

  • You can load almost everything, not just JavaScript. Webpack uses a loader named loaders to complete the loading. This is the corresponding loaders Detailed list

  • Webpack has a very powerful development tool ecosystem. Things like hot updates will dramatically change your development process.

  • There are many Webpack plugins for various types of tasks. In most cases, you can use existing solutions.

  • Webpack has a beautiful logo:)

Getting started

Let's start adjusting our application from the previous series.

First, we will install the initial development dependencies.

npm install --save-dev webpack
npm install --save-dev babel-core
npm install --save-dev babel-preset-es2015 babel-preset-react babel-preset-stage-0

In the list above, webpack is self-explanatory. Babel is used to convert ES6 to ES5 (if you have read the previous React and ES6 series, you should be very familiar with ES6 and ES5). Since babel 6, you have to install separate packages for each additional language feature. These packages are called presets. We installed es2015 preset,react preset and stage-0 preset. For more information about babel 6, you can read This article.

Next, install the non-development dependencies (react and react-dom packages):

npm install --save react react-dom

Now the most important step in your project is to build on Webpack. Create the webpack.config.dev.js file under your project root directory. This file will be used to package all of your JavaScript in one bundle (or multiple bundles) (not just JavaScript in most projects), and it will be ready to run in the user's browser.

webpack.config.dev.jsThe contents are as follows:

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

var config = {
    devtool: 'cheap-module-eval-source-map',
    entry: [
        './app.js'
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/dist/'
    },
    plugins: [
        new webpack.NoEmitOnErrorsPlugin()
    ]
};

module.exports = config;

Highlights of the above code:

  • Line 5. Among the various debugging strategies to improve the application, we have a choice. You can click Here Learn more about cheap-module-eval-source-map.

  • Lines 6-8. Here we define app.js as the main entry point for the application.

  • Lines 9-13. This configuration specifies that the Web pack packages all modules into a file bundle.js and places the bundle.js file under the dist / path.

Webpack loaders

With Webpack, you can load almost everything into your code (here is the Detailed list ) Webpack uses the name Webpack loader.

You can make file extensions associated with special loaders.

In our case, we will use babel-loader to convert ES2015/ES6 code into ES5. First, we need to install npm dependency packages.

npm install --save-dev babel-loader

Then, the configuration of the webpack.config.dev.js file is adjusted by adding some new loader keywords to the export object.

var config = {
    ... add the below code as object key ...
    module: {
        loaders: [
            {
                test: /\.js$/,
                loaders: ['babel-loader'],
                exclude: /node_modules/
            }
        ]
    }
};

module.exports = config;

It is important to note that we prohibit Webpack from parsing files in the node_modules folder by setting the exclude keyword.

Next, we add the. babelrc file under the project's root directory.

{
  "presets": ["react", "es2015", "stage-0"]
}

This file is to configure babel to use react,es2015 and stage-0 presets that we added earlier.

Now whenever a Webpack encounters, such as import CartItem from'. / cartItem. js', it loads the file and converts ES6 to ES5.

Add Webpack Development Server

To run this program, we need to run these files on the server.

Fortunately, the Webpack ecosystem already provides everything you need. You can use it. Webpack Development Server perhaps Web pack development middleware, such as Express.js.

We will use the latter. The advantage is that it is faster to process files in memory.

Let's install the npm module:

npm install --save-dev webpack-dev-middleware express

Next, add the server.js file under the root directory:

var path = require('path');
var express = require('express');
var webpack = require('webpack');
var config = require('./webpack.config.dev');

var app = express();
var compiler = webpack(config);

var port = 3000;

app.use(require('webpack-dev-middleware')(compiler, {
    noInfo: true,
    publicPath: config.output.publicPath
}));

app.use(require('webpack-hot-middleware')(compiler));

app.get('*', function (req, res) {
    res.sendFile(path.join(__dirname, 'index.html'));
});

app.listen(port, function onAppListening(err) {
    if (err) {
        console.error(err);
    } else {
        console.info('==> Webpack development server listening on port');
    }
});

This is a typical express.js server using Webpack Dev Middleware.

Add Hot Refresh Module

Webpack Dev Middleware already includes hot refresh features. Whenever your code changes, it refreshes the page immediately.

If you want to see a simple demonstration of hot refresh, look at Dan Abramov's video.

To activate Hot Module Reloading, you must first install the npm package.

npm install --save-dev webpack-hot-middleware

Then set entry and plugins in the webpack.config.dev.js file:

var config = {
    entry: [
        './app.js',
        'webpack-hot-middleware/client'
    ],

    ...

    plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoEmitOnErrorsPlugin()
    ]
};

module.exports = config;

There are many ways to further use module refresh for React applications.

One simple way is to install the babel-preset-react-hmre module.

npm install --save-dev babel-preset-react-hmre

Adjust the content of the. babelrc file:

{
  "presets": ["react", "es2015", "stage-0"],
  "env": {
    "development": {
      "presets": ["react-hmre"]
    }
  }
}

At this point, the application has the function of hot refresh.

The last steps

  • Create index.html file

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>React and ES6 Part 6</title>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/foundation/5.5.2/css/foundation.min.css">
</head>
<body>
<nav class="top-bar" data-topbar role="navigation">
    <section class="top-bar-section">
        <ul class="left">
            <li class="active">
                <a href="http://egorsmirnov.me/2016/04/11/react-and-es6-part6.html" target="_blank">
                    Blog post at egorsmirnov.me: React and ES6 - Part 6, React and ES6 Workflow with Webpack
                </a>
            </li>
        </ul>
    </section>
</nav>
<div class="root"></div>
<script src="/dist/bundle.js"></script>
</body>
</html>
  • Create app.js file

import React from 'react';
import ReactDOM from 'react-dom';
import CartItem from './cartItem.js';

const order = {
    title: 'Fresh fruits package',
    image: 'http://images.all-free-download.com/images/graphiclarge/citrus_fruit_184416.jpg',
    initialQty: 3,
    price: 8
};

ReactDOM.render(
    < CartItem
        title={order.title}
        image={order.image}
        initialQty={order.initialQty}
        price={order.price
        }
    />,
    document.querySelector('.root')
)
;
  • Create cartItem.js file

import React from 'react';

export default class CartItem extends React.Component {

    static propTypes = {
        title: React.PropTypes.string.isRequired,
        price: React.PropTypes.number.isRequired,
        initialQty: React.PropTypes.number
    };

    static defaultProps = {
        title: 'Undefined Product',
        price: 100,
        initialQty: 0
    };

    state = {
        qty: this.props.initialQty,
        total: 0
    };

    constructor(props) {
        super(props);
    }

    componentWillMount() {
        this.recalculateTotal();
    }

    increaseQty() {
        this.setState({qty: this.state.qty + 1}, this.recalculateTotal);
    }

    decreaseQty() {
        let newQty = this.state.qty > 0 ? this.state.qty - 1 : 0;
        this.setState({qty: newQty}, this.recalculateTotal);
    }

    recalculateTotal() {
        this.setState({total: this.state.qty * this.props.price});
    }

    render() {
        return (
            <article className="row large-4">
                <figure className="text-center">
                    <p>
                        <img src={this.props.image}/>
                    </p>
                    <figcaption>
                        <h2>{this.props.title}</h2>
                    </figcaption>
                </figure>
                <p className="large-4 column"><strong>Quantity: {this.state.qty}</strong></p>

                <p className="large-4 column">
                    <button onClick={this.increaseQty.bind(this)} className="button success">+</button>
                    <button onClick={this.decreaseQty.bind(this)} className="button alert">-</button>
                </p>

                <p className="large-4 column"><strong>Price per item:</strong> ${this.props.price}</p>

                <h3 className="large-12 column text-center">
                    Total: ${this.state.total}
                </h3>

            </article>
        );
    }
}

Modify package.json

Now all the previous fragmented code has been integrated into one project.

We need to add some scripts in the scripts area of the package.json file.

{
  "name": "awesome-application",
  "version": "1.0.0",
  ...
  "scripts": {
    "start": "node server.js"
  },
  ...
}

Operating project

  • Run npm start

  • Open http://localhost:3000 in the browser

  • Project Operation Effect Chart

Webpack production environment configuration

Now we can run our application on the server and refresh our pages with hot module updates.

But what if we want to deploy the product to the production environment? No problem. Webpack has a solution.

Create a webpack.config.prod.js file with the following contents:

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

var config = {
    devtool: 'source-map',
    entry: [
        './app.js'
    ],
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    plugins: [
        new webpack.optimize.OccurrenceOrderPlugin(),
        new webpack.DefinePlugin({
            'process.env': {
                'NODE_ENV': JSON.stringify('production')
            }
        }),
        new webpack.optimize.UglifyJsPlugin({
            compressor: {
                warnings: false
            }
        })
    ],
    module: {
        loaders: [
            {
                test: /\.js$/,
                loaders: ['babel-loader'],
                exclude: /node_modules/
            }
        ]
    }
};

module.exports = config;

It is similar to configuration files in development mode, but has the following differences:

  • Hot refresh is no longer available because it is not required in production environments.

  • JavaScript bundle s are dependent on the UglifyJs compression of webpack.optimize.UglifyJsPlugin.

  • The environment variable NODE_ENV is set to production. This requires masking warnings from React development environments.

Next, update scripts in the package.json file:

{
  ...
  "scripts": {
     "start": "node server.js",
     "clean": "rimraf dist",
     "build:webpack": "NODE_ENV=production webpack --progress --colors --config webpack.config.prod.js",
     "build": "npm run clean && npm run build:webpack"
  },
  ...
}

So far, if you run NPM build on the console, the compressed file bundle.js will be created and placed under the dist / path. This document is ready to be used in the production environment.

This is just the beginning.

What we've just learned is just some of the basics of Webpack.

Webpack is an easy tool to get started, but to master it, you need time to study it.

Reference Documents

Sweeping application to join the whole stack tribe

Posted by snowrhythm on Thu, 13 Jun 2019 13:03:53 -0700