使用Gulp和Browserify来搭建React应用程序

react

对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 ></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 ></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 ></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应用程序 的全部内容, 来源链接: utcz.com/z/381276.html

回到顶部