前端模块化开发学习之gulp&browserify篇

   随着web应用的发展,前端的比重占得越来越多,编写代码从而也越来越复杂。而通常我们需要将不同功能或者不同模块的代码分开写,最后在html中一起加载,这样做是可以的,但是当你需要进行维护或者是二次开发的时候,你会觉得十分费劲,因为你不知道文件之间复杂的关系,所以我们需要利用一些插件来配合进行模块化的开发。

  所谓模块化的开发,写过nodejs的人都知道,文件之间的依赖可以用require()实现,但是浏览器端是不支持这样的依赖形式的,而browserify却可以解决这个问题,再加上gulp这个强大的构建工具,使得前端的模块化开发变得简单了。

   接下来就利用gulp和browserify两个工具,将ReactJs编写的一个小Demo进行展示:

    一.如何用React编写Demo

    二.Gulp入门及操作

    三.Browserify入门及操作

    四.演示Demo

   先来看下我们最终的目录结构,以便读者的后续操作:

  

   一.如何用React编写Demo

   React是Facebook于2013年开源的一套框架,它从刚开始的UI框架逐渐演变成了新的Web解决方案。它的主要特点有三个:

    ---Just the UI

    ---Virtual DOM

    ---data flow

  一个语言的框架,重要的不是记住它的接口,而是要掌握它的思想,要理解并掌握React,需要从这三个特性入手。

   Just the UI

    没错,React在UI上有非常有优势的地方,这个优势主要来源于React可以将一个网页,甚至是一个项目工程的静态页面切割成不同的块,也就是组件。

    组件化的开发可以避免模板(如ejs)开发复杂的逻辑,同时它不影响其他框架库类合并使用,更有利于团队开发。可见React使开发有了更便捷,使维护更简单。 

  Virtual DOM

    熟悉前端的人都知道,传统的DOM渲染及操作是很耗时的,特别是在DOM操作比较频繁的情况下,DOM是性能出现瓶颈的主要因素。

    而React采用虚拟DOM,利用diff算法来进行DOM管理,这里的虚拟DOM其实是保存在内存中,所以速度是非常快的。而且虚拟DOM可以在服务器端渲染,在性能方面这是很有创新的。可见React使网站性能更好。

  data flow

    React中的数据流与Angular是不同的,或许你认为Angular的双向数据流对于数据交互非常轻松,但是React基于属性Props和状态State的单向数据流会给你带来条理非常清晰的逻辑,当然你还可以引入其他框架或者库类来进行与后台的数据交换,这一切的数据都是由组件(React中组件就是一个个状态机)的属性和状态决定。可见React使任务逻辑更清晰。

  React是很创新的,对现代工业化前端的开发,维护以及使用的性能都是非常好的提升。还有关于React一些细节就不在这里细说了。  

  

  接下来我们开始编写我们的React Demo。这是一个类似问卷的一个小Demo,包含了3个判断题的组件的一个页面,我们最后需要将用户填写的结果上传到服务器,例子很简单,大家主要要体验下这个开发过程。

  首先在创建一个工程项目:

    1.创建一个项目文件夹,并且在sublime text中打开

    2.使用cmd进入这个文件夹,然后npm init创建package.json文件,这个文件展示工程的相关信息,包括插件的信息。(前提是要先安装npm)

    

    3.编写子组件Child.jsx(判断题组件),从现在开始我们直接采用模块化的语法来编写JSX文件,写过Node的小伙伴会觉得很熟悉,它其实和服务器端的CommonJs规范是差不多的。有关React的语法可以通过React的官方文档进行了解。

    facebook.github.io/react/index.html      >>Learn React Now !

 1 var React = require("react/addons");
 2 
 3 // 判断题可以看作对和错只能选一个的题目,因此是一个单选框
 4 var Child = React.createClass({
 5     // 状态对象包含判断题的当前选项的值
 6     // @param : value
 7     // @key : true,false
 8     getInitialState : function(){
 9         return{
10             value : "true"
11         };
12     },
13     handleChange : function(event){
14         //通过事件委托连接子组件和父组件,将子组件中的value状态传入到父组件中
15         if(this.props.onChange){
16             this.props.onChange(event);
17         }
18         //更改子组件的状态,重新渲染UI上。
19         this.setState({
20             value : event.target.value
21         });
22     },
23     render : function(){
24         return(
25             <div>
26                 <label>{this.props.label}</label>
27                 <input type="radio" name={this.props.name} checked={this.state.value == "true"} value="true" onChange={this.handleChange} />
28                 "true"
29                 <input type="radio" name={this.props.name} checked={this.state.value == "false"} value="false" onChange={this.handleChange} />
30                 "false"
31             </div>
32         )
33     }
34 });
35 
36 module.exports = Child;
View Code  

    4.编写父组件Parent.jsx(提交组件)。

 1 var React = require("react/addons");
 2 var Child = require("./Child.jsx");
 3 
 4 var Parent = React.createClass({
 5     getInitialState : function(){
 6         return{
 7             //题目编号
 8             name : ["judge-1","judge-2","judge-3"],
 9             //题目名称
10             label : ["do you think yxy is handsome?",
11                 "do you like this boke?",
12                 "do you want to know React?"
13             ],
14             //用户默认选项
15             value1 : "true",
16             value2 : "true",
17             value3 : "true"
18         }
19     },
20     handleChange : function(value,event){
21         var newState = {};
22         //通过子组件传过来的value改变当前父组件的value
23         newState[value] = event.target.value;
24         //设置新状态
25         this.setState(newState);
26     },
27     handleSubmit : function(event){
28         //取消提交默认事件
29         event.preventDefault();
30         //打印父组件存放的数据
31         console.log(this.state);
32     },
33     render : function(){
34         var renderChilds = [];
35         renderChilds = this.state.name.map(function(value,index){
36             return(
37                 <Child name={this.state.name[index]} label={this.state.label[index]} onChange={this.handleChange.bind(this,"value"+(index+1))}></Child>
38             );
39         }.bind(this));
40         return(
41             <form onSubmit={this.handleSubmit}>
42                 {renderChilds}
43                 <button type="submit">提交</button>
44             </form>
45         );
46     }
47 });
48 
49 module.exports = Parent;
View Code

    5.最后的出口文件app.jsx。

1 var React = require("react/addons");
2 var Parent = require("./Parent.jsx");
3 
4 React.render(<Parent></Parent>,document.body);
5 Perf = React.addons.Perf;
View Code

    6.目前为止我们工程的目录如下:

    

    React编写告一段落。

  二.Gulp入门及操作

  什么是Gulp

  Gulp是一个基于流的自动化构建工具,需要注意两点,一为自动化,二为流。

  在Gulp之前又一款名为Grunt的工具拉开了前端自动化的帷幕。所谓自动化,就是自动帮你完成一些工程中需要我们去手动完成的一些重复繁琐的操作,简单的比如预处理,压缩,合并文件等等。而"流",代表着Gulp通过IO流的通道高效地进行自动化任务,前面提到的Grunt是与之相反,它没进行一次任务都会打开一次IO通道,任务耗时自然没有Gulp好。

  了解Grunt ->  官网 : http://gruntjs.com/          中文官网 : http://www.gruntjs.net/        

  了解Gulp ->  官网 :  http://gulpjs.com/          中文官网 : http://www.gulpjs.com.cn/

  

  安装Gulp

  安装及项目使用过程在官网都有介绍,这里再简单说一下。

  1.全局安装Gulp

npm install -g gulp

  2.作为项目的开发依赖安装

npm install  gulp --save-dev

  

  如何使用Gulp管理文件

  1.创建gulpfile.js文件于项目根目录,在其中编写我们的任务代码。

var gulp = require('gulp');

gulp.task('default', function() {
  // 将你的默认的任务代码放在这
});

  2.在gitBash或者其他窗口命令中执行任务

gulp

  关于Gulp

  Gulp的学习非常简单,反复练习几次你就会发现Gulp的方便之处~

  三.Browserify入门及操作

  上一点中,我们知道了gulp是一款非常强大的自动化构建工具,然而我们最开始也提到了浏览器中是不能直接解析类似require()这样的语法的。所以我们需要Browserify这个强大的工具。

  什么是Browserify

  Browserify 可以让你使用类似于 node 的 require() 的方式来组织浏览器端的 Javascript 代码,通过预编译让前端 Javascript 可以直接使用 Node NPM 安装的一些库。

  了解Browserify ->  官网 : http://browserify.org/

  

  安装Browserify

  安装Browserify和安装Gulp是一样的简单。

  1.全局安装Browserify

npm install -g browserify

  2.作为项目的开发依赖安装

npm install browserify --save-dev

  

  如何使用Browserify

   1.利用Browserify解决require()依赖问题,将app.js中所有依赖项加载并整合到goal.js中。html只要加载goal.js即可。

browserify app.js > goal.js

  

  关于Browserify

  Browserify解决了js在浏览器端的依赖问题,但是还有一个更为强大的工具名曰webpack!它可以将js,css,png等很多文件的依赖问题解决,而Browserify只能解决js。但已经足够强大,有关webpack的内容我和大家都还需要慢慢去了解。

  四.演示Demo

  终于到了激动人心的时候,现在我会结合前面两个工具来进行前端模块化开发的模拟。

  1.包含所有依赖到node_modules文件中,package.json中会出现对应依赖项。

    1.1 React框架.

    npm install react --save-dev

    安装React是为了使我们编写的React组件能够顺利使用。

    

    1.2 Gulp工具.

    npm install gulp --save-dev

    安装Gulp方便自动化构建我们的文件

    1.3 Browserify工具

    npm install browserify --save-dev

    安装Browserify解决js依赖问题。

    *1.4 reactify工具

    npm install reactify --save-dev

    将jsx编译为js,类似与JSXTransform.js。

    *1.5 react-tools工具

    npm install react-tools --save-dev

      

    *1.6 vinyl-source-stream工具

    npm install vinyl-source-stream --save-dev

    这个要着重说一下,使用gulp时,你可能会陷入“流不兼容”的问题。这主要是因为常规流和Vinyl文件对象有差异,或是使用了仅支持buffer(不支持流)库的gulp插件与常规流不兼容。

    如果我们需要将gulp和(或)gulp插件与常规的可读流一起使用,我们就需要先把可读流转换为vinyl。

    如果实在不能理解,可以取百度Google更多资料,推荐看看这篇文章 : http://segmentfault.com/a/1190000000711469

     

  2.编写gulpfile.js文件

    在编写之前要明确我们的目的 ->将所有的jsx及jsx所依赖的js文件合并到一个新的js文件中

    因此gulpfile.js文件如下 : 

 1 var gulp = require("gulp");
 2 var browserify = require("browserify");
 3 var source = require("vinyl-source-stream");
 4 var reactify = require("reactify");
 5 
 6 
 7 //gulp主动设置的命令
 8 gulp.task("combine",function(){
 9     //通过browserify管理依赖
10     browserify({
11         //入口点,app.jsx
12         entries : ["./app.jsx"],
13         //利用reactify工具将jsx转换为js
14         transform : [reactify]
15     })
16         //转换为gulp能识别的流
17         .bundle()
18         //合并输出为app.js
19         .pipe(source("app.js"))
20         //输出到当前文件夹中
21         .pipe(gulp.dest("./"));
22 });
23 
24 
25 //gulp默认命令
26 gulp.task("default",["combine"]);
View Code

  

  3.执行gulp命令

  

  

  4.查看我们的目录结构

  

  5.打开index.html

  

  6.执行4次提交操作,观察数据是否正确显示

  

  

  7.可以看到value1,value2,value3的值随我们的不同提交而改变。

  

  总结:

  前端如今已经步入工业化的时代,结合多样的工具可以让我们更高效地进行开发,当然现在的前端工具仍处于不稳定的阶段,但我们也需要不断的摸索,从grunt到gulp,再到当下最火的webpack,前端多样化的工具的更新迭代从未停下脚步,因此我们更不应该停止学习的脚步。

  同样的,gulp+browserify的开发模式可能会随着前端的浪潮逐渐被埋没,但它的思想是永恒的,我们要做的便是抛下浮躁,去探索更好的开发模式。

原文地址:https://www.cnblogs.com/yxy99/p/5068121.html