React 和 ES6 工作流之 Webpack的运用(第六部份)

这是React和ECMAScript2015系列文章的末了一篇,我们将继承探究React 和 Webpack的运用。

下面是一切系列文章章节的链接:

本篇文章Github源码

ReactJS
《React 和 ES6 工作流之 Webpack的运用(第六部份)》《React 和 ES6 工作流之 Webpack的运用(第六部份)》

什么是Webpack?

就像JSPM一样,Webpack是你的前端运用的模块治理的解决方案。

运用Webpack,你可以用一种轻易的要领完全掌握你的运用资本。

为何Webpack这么受欢迎?主要有以下几个缘由:

  • Webpack运用npm作为外部模块源。假如你想增加React到你的项目中,只须要实行 npm install react即可。这是一个附加的上风,由于你已晓得怎样将你喜好的库增加到你的项目中。

  • 你险些可以加载一切的东西,而不只是JavaScript。Webpack运用名字为loaders的装载机来完成加载。这是对应的loaders清单

  • Webpack有一个很壮大的开辟东西生态系统。像热更新如许的东西将戏剧性的转变你的开辟流程。

  • 关于种种类型的使命有许多Webpack plugins。在大多数情况下,你可以运用已存在的解决方案。

  • Webpack 有很漂亮的logo :)

Getting started

让我们最先从之前的系列文章中调解我们的运用顺序。

起首,我们将要装置初始的开辟依靠。

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

在上面的列表中,webpack是自诠释型的。Babel是用于将ES6转换成ES5(假如你浏览了前面的React and ES6系列文章,你应当对ES6和ES5异常熟习)。自从babel 6后你必需为每个分外的言语特征装置自力的包。这些包叫做presets。我们装置es2015 preset,react presetstage-0 preset。关于更多关于babel 6的信息,你可以浏览这篇文章

下一步,装置非开辟依靠(react和react-dom包):

npm install --save react react-dom

如今在你的项目中基于Webpack最主要的一步。在你的项目根目录下面建立webpack.config.dev.js文件。这个文件将用来打包你一切的在一个bundle(或许多个bundle)内里的JavaScript(在大多数项目中不只是JavaScript),打包完就可以在用户的浏览器中正式运转。

webpack.config.dev.js的内容以下:

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;

以上代码的亮点:

  • Line 5. 在进步运用顺序的种种调试战略中,我们有一个挑选,你可以点击这里相识更多关于cheap-module-eval-source-map的内容。

  • Lines 6-8. 这里我们定义了app.js为运用顺序的主进口。

  • Lines 9-13. 这个设置制订Webpack将打包一切的模块成文件bundle.js,而且将bundle.js文件放到dist/途径下面。

Webpack loaders

Webpack险些可以加载一切的东西到你的代码中(这里是清单)。Webpack运用的名字叫做Webpack装载机。

你可以制订文件扩展名关联到迥殊的装载机。

在我们的案例中,我们将运用babel-loader来将ES2015 / ES6的代码转换成ES5.起首,我们须要装置npm依靠包。

npm install --save-dev babel-loader

然后,经由过程增加一些新的装载机关键字到出口对象中来调解webpack.config.dev.js文件的设置。

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

module.exports = config;

这里须要重点注重的是,我们经由过程exclude关键字的设置制止Webpack剖析node_modules文件夹内里的文件。

接下来我们在项目的根目录下面增加.babelrc文件。

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

这个文件是设置babel以便可以运用前面我们增加的react,es2015stage-0presets。

如今,不管什么时候Webpack碰到,比方:import CartItem from './cartItem.js',它将加载这个文件而且将ES6转换成ES5

增加Webpack开辟服务器

为了运转这个顺序,我们须要在服务器上运转这些文件。

荣幸的是,Webpack生态系统已供应一切你须要的东西。你可以运用Webpack开辟服务器或许Webpack开辟中间件,比方:Express.js

我们将运用后者。上风是在内存中处置惩罚文件时速度快。

让我们装置npm模块:

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

下一步,在根目录下面增加server.js文件:

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');
    }
});

这是典范的运用Webpack Dev Middlewareexpress.js服务器。

增加热革新模块

Webpack Dev Middleware已包含了热革新的特征。不管什么时候,你的代码发生变化,它都邑马上革新页面。

假如想简朴的看看热革新的演示结果,可以看看Dan Abramov视频

为了激活Hot Module Reloading,你起首得装置必需得npm包。

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

然后在webpack.config.dev.js文件中设置entryplugins:

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

    ...

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

module.exports = config;

假如想对React 运用更进一步运用模块革新其实有许多种要领。

个中一个简朴的要领就是装置babel-preset-react-hmre模块。

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

调解.babelrc文件的内容:

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

到这一步,这个运用就具有热革新的功用。

末了几步

  • 建立index.html文件

<!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>
  • 建立app.js文件

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')
)
;
  • 建立cartItem.js文件

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>
        );
    }
}

修正package.json

如今已将前面一切碎片化的代码已整合在一个项目中。

我们须要在package.json文件的scripts地区增加一些剧本。

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

运转项目

  • 运转npm start

  • 在浏览器中翻开http://localhost:3000

  • 项目运转结果图
    《React 和 ES6 工作流之 Webpack的运用(第六部份)》

Webpack临盆环境设置

如今我们可以在服务器上运转我们的运用顺序而且可以经由过程热模块更新革新我们的页面。

然则假如我们想要将产物布置到临盆环境?没问题,Webpack有对应的解决方案。

建立webpack.config.prod.js文件,文件内容为:

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;

它和开辟形式下的设置文件有点类似,然则有以下不同点:

  • 热革新的功用不再有,由于在临盆环境中不须要这个功用。

  • JavaScript bundle被依靠于webpack.optimize.UglifyJsPluginUglifyJs紧缩。

  • 环境变量NODE_ENV被设置成production。这须要屏障来自React开辟环境中的正告。

下一步,更新package.json文件中的scripts

{
  ...
  "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"
  },
  ...
}

到如今为止,假如你在掌握台运转npm run build,紧缩文件bundle.js将被建立而且放在dist/途径下面。这个文件预备在临盆环境中运用。

这只是刚刚最先

我们适才学到的东西只是Webpack的一些基本。

Webpack是一个很轻易入门的东西,然则要想通晓,须要点时候好好研讨研讨。

参考文档

社群品牌:从零到壹全栈部落
定位:寻觅共好,配合进修,延续输出全栈手艺社群
业界声誉:IT界的逻辑思维
文明:输出是最好的进修体式格局
官方民众号:全栈部落
社群发起人:春哥(从零到壹创始人,交换微信:liyc1215)
手艺交换社区:全栈部落BBS
全栈部落完全系列教程:全栈部落完全电子书进修笔记

关注全栈部落官方民众号,每晚十点吸收系列原创手艺推送
《React 和 ES6 工作流之 Webpack的运用(第六部份)》
    原文作者:愿码社区技术团队
    原文地址: https://segmentfault.com/a/1190000010185534
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞