欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

前端模块化发展简史

来源:本站整理 作者:佚名 时间:2017-06-04 TAG: 我要投稿

前端发展日新月异,短短不过 10 年已经从原始走向现代,甚至引领潮流。网站逐渐变成了互联网应用程序,代码量飞速增长,为了支撑这种需求和变化,同时兼顾代码质量、降低开发成本,接入模块化势在必行。伴随这一变化的是相对应的构建工具的快速成长,或是为了优化、或是为了转义,都离不开这类工具。
所谓温故而知新,本篇回顾总结下前端模块化的发展历程及辅助工具。在回顾中可以更清晰的看到当前我们用的方案所处的位置,为什么会发展到这一步,目前模块化方案带来的优势等。
1. 没有模块化的日子
最开始 JavaScript 承担的任务量并不多,表单验证基本上就是他的全部,最多就是简短的前端交互,这个时期 JavaScript 组织结构非常凌乱,大部分都是后端哥哥们顺手代劳,那时候还没有“前端”这一职位。 一般都是写到一个文件或者直接写到 jsp、asp 的后端模板页面上就完事了。这个阶段没啥可说的,跳过吧。。。
2. 传统模块化
随着 ajax 的流行,前端能做的东西一夜之间暴涨,代码量飞速增加,单文件维护代码已经太沉重,于是拆之,进而引入模块化,将负责不同功能的代码拆分成小粒度的模块,方便维护。
这里要说的模块化是抛开现在你所熟知的 require,amd,seajs 等,不借助任何的模式和工具,由 JavaScript 直接完成的代码结构化。JavaScript 天生没有模块化的概念(直到 ES6), 而不像后端语言源生自带模块功能, 比如 Java 的 import、C++的 include、Node 的 require(下文说到),所以需要通过其他的方式来实现模块化。
应用模块化开发的主要目的是为了复用代码、代码结构清晰、便于维护等,比如在开发过程中,我们往往会将一些重复用到的代码提取出来,封装到一个 function 里,然后在需要的地方调用,那么这可以看做是一种模块化。
我们看一段代码 例 – 1:
function show(element) { // 展示一个元素 }
function close(element) { // 隐藏一个元素 }
上面的代码非常直观,就是要显示、隐藏一个 dom 元素,往往这种方法需要大范围多次调用,一般我们可能会放到 util.js 这样的文件里,这是第一步。接下来在业务代码中引用,例 – 2
   
   
   
2.1 存在的问题
以现在的经验来看,上面的写法会带来非常明显的问题,当然也是在这个模块化引入阶段逐步暴露的。
全局变量冲突风险:如果编写 page-1 的同学不知道 utils 里面有一个 show/close 方法,然后他自个也写了一个,同时还添加了额外逻辑,自然就覆盖了原来的方法,那么 page-2 同学在不知道的情况下调用了这方法,自然会发生错误.
人工维护依赖关系:因为存在依赖关系,所以必须先加载 util,然后才能加载 page-1/2,这里的例子非常简单,但在实际项目场景了,这样的依赖会非常多且复杂,维护非常困难,很难建立清晰的依赖关系。想想当时高大上的校内网,那种程度的页面得需要多少的模块去支撑。后续项目迭代往往会带来意料之外的问题.
2.2 尝试解决问题
针对问题 1,可以做下面这些改进:
2.2.1 代码提取
把这些方法放到一个 object 里面对外输出,例 - 3
var utils = {
    _name: ‘baotong.wang’,
    show: function(element) {},
    close: function(element) {}
}
但这样依然不能避免我们的 utils 被覆盖的可能性,孱弱的英语积累让我们想不出什么更高级的词来命名 utils,var fuzhufangfa = {}?。。。
不过这种写法同时还带来了暴露内部变量的问题,外部可以访问到 _name。
2.2.2 命名空间
然后部分开发者引入了命名空间,这个东西牛逼了,例 – 4:
var com.company.departure.team.utils = {}
代码模块通过严格的命名规则做了规范,可以按照实际情况具体到部门、team、类库。如果一个公司在代码规范上做了这样的约束,基本上可以避免变量名冲突的问题,但同时带来的需要输入过多单词的负担,目前还没有哪个 IDE 能支持 JavaScript 像 Java 一样可以一路点点点下去,这些都是需要打出来的。当然我们也可以不设计成这么复杂的命名空间,var Company.ProjectName.Module = {}; 同时结合局部变量减少输入的长度。
2.2.3 闭包封装
为了解决封装内部变量的问题,就该有请立即执行的函数登场了,这也是我们接触的最多的一种模块化方式,公司内部有点年纪的项目多少都能看到这样的写法,结合命名空间如下,例 – 5:
(function {
   var Company = Company || {};
   Company.Base = Company.Base || {};
   var _name = ‘baotong.wang’
   function show  {}
   function close  {}
   Company.Base.Util = {
     show: show,
     close: close
   }
});
上述写法通过一个立即执行的函数表达式,赋予了模块的独立作用域,同时通过全局变量配置了我们的 module,从而达到模块化的目的。基本上到这一步,问题 1 就解决了。
2.2.4 关于依赖关系
针对问题 2,代码的组织依赖关系,这块我不是很了解,向司徒求证了一下。大概情况如下。
当时业界也是有不少方案的,比如百度的 Tangram 与 Qwrap,查了下他们的 github 地址,最后一次更新是在五年前。它解决依赖关系的方式是在类库中什么依赖,类似 depend=[“com.qunar.dujia.lib”, “”, …],然后通过配套的工具去解析。
同时也有一些后端大牛为了解决前端工程化的问题发明创造了各种方案,但当时的氛围并没有现在这么重视前端,前端从业人员的水平也没现在高;同时后端哥哥们往往对前端问题、痛点了解的不深入,所以开发出来的方案很难推广。比如搞 Java 和搞 Ruby 的后端做的方案基本不太会一样。 用司徒的话来讲叫生不逢时。
2.3 这个时代的工具
2.3.1 代码合并
例 – 2 中的代码引用方式相信肯定存在于一些站点上。虽然不会带来功能问题,但是却带来了很多不必要的 http 请求,特别是复杂页面需要引用很多独立 JavaScript 的时候,从而延长了页面的 ready 时间。所以这里需要合对文件进行合并处理,将可以合并的业务代码连接到一个文件里。

[1] [2] [3]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载