02月12, 2017

前端模块化规范

前端模块化规范

看看现在三分天下的流行框架:React、Angular2、Vue,他们的最大的共同点就是:模块化、组件化;还有由Nodejs衍生而来的各种前端构建工具:Webpack、Gulp、Systemjs,使用它们的基础也是模块化、组件化。

至于模块化的好处,网上各种论调就不多说了,除此之外,更重要的是:在模块化的基础上形成一种团队成员间的默契化规范,形成团队内的私有仓库,统一管理,达到像后端调用package一样自然而然的调用前端模块的目的;

一切源自CommonJS:

不要怕这又是个什么框架要去花时间学习,CommonJS是JS的模块化规范,由于JS的历史原因,起初并没有模块化之说,之后JS成为了浏览器端的事实标准,地位越来越重要,CommonJS规范就是为了解决这个问题而提出的,并希望JS不仅仅运行于浏览器端,而是任何地方;感觉很牛逼的样子!然后,Nodejs在服务端实现了CommonJS规范,从而将JS从浏览器的小环境拉到了前后端通行的大环境,丑小鸭终于变白天鹅了!

按照CommonJS规范,文件即模块,使用require引用和加载模块,exports定义和导出模块,module标识模块,使用require时需要去读取并执行该文件,然后返回exports导出的内容,由于模块的读取执行是同步的文件操作,所以CommonJS只能在服务端由Nodejs发扬光大;但是在浏览器端,这种同步操作并不适用,至少会很耗时,阻塞后续代码的运行;从而在浏览器端由CommonJS衍生出两大分支:AMD(异步模块定义)和CMD(通用模块定义);

AMD(异步模块定义):

AMD的代表是RequireJS,通过define(id?, dependencies?, factory)来定义模块,require([dependencies], function(){})来调用模块,使用提前异步加载依赖模块的方式,模块加载完毕后执行回调函数,这里要好好理解JS的异步机制,不可按同步顺序执行的思维去理解,多个文件异步并行加载,哪个先执行完不是你按照加载顺序可预料到的,而是等所有依赖执行完毕,最后一并回调结果;

CMD(通用模块定义):

CMD的代表是SeaJS(已过时?),与RequireJS定义和加载模块的方式略有不同,同样可以通过define(id?, dependencies?, factory)定义模块,但是SeaJS是采用的就近依赖的方式来加载模块,一般不在dependencies里依赖模块,而是统一写法:define(function(require, exports, module){}),在factory里就近加载依赖模块,由seajs.use([dependencies],function(mod,[mod]){})来使用模块;本质上也是异步的加载模块,只是和RequireJS相比加载和执行的时机不一样罢了;

相比来说,Seajs和Requirejs都是很不错的前端模块化组织方案,各有千秋;Requirejs要等到所有前置依赖加载并执行完毕,再回调主要的代码逻辑,如果非要说有所欠缺,就得在前置依赖那里做优化了,但大致上是很流畅的;Seajs只是将依赖模块预先加载并不执行,在需要时就近使用,这时就可能也许会出现延迟的现象;

工具是非常重要的生产力:

虽然浏览器端流行的模块化规范是AMD和CMD,但是借助工具的力量,我们依然可以在浏览器端模拟CommonJS规范,比如借助Gulp、Webpack之类的工具,我们在开发环境依然可以像写Nodejs一样写前端的JS代码,由工具打包成浏览器可运行的JS,同样,异步的调用代码块也是可行的;

UMD(通用模块规范):

现在JS已经可以通行前后端了,那么很大程度上一个JS模块是既可以在浏览器端运行,同时也能在服务端跑了,UMD方案即是对AMD和CommonJS规范的整合,实现对JS模块化的跨平台;像下面这个鬼样子:

(function(root, factory){
  if(typeof define ==="function"&& define.amd){
    // AMD
    define(["jquery"], factory);
    }elseif(typeof exports ==="object"){
      // Node, CommonJS之类的
      module.exports = factory(require("jquery"));
    }else{
      // 浏览器全局变量(root 即 window)
      root.returnExports = factory(root.jQuery);
    }
  }(this,function($){
  // 方法
  function myFunc(){};
    // 暴露公共方法
    return myFunc;
}));

ES6的模块化:

ES6作为JavaScript新的标准,自带了模块化的buff,通过import和export导入导出模块;基本思想与CMD、AMD差不多,只是多了更多语法糖式的东西,毕竟属于原生的支持,当然更加好用和易于理解;由于当前的浏览器环境,要想安心的使用,还是得借助工具的力量进行转换;

转载&参考

前端各种模块化规范常回顾

前端工程之模块化

本文链接:http://westpsk.com/post/fe_module.html

-- EOF --

Comments