对React有一定了解之后,我们知道,需要把JSX文件转换成JS文件,组件需要导入导出。本篇就体验使用Gulp把JSX文件转换成JS文件,使用Browserify来把组件捆绑到一个文件并理顺组件之间的依赖关系。

Gulp是用来干嘛的呢?用来把Coffeescript, SASS, JSX等转换成浏览器能理解的JavaScript或CSS,再比如压缩文件到最小尺寸,再比如把文件捆绑到一个文件以减少请求次数,等等。

【文件结构】

node_modules/

gulpfile.js

Typler/

.....src/

..........index.html

..........js/

...............App.js

...............Child.js

...............Parent.js

【需求】

Development阶段:把JSX文件转换成JS文件,并保存到dist/src文件夹中;把src文件夹中的index.html文件复制到dist文件夹中

Product阶段:把所有的JS文件concat, minify, 最终绑定到一个文件build.js,把index.html中所有<script>,替换成一个<script>标签。

【index.html】

<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="app"></div> <script src="../../lib/react.js"></script>
<script src="../../lib/react-dom.js"></script>
<script src="../src/js/Child.js"></script>
<script src="../src/js/Parent.js"></script>
<script src="../src/js//App.js"></script>
</body>
</html>

【Child.js】

var child = React.createClass({
render: function(){
return (
<div>
and this is the <b>{this.props.name}</b>.
</div>
)
}
});

**
【Parent.js】**

var Parent = React.createClass({
render: function(){
return (
<div>
<div>This is the parent.</div>
<child name="child" />
</div>
)
}
});

【App.js】

ReactDOM.render(<Parent />, document.getElementById('app'));

【下载NPM Packages】

npm install --save-dev gulp
npm install --save-dev gulp-concat
npm install --save-dev gulp-uglify
npm install --save-dev gulp-react
npm install --save-dev gulp-html-replace

【gulpfile.js】

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var react = require('gulp-react');
var htmlreplace = require('gulp-html-replace'); var path = {
HTML: 'Tyler/src/index.html',
ALL:['Tyler/src/js/*.js', 'Tyler/src/js/**/*.js','Tyler/src/index.html'],
JS: ['Tyler/src/js/*.js', 'Tyler/src/js/**/*.js'],
MINIFIED_OUT: 'build.min.js',
DEST_SRC: 'Tyler/dist/src', //把从jsx文件转换而来的文件放这里
DEST_BUILD: 'Tyler/dist/build',
DEST: 'Tyler/dist'
}; //获取js的源文件,把jsx转换成js,放到目标文件夹
gulp.task('transform', function(){
gulp.src(path.JS)
.pipe(react())
.pipe(gulp.dest(path.DEST_SRC))
}) //把Tyler/src/index.html这个文件复制放到Tyler/dist中
gulp.task('copy', function(){
gulp.src(path.HTML)
.pipe(gulp.dest(path.DEST));
}); //观察index.html和js文件的变化,执行以上的2个任务
gulp.task('watch', function(){
gulp.watch(path.ALL, ['transform', 'copy']);
}); //名称为default的task,需要
gulp.task('default',['watch','transform', 'copy']);
  • transform这个task用来把jsx转换成js
  • copy这个task用来把Tyler/src/index.html复制拷贝到Tyler/dist/index.html
  • watch这个task用来观察js和html文件的变化,一旦有变化就执行transform和copy这个task
  • default是默认的task,一定需要,执行所有的task

现在执行gulp命令后,Tyler下多了dist文件夹,dist文件夹下多了index.html和src文件夹,src文件夹下有Child.js, Parent.js, App.js.

现在还剩下发布状态下的一些task,要做的事包括:

  • 先获取到所有的js文件
  • 把所有的js文件拼接起来
  • 最小化js文件
  • 把输出文件放到dist/build文件夹中

我们在gulp.js文件中增加如下:

//发布到生产环境的task
gulp.task('build', function () {
gulp.src(path.JS)
.pipe(react())
.pipe(concat(path.MINIFIED_OUT)) //合并到build.min.js文件中
.pipe(uglify(path.MINIFIED_OUT)) //压缩build.min.js文件中
.pipe(gulp.dest(path.DEST_BUILD));//把build.min.js文件放到Tyler/dist/build文件夹中
});

运行"gulp build"命令,这样,在Tyler/dist/build下多了一个合并压缩后的build.min.js文件。

但这里还有一个问题:Tyler/dist/index.html中依然引用的是src/js中的文件

    <script src="../src/js/Child.js"></script>
<script src="../src/js/Parent.js"></script>
<script src="../src/js//App.js"></script>

而我们需要引用的是如下这个文件:

<script src="build/build.min.js"></script>

gulp-html-replace就是为解决这个问题而存在。需要两步。

第一步:来到Tyler/src/index.html文件中,添加<!--build:js--><!--endbuild-->指令。

<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="app"></div> <script src="../../lib/react.js"></script>
<script src="../../lib/react-dom.js"></script>
<!-- build:js -->
<script src="../src/js/Child.js"></script>
<script src="../src/js/Parent.js"></script>
<script src="../src/js//App.js"></script>
<!-- endbuild -->
</body>
</html>

第二步:添加task

//在Tyler/dist/index.html中引用的js文件和Tyler/src/index.html中不一样,需要替换
gulp.task('replaceHTML', function(){
gulp.src(path.HTML)
.pipe(htmlreplace({
'js': 'build/' + path.MINIFIED_OUT
}))
.pipe(gulp.dest(path.DEST));
}); //把发布到生产环境之前的所有任务再提炼
gulp.task('production', ['replaceHTML', 'build']);

运行:gulp production

再次来到Tyler/dist/index.html中,惊喜地发现如下:

<!DOCTYPE html>
<html>
<head></head>
<body>
<div id="app"></div> <script src="../../lib/react.js"></script>
<script src="../../lib/react-dom.js"></script>
<script src="build/build.min.js"></script> </body>
</html>

使用gulp-html-replace生效了!

最后,把完整的gulpfile.js呈现如下:

//Tyler

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var react = require('gulp-react');
var htmlreplace = require('gulp-html-replace'); var path = {
HTML: 'Tyler/src/index.html'
, ALL: ['Tyler/src/js/*.js', 'Tyler/src/js/**/*.js', 'Tyler/src/index.html']
, JS: ['Tyler/src/js/*.js', 'Tyler/src/js/**/*.js']
, MINIFIED_OUT: 'build.min.js'
, DEST_SRC: 'Tyler/dist/src', //把从jsx文件转换而来的文件放这里
DEST_BUILD: 'Tyler/dist/build'
, DEST: 'Tyler/dist'
}; //获取js的源文件,把jsx转换成js,放到目标文件夹
gulp.task('transform', function () {
gulp.src(path.JS)
.pipe(react())
.pipe(gulp.dest(path.DEST_SRC))
}) //把Tyler/src/index.html这个文件复制放到Tyler/dist中
gulp.task('copy', function () {
gulp.src(path.HTML)
.pipe(gulp.dest(path.DEST));
}); //观察index.html和js文件的变化,执行以上的2个任务
gulp.task('watch', function () {
gulp.watch(path.ALL, ['transform', 'copy']);
}); //名称为default的task,需要
gulp.task('default', ['watch', 'transform', 'copy']); //发布到生产环境的task
gulp.task('build', function () {
gulp.src(path.JS)
.pipe(react())
.pipe(concat(path.MINIFIED_OUT)) //合并到build.min.js文件中
.pipe(uglify(path.MINIFIED_OUT)) //压缩build.min.js文件中
.pipe(gulp.dest(path.DEST_BUILD));//把build.min.js文件放到Tyler/dist/build文件夹中
}); //在Tyler/dist/index.html中引用的js文件和Tyler/src/index.html中不一样,需要替换
gulp.task('replaceHTML', function(){
gulp.src(path.HTML)
.pipe(htmlreplace({
'js': 'build/' + path.MINIFIED_OUT
}))
.pipe(gulp.dest(path.DEST));
}); //把发布到生产环境之前的所有任务再提炼
gulp.task('production', ['replaceHTML', 'build']);

以上,我们了解了有关gulp的好多方面,但这样的做法还有那些不足呢?

  • 需要手写各个组件的js文件位置
  • Parent.js依赖Child.js,需要手动让Child.js先与Parent.js加载
  • App.js依赖Parent.js,需要手动让Parent.js先与App.js先加载
  • 很难调试,很难知道jsx哪里出了问题

Browserify就是为了解决以上问题而存在的。

【Browserify+Gulp+React(Developement Tasks)】

安装NPM Packages

npm install --save-dev vinyl-source-stream
npm install --save-dev browserify
npm install --save-dev watchify
npm install --save-dev reactify
npm install --save-dev gulp-streamify

gulpfule.js

//Tyler using browserify

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var htmlreplace = require('gulp-html-replace');;
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var reactify = require('reactify');
var streamify = require('gulp-streamify'); var path = {
HTML: 'Tyler/src/index.html'
, MINIFIED_OUT: 'build.min.js'
, OUT: 'build.js'
, DEST: 'Tyler/dist1'
, DEST_BUILD: 'Tyler/dist1/build'
, DEST_SRC: 'Tyler/dist1/src'
, ENTRY_POINT: 'Tyler/src/js/App.js'
}; //Tyler/src/index.html中复制到TylerTyler/dist中
gulp.task('copy', function () {
gulp.src(path.HTML)
.pipe(gulp.dest(path.DEST));
}); //监测
gulp.task('watch', function () { //监测html文件
gulp.watch(path.HTML, ['copy']); //watchify配合browserify使用,因为单独使用browserify会每次遍历每个组件,一旦有变化就会重新生成绑定文件。而有了watchify,会缓存文件,只更新哪些发生改变的文件
var watcher = watchify(browserify({
entries: [path.ENTRY_POINT],//Tyler/src/js/App.js, browserify会检测Tyler/src/js下的所有js文件,以及Tyler/src/js下所有子文件夹下的js文件
transform: [reactify],//使用reactify把jsx转换成js文件
debug: true,//告诉Browersify使用source maps, souce maps帮助我们在出现错误的时候定位到jsx中的错误行
cache: {},//必须的,browserify告诉我们这样使用
packageCache: {},//必须的,browserify告诉我们这样使用
fullPath: true//必须的,browserify告诉我们这样使用
})); return watcher.on('update', function(){
watcher.bundle()//把所有的jsx文件绑定到一个文件
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC)); console.log('Updated');
})
.bundle()
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC));
}); //默认的task
gulp.task('default', ['watch']);

运行gulp命令,在Tyler文件夹下多了dist1文件夹。

【Browserify + Gulp + React(Production Tasks)】

在发布到生产环境之前,需要添加如下task

//发布到生产环境之前
gulp.task('build', function () {
browserify({
entries: [path.ENTRY_POINT]
, transform: [reactify]
})
.bundle()
.pipe(source(path.MINIFIED_OUT))
.pipe(streamify(uglify(path.MINIFIED_OUT)))
.pipe(gulp.dest(path.DEST_BUILD));
}); gulp.task('replaceHTML', function () {
gulp.src(path.HTML)
.pipe(htmlreplace({
'js': 'build/' + path.MINIFIED_OUT
}))
.pipe(gulp.dest(path.DEST));
}); gulp.task('production', ['replaceHTML', 'build']);

使用Browserify完整版如下:

//Tyler using browserify

var gulp = require('gulp');
var uglify = require('gulp-uglify');
var htmlreplace = require('gulp-html-replace');;
var source = require('vinyl-source-stream');
var browserify = require('browserify');
var watchify = require('watchify');
var reactify = require('reactify');
var streamify = require('gulp-streamify'); var path = {
HTML: 'Tyler/src/index.html'
, MINIFIED_OUT: 'build.min.js'
, OUT: 'build.js'
, DEST: 'Tyler/dist1'
, DEST_BUILD: 'Tyler/dist1/build'
, DEST_SRC: 'Tyler/dist1/src'
, ENTRY_POINT: 'Tyler/src/js/App.js'
}; //Tyler/src/index.html中复制到TylerTyler/dist中
gulp.task('copy', function () {
gulp.src(path.HTML)
.pipe(gulp.dest(path.DEST));
}); //监测
gulp.task('watch', function () { //监测html文件
gulp.watch(path.HTML, ['copy']); //watchify配合browserify使用,因为单独使用browserify会每次遍历每个组件,一旦有变化就会重新生成绑定文件。而有了watchify,会缓存文件,只更新哪些发生改变的文件
var watcher = watchify(browserify({
entries: [path.ENTRY_POINT], //Tyler/src/js/App.js, browserify会检测Tyler/src/js下的所有js文件,以及Tyler/src/js下所有子文件夹下的js文件
transform: [reactify], //使用reactify把jsx转换成js文件
debug: true, //告诉Browersify使用source maps, souce maps帮助我们在出现错误的时候定位到jsx中的错误行
cache: {}, //必须的,browserify告诉我们这样使用
packageCache: {}, //必须的,browserify告诉我们这样使用
fullPath: true //必须的,browserify告诉我们这样使用
})); return watcher.on('update', function () {
watcher.bundle() //把所有的jsx文件绑定到一个文件
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC)); console.log('Updated');
})
.bundle()
.pipe(source(path.OUT))
.pipe(gulp.dest(path.DEST_SRC)); }); //默认的task
gulp.task('default', ['watch']); //发布到生产环境之前
gulp.task('build', function () {
browserify({
entries: [path.ENTRY_POINT]
, transform: [reactify]
})
.bundle()
.pipe(source(path.MINIFIED_OUT))
.pipe(streamify(uglify(path.MINIFIED_OUT)))
.pipe(gulp.dest(path.DEST_BUILD));
}); gulp.task('replaceHTML', function () {
gulp.src(path.HTML)
.pipe(htmlreplace({
'js': 'build/' + path.MINIFIED_OUT
}))
.pipe(gulp.dest(path.DEST));
}); gulp.task('production', ['replaceHTML', 'build']);

使用Gulp和Browserify来搭建React应用程序的更多相关文章

  1. 使用Webpack和Babel来搭建React应用程序

    用Webpack(npm install -g webpack)代码打包,Webpack大致需要知道三件事: 1)让Webpack知道应用程序或js文件的根目录 2)让Webpack知道做何种转换 3 ...

  2. React gulp、Browserify、Webpack实例

    一.gulp var gulp = require('gulp'); var react = require('gulp-react'); gulp.task('jsx', function() { ...

  3. [转载]Sublime Text 3 搭建 React.js 开发环境

    [转载]Sublime Text 3 搭建 React.js 开发环境 Sublime有很强的自定义功能,插件库很庞大,针对新语言插件更新很快,配合使用可以快速搭建适配语言的开发环境. 1. babe ...

  4. sublime text3搭建react native

    Sublime Text 3 搭建React.js开发环境 Sublime有很强的自定义功能,插件库很庞大,针对新语言插件更新很快,配合使用可以快速搭建适配语言的开发环境. 1. babel-subl ...

  5. 前端构建工具的用法—grunt、gulp、browserify、webpack

    随着前端项目的飞速发展,项目越来越大.文件越来越多,前端工程化的工具也越来越多.下面介绍目前最流行的四种构建工具——grunt.gulp.browserify.webpack 所有的构建工具都是基于N ...

  6. 1、在MAC上搭建React Native开发环境

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  7. react-native —— 在Windows下搭建React Native Android开发环境

    在Windows下搭建React Native Android开发环境 前段时间在开发者头条收藏了 @天地之灵_邓鋆 分享的<在Windows下搭建React Native Android开发环 ...

  8. 手把手教你在Windows下搭建React Native Android开发环境

    最近看到React Native好像好厉害的样子,好奇心驱使之下体验了一下并将在Window下搭建React Natvie Android环境的步骤记录下来,并有需要的朋友参考.(我都是参考官方文档的 ...

  9. 使用Gulp和Browserify创建多个绑定文件

    Browserify是一个Javascript的绑定工具,帮助我们理顺module之间的依赖关系.Gulp用来优化workflow.两者的共同点都是使用流,但在使用流方面也有不同之处: Browser ...

随机推荐

  1. Ubuntu遇到Please ensure that adb is correctly located at '...adb.exe' and can be executed 问题解决方法

    上次我们在SDK更新的到最新的Android L版本之后,我发现我的ADT和android指定的版本不对应,我的ADT是22版本的,android L需要23版本以上的,版本不对应的话就无法加载这个S ...

  2. oracle 多级菜单查询 。start with connect by prior

    select * from S_dept where CODE in(select sd.code from s_dept sd start with sd.code='GDKB' connect b ...

  3. 20145225《Java程序设计》 第10周学习总结

    20145225<Java程序设计> 第10周学习总结 教材学习内容总结 一.网络编程 网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据: 程序员所作的事情就是把数据发送到指定 ...

  4. shell脚本学习

    1.注释 如果使用bash,则在脚本文件头注释:#/bin/bash2.将脚本文件加上可读与执行权限,就可以使用./shell.sh来执行,也可以使用sh shell.sh的方式来直接执行,sh是ba ...

  5. [VBS]带参数删除扩展名不是*.h、*.c、*.cpp的全部文件

    脚本使用例程CleanFolder遍历一个文件夹 1)使用CleanFolder递归遍历该文件夹下的所有子文件夹 2)如果该子文件夹的大小为0,则删除这个文件夹 3)遍历该文件夹下的所有文件,扩展名不 ...

  6. Lucene.Net+盘古分词器(详细介绍)(转)

    出处:http://www.cnblogs.com/magicchaiy/archive/2013/06/07/LuceneNet%E7%9B%98%E5%8F%A4%E5%88%86%E8%AF%8 ...

  7. Windows 8.1 应用再出发 - 几种布局控件

    本篇为大家介绍Windows 商店应用中几种布局控件的用法.分别是Canvas.Grid.StackPanel 和 VariableSizedWrapGrid. 1. Canvas Canvas使用绝 ...

  8. openSUSE 13.1 Milestone 4 发布

    openSUSE 13.1 发布第四个里程碑版本,下载地址: openSUSE-Factory-KDE-Live-Build0652-x86_64.iso (949MB, MD5, torrent) ...

  9. 统计《ASP.Net特供视频教程》总长度

    忽然想统计一下我录制过的视频一共多长时间,由于视频文件很多,一共72个,挨个打开进行累加不是程序员应该想起的办法.所以就打算写一个程序来完成这件事,最核心的问题就是“获得一个视频文件的时长”. ffm ...

  10. 大话JS面向对象之扩展篇 面向对象与面向过程之间的博弈论(OO Vs 过程)------(一个简单的实例引发的沉思)

    一,总体概要 1,笔者浅谈 我是从学习Java编程开始接触OOP(面向对象编程),刚开始使用Java编写程序的时候感觉很别扭(面向对象式编程因为引入了类.对象.实例等概念,非常贴合人类对于世间万物的认 ...