對React有必定了解以後,咱們知道,須要把JSX文件轉換成JS文件,組件須要導入導出。本篇就體驗使用Gulp把JSX文件轉換成JS文件,使用Browserify來把組件捆綁到一個文件並理順組件之間的依賴關係。html
Gulp是用來幹嗎的呢?用來把Coffeescript, SASS, JSX等轉換成瀏覽器能理解的JavaScript或CSS,再好比壓縮文件到最小尺寸,再好比把文件捆綁到一個文件以減小請求次數,等等。node
【文件結構】react
node_modules/
gulpfile.js
Typler/
.....src/
..........index.html
..........js/
...............App.js
...............Child.js
...............Parent.jsnpm
【需求】gulp
Development階段:把JSX文件轉換成JS文件,並保存到dist/src文件夾中;把src文件夾中的index.html文件複製到dist文件夾中瀏覽器
Product階段:把全部的JS文件concat, minify, 最終綁定到一個文件build.js,把index.html中全部<script>
,替換成一個<script>
標籤。緩存
【index.html】app
<!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】dom
var child = React.createClass({ render: function(){ return ( <div> and this is the <b>{this.props.name}</b>. </div> ) } });
【Parent.js】ui
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']);
如今執行gulp命令後,Tyler下多了dist文件夾,dist文件夾下多了index.html和src文件夾,src文件夾下有Child.js, Parent.js, App.js.
如今還剩下發布狀態下的一些task,要作的事包括:
咱們在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的好多方面,但這樣的作法還有那些不足呢?
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']);