/ nodejs

ES6 + Express + Babel + Gulp + React + Webpack

自己动手才发现原来写篇好文章真的是太难了,如果评个等级的话,这篇文章大概是渣渣水平,哈哈。
不过,总算是写完了,也算是最近学习的一个总结吧 :)

本文目录

  • 准备工作
  • 项目目录结构
  • Express
    • 安装
    • 写个server测试一下
  • Babel
    • 安装
    • 配置.babelrc
    • 使用es6语法编写代码
    • 使用bebel转换
  • Gulp
    • 安装
    • 编写gulpfile
      • 一个简单的gulpfile
      • 能够监听文件更改的gulpfile
  • React + Webpack
    • 安装
    • webpack.config.js
    • 在gulp中使用webpack
    • 使用React
  • 总结

准备工作

作为一个noder,开始一切之前当然少不了npm init
关于express, babel, gulp, webpack, react本文不进行介绍,如有需要可以到其主页自行了解。
Express
Babel
Gulp
React
Webpack

项目目录结构

app
├─ lib/
├─ public/
│  ├─ dist/
│  └─ src/
│      └─ index.js
├─ src/
│  └─ app.js
├─ .babelrc
├─ index.html
├─ gulpfile.babel.js
├─ package.json
├─ README.md
└─ webpack.config.js

Express

安装

这次准备纯手写,所以不用express-generator生成了,简单的示例尽量不使用多余的中间件。
npm install --save express body-parser

写个server测试一下

// src/app.js

var express = require('express');
var bodyParser = require('body-parser');

var app = express();
var router = express.Router();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());

router.get('/', function(req, res, next) {
  res.end('Hello World!');
});

app.use('/', router);

app.listen(3000, function() {
  console.log('server listening at port 3000...');
});

简单起见,404和error handler就不写了。
node src/app.js跑起来,浏览器打开http://localhost:3000,可以看到页面中显示Hello World!了。

Babel

babel升级到6.x之后,需要明确指定转换,我们使用预设的es2015。

安装

npm install -g babel-core
npm install --save-dev babel-core babel-preset-es2015

配置.babelrc

在根目录新建.babelrc文件,配置如下:

{
  "presets": ["es2015"]
}

使用es6语法编写代码

我们现在将之前写过的src/app.js修改为es6语法

// src/app.js

import express, { Router } from 'express';
import bodyParser from 'body-parser';

let app = express();
let router = Router();

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cookieParser());

router.get('/', (req, res, next) => {
  res.end('Hello World!');
});
app.use('/', router);

app.listen(3000, () => {
  console.log('server listening at port 3000...');
});

使用bebel转换

将代码修改为es6语法之后,就可以使用babel进行转换了。
使用命令babel src -d lib
可以看到控制台中显示:

src/app.js -> lib/app.js

之后还是运行一下看看效果,浏览器打开http://localhost:3000,我们和熟悉的Hello World又见面啦。

Gulp

每次修改完代码都要重新用babel转换一次是不是很麻烦?别怕,我们有gulp。

安装

npm install -g gulp-cli
npm install --save-dev gulp gulp-babel

编写gulpfile

在根目录新建一个gulpfile.babel.js文件。
gulp原生并不支持es6语法,但是我们可以告诉gulp使用babel将gulpfile转换为es5,方法就是将gulpfile命名为gulpfile.babel.js

一个简单的gulpfile

我们先写一个简单的gulpfile测试一下gulp是否能够正常工作。

import gulp from 'gulp';
import babel from 'gulp-babel';

gulp.task('default', () => {
  return gulp.src('src/**/*.js')
    .pipe(babel())
    .pipe(gulp.dest('lib'));
});

控制台执行gulp,可以看到:

[13:00:35] Requiring external module babel-register
[13:00:36] Using gulpfile /path/to/file/gulpfile.babel.js
[13:00:36] Starting 'default'...
[13:00:36] Finished 'default' after 191 ms

然后lib文件夹下就生成了转换后的文件了。

能够监听文件更改的gulpfile

虽然上面的gulpfile能够将使用了,但是还是跟之前直接用babel一样,每次都要gulp一下,下面我们就来写一个能够监听文件的gulpfile。当文件被修改之后,自动将文件转换。
这里使用gulp-watch监听文件更改。
npm install --save-dev gulp-watch

import gulp from 'gulp';
import watch from 'gulp-watch';
import babel from 'gulp-babel';

gulp.task('transform', () => {
  return gulp.src('src/**/*.js')
    .pipe(babel())
    .pipe(gulp.dest('lib'));
});

gulp.task('watch', () => {
  return gulp.src('src/**/*.js')
    .pipe(watch('src/**/*.js', {
      verbose: true
    }))
    .pipe(babel())
    .pipe(gulp.dest('lib'));
});

gulp.task('default', () => {
  gulp.start('transform');
});

控制台执行gulp watch

[14:11:46] Requiring external module babel-register
[14:11:47] Using gulpfile /file/to/path/gulpfile.babel.js
[14:11:47] Starting 'watch'...

然后修改app.js并保存,可以看到控制台中多了一行信息

[14:13:20] app.js was changed

对于gulp其他的用法这里就不细说了,有兴趣的可以去看桑大i5tingGulp实战和原理解析(以weui作为项目实例)

React + Webpack

安装

react
npm install --save react react-dom
webpack
npm install --save-dev webpack webpack-dev-server
为了编译jsx,我们还需要其他一些模块
npm install --save-dev babel-loader babel-preset-react

webpack.config.js

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

module.exports = {
  devtool: 'eval',
  entry: {
    public: './public/src/index'
  },
  output: {
    path: path.join(__dirname, 'public/dist'),
    filename: 'bundle.js',
    publicPath: 'public/dist'
  },
  plugins: [],
  module: {
    loaders: [
      {
        test: /\.js$/,
        include: [path.join(__dirname, 'public/src')],
        loader: 'babel',
        query: {
          presets: ['react', 'es2015']
        }
      }
    ]
  }
};

在gulp中使用webpack

修改gulpfile.babel.js,添加buildwebpack-dev-server任务,分别是生成打包文件和启动开发服务器,并将default修改为同时执行transformwebpack-dev-server

import gulp from 'gulp';
import gutil from 'gulp-util';
import watch from 'gulp-watch';
import babel from 'gulp-babel';
import webpack from 'webpack';
import WebpackDevServer from 'webpack-dev-server';

import webpackConfig from './webpack.config.js';

// transform
gulp.task('transform', () => {
  return gulp.src('src/**/*.js')
    .pipe(babel())
    .pipe(gulp.dest('lib'));
});

// watch transform
gulp.task('watch-transform', () => {
  return gulp.src('src/**/*.js')
    .pipe(watch('src/**/*.js', {
      verbose: true
    }))
    .pipe(babel())
    .pipe(gulp.dest('lib'));
});

gulp.task('webpack:build', (callback) => {
  // modify some webpack config options
  var myConfig = Object.create(webpackConfig);
  myConfig.plugins = myConfig.plugins.concat(
    new webpack.DefinePlugin({
      'process.env': {
        // This has effect on the react lib size
        'NODE_ENV': JSON.stringify('production')
      }
    }),
    new webpack.optimize.DedupePlugin(),
    new webpack.optimize.UglifyJsPlugin()
  );

  // run webpack
  webpack(myConfig, (err, stats) => {
    if (err)
      throw new gutil.PluginError('webpack:build', err);
    gutil.log('[webpack:build]', stats.toString({
      colors: true
    }));
    callback();
  });
});

gulp.task('webpack-dev-server', (callback) => {
  // modify some webpack config options
  var myConfig = Object.create(webpackConfig);
  myConfig.devtool = 'eval';
  myConfig.debug = true;

  // Start a webpack-dev-server
  new WebpackDevServer(webpack(myConfig), {
    publicPath: '/' + myConfig.output.publicPath,
    stats: {
      colors: true
    }
  }).listen(3001, 'localhost', (err) => {
    if (err) throw new gutil.PluginError('webpack-dev-server', err);
    gutil.log('[webpack-dev-server]', 'http://localhost:3001/');
  });
});

gulp.task('default', ['watch-transform', 'webpack-dev-server']);

使用React

在根目录下创建index.html文件

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello Wrold</title>
  </head>
  <body>
    <div id="root"></div>
    <script src="http://127.0.0.1:3001/public/dist/bundle.js"></script>
  </body>
</html>

之后在public/src目录创建index.js文件,简单的写个hello world.

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

class App extends Component {
  render() {
    return (
      <h1>Hello Wrold!!</h1>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

控制台执行gulp webpack-dev-server,打开http://localhost:3001
我们和Hello world!第三次见面了~

总结

到这里文章就结束了,然而这只是文章的结束,现在只是把大体的结构搭建起来了,剩下要做的还有很多,继续加油把~
PS: 我也不知道这种目录结构是否合理,如有不同意见,欢迎拍砖~