如何学习前端模块化知识

JavaScript(16)
  JS的强大已经不用解释了,从Web RIA到Node服务器,到处都是JS的身影。然而由于出身的缘故,JS本身在大规模应用上存在着很多问题,比如模块化编程。本文以浏览器端模块化编程为内容,重点介绍AMD规范和CMD规范。在服务器端,NodeJS遵守的Common规范我们这里暂不讨论。
  对于计算机语言,模块化编程是必不可少的,对架构设计、代码复用起到至关重要的作用,工程中引入别人写好的库和模块能大大缩减开发周期。C/C++中,我们可以用include;Java中我们可以用import。可是在JS中,这些是不存在的,取而代之的是script标签。
  在浏览器端,我们可以通过script标签引入需要的库,然后加载自己的脚本,最后运行脚本。这样做似乎与include和import没什么区别,然而有几个重要的因素必须要考虑:JS是解释型语言,边加载边运行,后续脚本运行时,这些脚本所依赖的一切必须已经加载完毕;JS脚本加载时会阻塞浏览器,如果加载的JS很多很大,浏览器会卡住,带来很差的用户体验;通过调整script标签顺序可以修改JS模块之间的依赖,然而当模块很多时,这种做法就不可用了。
  鉴于以上,JS模块化编程规范应运而生,并出现了大量实现。这些实现,简单讲就是一个超底层的JS库,这个库的作用有两个:一是完成JS脚本的异步加载与执行;二是确保JS脚本按照用户设计的依赖关系加载,即一段脚本执行时,它的所有依赖已经加载完毕了。不同的规范,只是写法用法不同而已,最终目的都是一样的。另外,模块化编程与异步加载不分家,会让JS按需加载,大大提高页面响应速度;模块加载提供命名空间的效果,有效防止作用域污染,并有一定的容错能力。
  AMD规范和CMD规范是目前最为流行的两种模块化编程模式,符合AMD规范的库有RequireJS,符合CMD规范的库有SeaJS。
2. AMD(Asynchronous ModuleDefinition)规范
  AMD翻译过来叫“异步的模块定义”,接口非常简单,只有一个define,完整格式如下:
define(‘module-name’, [‘lib1’, ‘lib2’], function (lib1, lib2) {
return {};
第一个参数是模块的名称,可以省略;第二个是模块的依赖,也就是其他模块,如果省略,则此模块没有任何依赖;第三个参数是依赖加载完毕后的回调函数,回调函数的形参是依赖模块的输出,顺序与第二个数组参数一致,回调函数的返回值就是此模块的输出,可以作为其他模块的依赖形参。
2.1&&纯数据模块
  这种模块没有任何依赖,不做任何操作,只是为了提供数据源,可以这样定义:
color: &black&,
size: &unisize&
2.2无依赖模块
  如果模块没有任何依赖,但进行了一些预处理,可以这样定义:
define(function() {
color: &black&,
size: &unisize&
2.3将模块定义为函数
  这种模块是最常见的,意为模块的输出是一个函数,模块的依赖是这个输出函数使用的外部变量,因此这种模块的输出是一个闭包。使用时也要格外小心,尤其是输出函数当做构造函数使用时。
define([&my/cart&, &my/inventory&],
function(cart, inventory){
//return a function todefine &foo/title&.
//It gets or sets thewindow title.
return function(title){
return title ? (window.title= title) :
inventory.storeName + ' ' + cart.
2.4引入符合Common规范的模块
define(function(require){
var mod = require(&./relative/name&);
2.5 JSONP模块
  JSONP可以跨域,应用非常广泛,使用JSONP模块时,callback必须设成’define’。
require([&/api/data.json?callback=define&],
function (data) {
//The data object will be the APIresponse for the
//JSONP data call.
console.log(data);
这种方法一般用于初始化,但错误处理比较复杂。
3. CMD规范
  CMD(Common ModuleDefinition)规范,跟AMD相比,CMD更像CommonJS。至于CMD和AMD哪个好哪个坏,完全没有定论的,主要看个人喜好。CMD的主接口也叫define,其参数可以是string、object、function。define的用法也可以像AMD一样,带id、依赖、回调,但这样就不属于CMD规范了。基本格式如下:
define(function (require, exports, module) {
3.1 require参数
  第一个形参require是一个方法,用来加载外部模块,用法跟2.4类似:
define(function (require, exports) {
// 获取模块 a 的接口
var a = require('./a');
// 调用模块 a 的方法
a.doSomething();
  但是这个require是同步模式加载,即如果模块没加载完毕,require后面的语句是不会执行的。AMD规范中都是异步加载,在回调function中使用require,其实相当于告诉构建器要在依赖队列中加入相关模块。
  require同样有异步加载功能,异步加载后,执行响应的回调:
define(function(require, exports, module) {
// 异步加载一个模块,在加载完成时,执行回调
require.async('./b',function(b) {
b.doSomething();
// 异步加载多个模块,在加载完成时,执行回调
require.async(['./c','./d'], function(c, d) {
c.doSomething();
d.doSomething();
3.2 exports参数
  exports是一个对象,是模块的对外接口,即AMD规范中的return部分,当然,也可以像AMD规范一样,利用return返回接口。两种方式都可以,非常灵活。
define(function(require, exports) {
// 对外提供 foo 属性
exports.foo = 'bar';
// 对外提供 doSomething 方法
exports.doSomething =function() {};
define(function(require) {
// 通过 return 直接提供接口
foo: 'bar',
doSomething: function() {}
值得注意的是,exports形参是不能重新定义的,因为重新定义后,原引用就断掉了,下面的做法起不到输出模块的作用:
define(function(require, exports) {
// 错误用法!!!
exports = {
foo: 'bar',
doSomething: function() {}
3.3 module参数
  module 是一个对象,上面存储了与当前模块相关联的一些属性和方法。
  module.id为模块标识,module.uri为模块绝对路径,module.dependencies为模块的依赖数组,module.exports为模块的输出引用。也就是说,3.2节最后的例子中,如果这样写,就是可以工作的:
define(function(require, exports, module) {
// 正确写法
module.exports = {
foo: 'bar',
doSomething: function() {}
同时,对module.exports的赋值必须是同步的,放在settimeout里面是不行的。
  可以看出,模块化编程为我们提供了良好的环境,在这个环境中,可以进行更明确的分工合作,让JS开发更专业化。同时,AMD规范和CMD规范都提供了异步加载,让Web前端应用更加高效,用户体验更好。
  至于这两种规范哪个好一些,这个完全看个人编码习惯了,适合你的,就是好的。不过总体来看,CMD有相当一部分兼容了AMD,其最大的区别还是对依赖的引用上。
  AMD主要通过回调函数的形参对依赖进行引用,有多少个依赖,就有多少个形参,当然如果依赖很多也可以不写那么多形参,通过arguments引用,或者在回调函数内部require也是一样的。这里需要说明的是,AMD规范中,尤其是RequireJS中,如果通过var a = require(‘module-name’);这种形式引入依赖,那么module-name必须要在依赖数组中存在,否则会报错。
  CMD规范的依赖引用主要是在回调函数中直接require了,并且这种require是同步的,也提供了异步接口,这样做,势必要影响运行期性能。但是想AMD那种预加载依赖的方式,势必要影响加载时间。这两种影响哪个能容忍,哪个不能容忍,应该具体情况具体分析,视应用而定。
CMD规范定义:
/seajs/seajs/issues/242
Javascript的AMD:
/happyPawpaw/archive//2528864.html
RequireJS中文网:
Sea.js文档:
http://seajs.org/docs/#docs
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:8539次
排名:千里之外
原创:19篇您的位置: >>
  模块化概念
  模块化就是为了减少循环依赖,减少耦合,提高设计的效率。为了做到这一点,我们需要有一个设计规则,所有的模块都在这个规则下进行设计。良好的设计规则,会把耦合密集的设计参数进行归类作为一个模块,并以此划分工作任务。而模块之间彼此通过一个固定的接口(所谓的可见参数)进行交互,除此之外的内部实现(所谓的隐参数)则由模块的开发团队进行自由发挥。
  程序模块化的目的:
减少循环依赖
提高设计效率
  程序模块化的实施:
把耦合密集的归为一个模块
模块间通过固定的接口交互
模块内部实现自由发挥
  HTML CSS Images的模块化设计
  页面模块化的实施,这里指的是针对除去JavaScript部分的页面代码进行模块化实施。通过html css 图片进行模块化。
  页面模块化的实施思路是高度耦合的页面片段封装,模块布局作为公开接口,高度耦合的页面进行封装,使用独立的css文件,高度耦合的图片进行封装,给某类相关性强的图片建立文件夹。
  页面模块化的目的是,实现多人协同开发页面,提高页面研发速度和降低维护难度。研发速度的提升体现在多人协同并行开发, 维护难度体现在减少版本的混乱,根据模块区分版本降低版本间代码冲突和文件错误覆盖。&
  拆分页面模块,从小到大的分解
  1. 拆分页面模块
  一个页面有很多个小单元模块组成,他来自有原始需求文档,比如logo,导航,内容1,内容2,内容3,内容4,尾部导 航,版权信息等等。根据他们就可以拆分出基本的模块。
  2. 拆分网站模块
  将整个网站安排频道或者分类进行拆分,比如首页,内容页,文字列表页,图片列表页,频道1页面,频道2页面,分类1页面,分类2页面,后台管理页面,等等。
  3. 每个网站作为一个模块。比如商城站,支付站,论坛,三个站独立为三个大模块。
  模块化实现
  1. 高度耦合提取为一个模块,用模块代码作用域进行控制
  代码1. 非继承模块,通过后代选择符方式控制作用域
&div class="mod"&&h3 class="title"&title&/h3&&div class="con"&
&a class="more"&more&/a&&/div&
.mod {}.mod .title {}.mod .con {}.mod .more {}
&div class="footer"&&ul&&li&&a href="" title=""&关于&/a&&/li&&li&&a href="" title=""&合作&/a&&/li&&li&&a href="" title=""&招聘&/a&&/li&&/ul&Copyright & 2009 某公司 版权所有&/div&
.footer {}.footer ul {}.footer p {}
  代码2. 继承模块,提取众多模块中公共部分,具体模块通过优先级进行处理。继承模块方面整站某些模块的批量修改处理,也提高复用性,降低代码重复。
.mod {}.mod .title {}.mod .con {}.mod .more {}.note {}.note .title {}.note .con {}.note .more {}
&div class="mod note"&&h3 class="title"&title&/h3&&div class="con"&
&a class="more"&more&/a&&/div&
  2. 页面模块
  页面模块代码作用域的控制通过css文件来控制。某类具有高度耦合的页面使用自身的css文件。
  3. 模块间的公开接口
  上面是模块的封装,公开的接口在页面中表现为什么?
  首先是reset,base,可继承模块,这些代码是开放接口,必须根据这些代码进行页面代码开发,也就是你的页面代码必须在以上代码基础上开发。
  其次是css文件,css文件名称和它作用于那些页面。
  再次是布局、模块class,id命名,模块在页面的哪个位置。在CSS中的表现就是定位,布局,和部分盒模型。float、position、 width、height等等。布局通常使用css作为接口实现,如果布局具有高度的逻辑性,完全可以通过html和css组合进行,比如960 Grid System,或者采用YUI grid.css。模块class和id的命名用于区分模块,不能在一个页面的所有css中出现不同模块同用一个class和id名。
  规划整站模块
  上文提到的基本的原理,真正实施起来还是存在很多问题,模块粒度问题,公共模块与普通模块的区分,继承模块是否值得继承等等,页面模块如何划分。
  首先,了解你的项目,通过画网站树状图了解你网站的总体结构和页面模块。
  其次,理清结构逻辑和视觉逻辑,结构逻辑就是看你的页面由那些模块组成,视觉逻辑了解可继承模块,布局逻辑(网格布局或者非网格布局)
  附图:
Web前端热门文章
Web前端最新文章下决心转前端了,求学习路线建议
刚毕业两个月,在公司做Java,感觉要学习的东西很繁,SSH什么的一大堆,而且最要命的是我不怎么感兴趣。所以打算转前端,而且自己也比较感兴趣。但是前端要学的东西也很多,HTML/CSS/JavaScript,然后还有各种HTML5/CSS3/Less/jQuery/Angular.js 等等前卫的东西。怎样的学习路线才能不让学习那么陡呢?希望过来人给点意见~
感谢您为本话题评分。
共有6个回答
LZ不是我吓你,前端很难,一入前端深似海啊。前端不仅仅是复制粘贴几段HTML标签,网上找点CSS特效,下载个jQuery插件什么的。一个专业前端在知识的深度和广度上要求都非常严格。仅仅是JavaScript,要写得漂亮、高效、模块化都不容易了,外加 bootstrap, less, html5, js, coffee, jquery, backbone, underscore, mustache, angular, ember, knockout…这一堆东西。还有nodejs做服务器端,单要精通JavaScript都很难了。又要广又要深,一开始会很力不从心。加油争分夺秒地学习吧……
认真学习完下面这个链接的东西,前端应该没问题。
很多人觉得前端没技术含量,纯体力活。如果LZ有志于做前端,不要有这些想法。如果做前端做得像做体力活,那么肯定就没前途了,这样的公司也没呆下去的价值。正如 @大名 所说,前端有很多东西可学,灵活运用能够大大降低工作繁杂度。而且前端创新的地方有很多,思维一定要活跃。我现在就很享受写JavaScript代码,了解越深,写得就越舒服。
不是有这么个笑话么,搞C的看不起搞C++的,搞C++的看不起搞java的,搞java的看不起搞.net的,搞.net的看不起搞js的,搞js的看不起搞html的,搞html的看不起美工,最后美工周末去泡mm的时候,一群傻X在那里加班。
前端3年经验了。其实呢,前端单个知识点都是很浅显的,主要是零散、繁杂。说难其实不是很难,就是繁。各个知识点不成体系,如果你能建立体系地学,还是能很快学起来的。说白了,前端就是经验堆出来的,经验是在实践中积累出来的,多练手很重要。
前端真的很深,LZ要明确方向,做哪种前端,移动平台的还是桌面平台的,考虑到兼容性就能让人痛苦了。
建议楼主往底层走....PS:我现在是最底层,往上走..
如果你认为此话题有广告、灌水的嫌疑,请给此话题评一颗星。平均分低的话题将不会再显示。
良好的讨论氛围由大家共同维护。javascript模块化是什么及其优缺点介绍
字体:[ ] 类型:转载 时间:
模块化是一种将系统分离成独立功能部分的方法,可将系统分割成独立的功能部分,严格定义模块接口、模块间具有透明性
如今backbone、emberjs、spinejs、batmanjs 等MVC框架侵袭而来。CommonJS、AMD、NodeJS、RequireJS、SeaJS、curljs等模块化的JavaScript扑面而来。web前端已经演变成大前端,web前端的发展速度之快。 1)我们来看看什么是模块化? 模块化是一种将系统分离成独立功能部分的方法,可将系统分割成独立的功能部分,严格定义模块接口、模块间具有透明性。javascript中的模块在一些C、PHP、java中比较常见: c中使用include 包含.h文件;php中使用require_once包含.php文件 java使用import导入包 此中都有模块化的思想。 2)模块化的优缺点: a&优点: 可维护性 1.灵活架构,焦点分离 2.方便模块间组合、分解 3.方便单个模块功能调试、升级 4.多人协作互不干扰 可测试性 1.可分单元测试 b&缺点: 性能损耗 1.系统分层,调用链会很长 2.模块间通信,模块间发送消息会很耗性能 3)最近的项目中也有用到模块化,使用的是seajs,但是当引用到jquery,jquery easyui/或者jquery UI组件时,有可能会用到很多jquery插件,那这样要是实现一个很复杂的交互时,模块间的依赖会很多,使用define()方法引入模块会很多,不知有么有什么好的方法? 4)附: 内聚度 内聚度指模块内部实现,它是信息隐藏和局部化概念的自然扩展,它标志着一个模块内部各成分彼此结合的紧密程度。好处也很明显,当把相关的任务分组后去阅读就容易多了。 设计时应该尽可能的提高模块内聚度,从而获得较高的模块独立性。 耦合度 耦合度则是指模块之间的关联程度的度量。耦合度取决于模块之间接口的复杂性,进入或调用模块的位置等。与内聚度相反,在设计时应尽量追求松散耦合的系统。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具function时代
  前端这几年发展太快了,我学习的速度都跟不上演变的速度了(门派太多了,后台都是大牛公司支撑类似于的react、的angular,angular的1.0还没怎么用过,网上查阅2.0的正式版就要出来,书写方法大改,思维架构都有很大的改变,真是难为了现在的前端)。2010年第一次接触前端js,还是从asp.net拖控件中接触,再接着就是我大学那个时代最出名的传智播客视频教学,那个时候课余时间全去看这个视频了,对着教学一个一个的敲,依稀的记得好定义了好多function,现在想想还是很有趣,心想反正就几个方法也不会重复。
Object,Function的prototype时代
  随着前端的代码越写越多(自己偶尔会和一起接点外包或帮老师做点项目,毕竟学了不用,永远也只是纸上谈兵),发现自己词穷了,自己定义的function名称太多了(方法重名可是会覆盖之前的方法),这个时候怎么办了,在学校最好一点是什么,就是几乎每个学校都有,你都能找到自己想要的书籍,因为我本身大学主专业是学习C#的,js这种弱类型语言不停的写function太不美观了(自黑一下,其实我是让人讨人厌的),图书馆有很多js设计模式的书籍,js高级,写的都很不错,到现在项目中也都没有完全的用到,有些可能用到了吧,可是都不记得这些专业术语名词(现在什么设计模式,什么新的缩写名词太多了,有些虽然用过,可就是就不住。记不住又不行,有些面试官就是喜欢问,不知道你可就惨了,有些更可笑的是考官在网上现查的,然后立即来问你,'哈哈,其实我也做过这种事')。虽然我是一个大懒人可是看多了,至少也是会记住一两个,用Function的prototype和arguments去搞面向对象还是很有趣的,因为是弱类型,所以很多写法更灵活。如果你想说你更懒,那你就Object里面定义一大顿方法也行,其实这种写法在现在也是很流行,比如我们常用的工具类。
  好的员不是一个人独自敲代码,闭门造车,我们多去查看新技术、新框架、新组建(不过这也确实难为很多人,毕竟是一个多姿多彩的世界。幸好随着时代的进步,我们看书学技术的途径也越来越多了,刚开始我关注过一些有趣技术的qq账号,每天都可以在我们逛QQ的时候,看到几条很有趣翻译的外国技术分享,再后来有朋友推荐我去看各大公司技术论坛网站,不过这个没看多久,太多了,好坏难分,重叠的太多了。发展越来越快,火得一塌糊涂,几个微信前端公共账号还是不错的,每天都会推荐一篇不错的文章,公共号为&前端早读课&,&前端大全&),个人认为好的都应该有拿来主义和创新精神,所以我们引用的框架越来越多,好多框架都是一个js文件,它们都怕自己的代码被污染,所以大多数用到了闭包,那什么是闭包了,闭包有什么好处呢,网上有好多,在这里我也啰嗦几句。
闭包的好处:
1. 逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑。2. 方便调用上下文的局部变量。3. 加强封装性,第2点的延伸,可以达到对变量的保护作用。
闭包的坏处:
闭包有一个非常严重的问题,那就是内存浪费问题,这个内存浪费不仅仅因为它常驻内存,更重要的是,对闭包的使用不当会造成无效内存的产生。
优化注意:
1)由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,所以不能滥用闭包,否则会造成的性能问题,在IE中可能导致内存泄露。解决方法是,在退出函数之前,将不使用的局部变量全部删除。2)闭包会在父函数外部,改变父函数内部变量的值。所以,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便
只要你搞前端,或者搞web几乎都有人问你,几率几乎达到80%,这个时候推荐一篇(深入理解Script系列(2):揭秘命名函数),这可是汤姆大叔,本身非常的佩服他,他写的js设计模式和js注意事项确实不错,就在博客园中,也很感谢这些人在博客园中,我们大学才更幸福。
js模块化和MVC
  Extjs或sencha touch这两个都是同一家公司的,也是我用到的最早的前端模块化和MVC,sencha touch我用的也是最多的,因为移动端毕竟火爆。
  说的它的好处吧:
  1.灵活架构,焦点分离   2.方便模块间组合、分解   3.方便单个模块功能调试、升级   4.多人协作互不干扰
  mvc是后端说的最多的术语,如果你现在还不懂你最好快点去恶补下,因为现在很多形形色色的前端MVC层出不穷,
  MVC开始是存在于桌面程序中的,M是指业务,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。比如一批统计数据可以分别用柱状图、饼图来表示。C存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。
  MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 的模式:
Model(模型)表示应用程序核心(比如记录列表)。View(视图)显示数据(数据库记录)。Controller(控制器)处理输入(写入数据库记录)。MVC 模式同时提供了对 HTML、CSS 和
的完全控制。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。  通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。  通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。  通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。MVC 分层有助于管理复杂的应用程序,因为您可以在一个时间内专门关注一个方面。例如,您可以在不依赖业务逻辑的情况下专注于视图设计。同时也让应用程序的测试更加容易。MVC 分层同时也简化了分组开发。不同的开发人员可同时开发视图、控制器逻辑和业务逻辑。
  啰嗦一点说一下sencha这家js框架公司的好处和弊端吧,他们提供的框架有很好的样式体系,基于sass写的,可以随便我们改变样式风格,提供的sencha.cmd第一次让我感觉到了前端的工程化,提供了代码的压缩、代码验证、代码模块的依赖合并。组件丰富,说了这么多大家感觉一定很爽吧。但是由于他提供非常多的组件,所以导致js代码过多,虽然有些我们可以自行配置筛选压缩,它的依赖压缩不是全部根据配置,大部门和里面的文件有关,必须不停的移除或添加,反正就是很麻烦,特别是版本的升级时候,真是想吐了。有时因为压缩的缘故还会报一些下错。
AMD和CMD时代
&  说来前面的大框架我们一定想用到更加轻便的模块框架了,这个时候一定要说说两派的代表框架RequireJS和SeaJs,引用一下github上的专业术语吧,个人也经过一段时间的验证。
RequireJS 和 Sea.js 都是模块加载器,倡导模块化开发理念,核心价值是让 JavaScript 的模块化开发变得简单自然。
两者的主要区别如下:
定位有差异。RequireJS 想成为端的模块加载器,同时也想成为 Rhino / Node 等环境的模块加载器。Sea.js 则专注于 Web 浏览器端,同时通过 Node 扩展的方式可以很方便跑在 Node 环境中。
遵循的规范不同。RequireJS 遵循 AMD(异步模块定义)规范,Sea.js 遵循 CMD (通用模块定义)规范。规范的不同,导致了两者 API 不同。Sea.js 更贴近 CommonJS Modules/1.1 和 Node Modules 规范。
推广理念有差异。RequireJS 在尝试让第三方类库修改自身来支持 RequireJS,目前只有少数社区采纳。Sea.js 不强推,采用自主封装的方式来&海纳百川&,目前已有较成熟的封装策略。
对开发调试的支持有差异。Sea.js 非常关注代码的开发调试,有 nocache、debug 等用于调试的插件。RequireJS 无这方面的明显支持。
插件机制不同。RequireJS 采取的是在源码中预留的形式,插件类型比较单一。Sea.js 采取的是通用事件机制,插件类型更丰富。
总之,如果说 RequireJS 是 Prototype 类库的话,则 Sea.js 致力于成为 jQuery 类库。
webpack时代
  Seajs我没怎么用过项目,所以也就不说了,RequireJS 用过,那时候用的.net的mvc5.0中的一个第三方插件,帮我省去了很多的,因为如果我们用nodejs的话一般要自己书写R.js,用来配置一些处理流程,强大的.net插件帮我省去了好多,可是每个模块你都的定义,并且在配置文件中书写出来,每个模块都要写初始模块定义,为什么我会这么去说话一个框架了,因为不断的学习用到了更好的webpack,以下是我的观点(有些解释术语参考了其它博客)
说说一下webpack的优点吧:
1.require.js的所有功能它都有2.编绎过程更快,因为require.js会去处理不需要的文件3.还有一个额外的好处就是你不需要再做一个封装的函数,require.js中你得这样
define(['jquery'], function(jquery){})
4.现在你需要一个很大的封装去定义每个模块,然后你需要在在require.js的配制文件中将每个模块的路径都配出来,用过requirejs都会遇到的好繁琐
require.config({
baseUrl: '/scripts',
'facebook'
: '//connect.facebook.net/en_US/all',
// 'facebook'
: '//connect.facebook.net/en_US/sdk/debug'
'requirejs'
: '../bower_components/requirejs/require',
: '../bower_components/react/react-with-addons',
'underscore'
: '../bower_components/lodash/dist/lodash',
'futures-requirejs' : '../bower_components/futures-requirejs/future',
: '../bower_components/jquery/jquery',
// 'phaser'
: '../bower_components/phaser/build/phaser',
'phaser.filters'
: '../bower_components/phaser/filters/',
: '../thirdParty/phaser/Phaser',
: '../bower_components/Snap.svg/dist/snap.svg',
: '../thirdParty/Proton',
'copyProperties'
: '../thirdParty/copyProperties',
: '../bower_components/flux/dist/Flux',
'eventEmitter'
: '../bower_components/eventEmitter/EventEmitter',
: '../bower_components/pixi/bin/pixi',
'crossroads'
: '../bower_components/crossroads/dist/crossroads',
: '../bower_components/js-signals/dist/signals',
: '../bower_components/hasher/dist/js/hasher',
: '../bower_components/async/lib/async',
'socket.io-client'
: '../bower_components/socket.io-client/dist/socket.io',
'html2canvas'
: '../bower_components/html2canvas/build/html2canvas.min',
: '../bower_components/hammerjs/hammer',
'touch-emulator'
: '../bower_components/hammer-touchemulator/touch-emulator',
: '../bower_components/moment/moment',
// 'famous'
: '../bower_components/famous',
'tinygradient'
: '../bower_components/tinygradient/tinygradient',
: '../bower_components/page/index',
// 'faker'
: '../bower_components/faker/dist/faker',
: '../thirdParty/Faker',
: '../thirdParty/Perlin',
'tinycolor'
: '../vendors/tinycolor',
: '../../node_modules/flux/index',
: './errors',
: '../../server',
location : '../bower_components/api2/src/',
'phaser.filters/Fire': {
deps: ['phaser'],
exports: 'page'
'snap' : {
exports: 'Snap'
'html2canvas' : {
exports: 'html2canvas'
'facebook' : {
exports: 'FB'
// 'underscore': {
exports: '_'
'phaser': {
exports: 'Phaser'
exports: 'PIXI'
'hammer': {
exports: 'Hammer'
'touch-emulator': {
exports: 'TouchEmulator'
'proton': {
exports: 'Proton'
'moment': {
exports: 'moment'
以下是webpack的一个文件配置,
var path = require("path");
var webpack = require("webpack");
var ExtractTextPlugin = require("extract-text-webpack-plugin")
module.exports = {
// context: path.join(__dirname),
index: './app/scripts/index.js',
page1: './app/scripts/page1.js',
page3: './app/scripts/page3.js'
path: path.join(__dirname, '_dist'),
filename: './scripts/[name]-bundle.js',
chunkFilename: "./scripts/[id]-chunk.js",
// library:'appConfig'
//主要应用jsonp命名重新定义
loaders: [{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
test: /\.less$/,
loader: 'style-loader!css-loader!less-loader'
test: /\.woff$/,
loader: 'url-loader?prefix=font/&limit=5000'
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
compact: false
'html-minify-loader': {
empty: true, // KEEP empty attributes
cdata: true, // KEEP CDATA from scripts
comments: true // KEEP comments
resolve: {
root: [path.join(__dirname, "bower_components"), path.join(__dirname, 'app', 'scripts')],
plugins: [
new monsChunkPlugin({
name: "commons",
filename: "./scripts/commons.js",
chunks: ["page1", "page2", "page3"]
new ExtractTextPlugin("./styles/[name].css"),
new webpack.ResolverPlugin(
new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
我们可以发现少了好多引用模块js文件路径引用,可能会有人问,它怎么知道我要引用那些js,在nodejs里有一个有趣的插件brower(这东西你如果没有用到,你老板可能会说你还是一个初级菜鸟)
Bower 是 推出的一款包,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系
包管理工具一般有以下的功能:
注册机制:每个包需要确定一个唯一的 ID 使得搜索和下载的时候能够正确匹配,所以包管理工具需要维护注册信息,可以依赖其他平台。文件:确定文件存放的位置,下载的时候可以找到,当然这个地址在上是可访问的。上传下载:这是工具的主要功能,能提高包使用的便利性。比如想用 jquery 只需要 install 一下就可以了,不用到处找下载。上传并不是必备的,根据文件存储的位置而定,但需要有一定的机制保障。依赖分析:这也是包管理工具主要解决的问题之一,既然包之间是有联系的,那么下载的时候就需要处理他们之间的依赖。下载一个包的时候也需要下载依赖的包
可能会有人会问,我虽然将这些包下了下来,那我还是不知道那些模块位置,我该如果引用了,webpack一个插件轻松解决这个问题:以下是配置文件
resolve: {
  root: [path.join(__dirname, "bower_components"), path.join(__dirname, 'app', 'scripts')],
}, plugins: [
  new webpack.ResolverPlugin(
    new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin("bower.json", ["main"])
那如果调用了
var $ = require("jquery");
是不是感觉很方便了,还有一些新手可能会吐槽,js本来就是弱类型语言,框架那么多,智能提示是不是很差,特别是玩那套玩多了的人一定会问,在此推荐以下webstorm、sublime、atom它们上面的插件还是不错的
5.requirejs它是异步依赖加载的,说白了就是,只要你用到了,它绝对会一次性加载完,就算你初始化没有用到,它也会加载,如果你把它压缩,文件就好大了,最后就一个文件。你也可以破坏它的原则,按传统的写法单独加载,不过就整体就不是很美观了。可能有些解决的插件,我没用到也是有可能的,这里也就不多说了。
webpakc就很好解决了,它提供的插件可以自动分析,根据你提过js文件主入口,自动分析,可合成多个js文件,但是它不会全部加载,按照你的需要一次加载,这样就不会出现页面刚初始化就加载不必要的js文件,提高页面速度(虽然可以靠用体力解决,说白了就是注意写法,不过好痛苦)
以上是它们的对比,再说说它的私有特性吧
1. 对 CommonJS 、 AMD 、ES6的语法做了兼容2. 对js、css、等资都支持打包(css都可以合成多个css文件包,好爽,再也不是sb似的全部加载了,sass和less虽然也是模块化的加载合并,可是css和js分离的关联不大,这里的css可以和js有更大的关联,更细致区分加载的js)3. 串联式模块加载器以及插件机制,让其具有更好的灵活性和扩展性,例如提供对CoffeeScript、ES6的支持4. 有独立的配置文件webpack.config.js5. 可以将代码切割成不同的chunk,实现按需加载,降低了初始化时间6. 支持 SourceUrls 和 SourceMaps,易于调试7. 具有强大的Plugin接口,大多是内部插件,使用起来比较灵活8.webpack 使用异步 IO 并具有多级缓存。这使得 webpack 很快且在增量编译上更加快
在补充一个特别的属性吧
项目开发中,仅有一台静态服务器是不能满足需求的,我们需要另启一台web服务器,且将静态服务器集成到web服务器中,就可以使用webpack的打包和加载功能。我们只需要修改一下配置文件就可以实现服务器的集成。
'./src/page/main.js',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://127.0.0.1:8080'
path: __dirname,
filename: '[name].js',
publicPath: "http://127.0.0.1:8080/assets/"
plugins: [
new webpack.HotModuleReplacementPlugin()
如果在开发中启动两个服务器并不是一个很好地选择,webpack提供了一个中间件webpack-dev-middleware,但其只能在生产环境中使用,可以实现在内存中实时打包生成虚拟文件,供浏览器访问以及调试。使用方式如下:
var webpackDevMiddleware = require("webpack-dev-middleware");
var webpack = require("webpack");
var compiler = webpack({
// configuration
output: { path: '/' }
app.use(webpackDevMiddleware(compiler, {
// options
  有些好处可能没有说到,webpack可能过几年它就会被取代也是有可能,但是现在如果你说你不会,那就请赶快恶补吧,它会带你飞的。
以上分析结合自己工作经验之谈,有些可能说大呢,说错了大家就一笑而过,不对的地方也希望诚恳指出。

我要回帖

 

随机推荐