前端框架的工程化之路

前端框架工程化之路

人类的发展动力源于一个“懒”字,就如现在的大前端正是史前那群“懒”而聪明的“切图仔”进了软件工程的施工现场,怀揣着更少代码、更少沟通、更少错误、更少维护的梦想奔袭而来。从框架齐放闹革命到三大框架三足鼎立,从构建工具争鸣到webpack一统江湖,从Javascript 遵循ES5长达7年统治到向ES6的自我进化。前端的发展与它们的成功都离不开一个“术”,工程化。

模块的进化

在没有框架的史前

我们面临的问题:
1.全局变量污染:各个文件的变量都是挂载到window对象上,污染全局变量。
2.变量重名:不同文件中的变量如果重名,后面的会覆盖前面的,造成程序运行错误。
3.文件依赖顺序:多个文件之间存在依赖关系,需要保证一定加载顺序问题严重。
于是老王想出使用自执行函数的方法去解决问题


var foo = (function(cNum){
   var aStr = ‘aa‘;
   var aNum = cNum + 1;
   return {
       aStr: aStr,
       aNum: aNum
    };
})(cNum);

前端最初始的模块诞生了,这个模块有问题吗?有!虽然模块内部的变量对全局不可见了,但暴露出来的foo是一个全局变量,这样的模块多了全局变量也会很多。

老李在老王的办法基础上添加命名空间去解决问题:


app.util.modA = xxx;
app.common.modA = xxx;
app.tools.modA.format = xxx; 

除了写法丑陋外,这样的模块约束力极低,很容易遭到不遵守的开发者破坏,需要开发者有一定的划分不同模块的能力,更大的问题是需要人为的解决模块加载、初始化等管理问题。

框架加冕时代

2009年横空出世的前端框架angular 的模块机制


angular.module(‘ConfigModule‘).service("TextConfig", function () {
    this.headerText = {
    };
});

angular.module(‘HeaderModule‘, [‘ConfigModule‘]).controller(‘HeaderCtr‘, [‘$scope‘, ‘TextConfig‘, function ($scope, textConfig) {
    $scope.headerText = textConfig.headerText;
}]);

Angularjs的模块机制相比老王、老李的解决方案上增强了模块的约束性,和帮助开发者划分模块外,最重要的是解决了模块的运行时管理问题(模块的初始化顺序问题和依赖的模块自动初始化问题。再被多个模块依赖的情况,模块仅且只加载一次的问题,统一的输入输出api问题)。看似完美的方案,但仍有问题。

构建工具辅政

angularjs的模块机制只解决了运行时管理问题,但没有解决模块加载管理问题。这让使用者不得不去链式在页面引用模块文件。所以在那个时候出现了一些构建工具与相应的插件来帮助我们 比如gulp、grunt、插件 browserify。实际上angularjs的模块机制也只是一定程度的解决了运行时管理问题,了解的同学应该知道在angularjs里做模块异步懒加载是件非常困难的事情。在angular 2及以上版本加入了动态加载模块的支持。其它框架,例如vue组件(这里暂且把vue的组件当作模块看待,后面会进行区分)也加了相应的支持, 这得益于框架的组件或模块的factor机制的支持和webpack code splitting功能的支持。


const Foo = resolve => {
  require.ensure([‘./Foo.vue‘], () => {
    resolve(require(‘./Foo.vue‘))
  })
}

const router = new VueRouter({
  routes: [
    { path: ‘/foo‘, component: Foo }
  ]
})  

一直在接近,但从未实现的组件化

前面谈模块化发展中谈到了vue的组件,组件是一种模块,但又超越模块。模块是逻辑单元的封装,让开发及维护成本更低。那么组件则是更高一层的抽象,是一个业务单元的封装,能够独立运行的软件单元。组件需要解决的问题:隔离、去污染问题(模块解决的隔离只限于js变量的隔离、而组件还需要解决css的隔离)、状态管理问题、与其它组件通讯问题,生命周期问题,一个好的组件设计还需要遵循软件设计的一些原则。

不得不改源码的jquery组件

我们先来看看jquery的年代组件长什么样? 以前的代码一般是用自执行函数作为一个类,这里为方便理解,我用ts展示一下。


export class component {
     selector:Element;
     options:any
     static defaultOption = {
        ‘color‘: ‘red‘,
        ‘fontSize‘: ‘16px‘,
        ‘textDecoration‘:‘none‘}
     constructor(selector,opt) {
           this.selector = selector;
           this.options = $.extend({}, this.defaultOption, opt)
     }
     highlight () {
            return this. selector.css({
                ‘color‘: this.options.color,
                ‘fontSize‘: this.options.fontSize,
                ‘textDecoration‘: this.options.textDecoration
            });
    }
}

组件使用者拿到这个组件并初始化,根据组件上层的一些交互,调用组件方法,改动组件内部。 我们可以看到组件上层依赖这个组件,且依赖的是highlight()的具体实现。根据OCP原则,对扩展开放,对修改关闭。当我们需求变化时,比如我们的highlight需要把背景色改一下,只能对组件内部逻辑做修改。很显然这样的组件不是一个好设计。

数据驱动让组件高可用性

进入有前端框架的时代,angular使用数据驱动改变视图的状态,这是很大的一个进步,数据驱动解耦了组件外层对组件的依赖关系,将真正的依赖抛向外层的传给组件的数据(有点类似依赖倒置的意思),组件内部负责根据数据的变化改变UI状态。(React Virtual DOM 驱动视图实际也是一种数据驱动,只是一个是找到数据最小粒度的变化直接改动对应的视图,一个是数据生成Virtual DOM找到最小粒度的Virtual DOM变化,改动对应的视图。本质上都是数据驱动视图)。
数据驱动视图解耦了组件与组件的依赖问题。但同时引入了一个问题,状态混乱问题。写过angularjs的同学应该知道状态混乱之痛,当我们在angularjs的多个组件依赖同一份数据时,当一个组件树中某一个组件将该数据更改时,整颗组件树中使用该数据的组件都会跟着共振。但实际情况是,树当中有一部分组件不需要跟着某一次的数据变化而变化。

状态管理让个体拒绝骚扰

react、angular使用immutablejs强化单向数据流。这的确减轻了复杂度,但这种方式对于子组件想通过状态变更驱动父组件、兄弟组件变化的情况,只能通过注册事件通知的形式。首先这种形式会违背隔离性,有很高的耦合,组件内部必须知道外部想要知道我会有什么变化,预留订阅的钩子。其次对于一颗组件树跨了N层,极端点从叶子节点到根节点这样一个通知在每层订阅子组件事件,会显得非常不合理。
于是衍生的一些flux redux库的状态集中式托管,让一个组件的数据驱动视图的变化,可以来源于任何一个组件树节点,又不会让变化成复杂的网状拓扑结构,而是成星型拓扑结构。
这个发展过程实际也是为了解耦合,让组件更加独立,就好似以前一个人的每一个日常活动都推送出去让全人类知道,由于日常太过苦逼影起社会负面情绪暴增,影响太大了(无单向数据流的情况)。于是乎改为在推送前,大家先订阅建立关系,建立关系则推送,大家发现这套太麻烦了,需要个体知道别人关心我哪个日常活动,家人想知道我吃的什么我建立一个晒图发布方式,领导想知道工作情况,我建立一个写周报发布方式,于是乎我不停的改变自己适应社会(这就是一种耦合,单向数据流方式)。当个体丧失人性后,终于想到了一个更好的办法,做自己该做的事,把这种拔内裤的事情交给社会,我在办公室就给我采集认真工作的照片,系统让领导看还是让其它同事看作为个体的我不需关心。我在吃大餐的时候你采集照片,系统要给哪些联系人,这由我此刻处的环境下社会关系决定。这个系统就是状态管理器,这个社会就是组件所处的环境。

组件进化之殇

组件的进化从未停下脚步,例如css隔离问题从依靠项目wiki中制订css命名规范到css Modules自动化解决css隔离问题。从angular1的混乱的网状状态管理到react、angular使用immutablejs强化单向数据流、和衍生的一些flux redux库的状态集中式托管。从vue的简单生命周期到2.0加入keep-alive、activated、deactivated使生命周期的增强。组件的发展一片欣欣向荣,但为什么我仍认为还没有实现组件化呢?

框架的出现让组件拥有了其应该有的特性,让开发者无需再重复造轮子解决这些问题。但也引入了新的问题,组件的独立性。
前面提到组件应当是一个独立运行的软件单元。而实际的情况是,组件只是在某框架体系下独立运行的软件单元。而工程化也是一个去底层服务的趋势,我们可以看看近年的docker技术、云服务的serverless概念,都强调其无需关注底层执行环境,想象一下如果某天我们开发一个页面无论采用任何技术架构与框架,都只需引入一个个Custom Element,把dom attribute作为API(或者拿着各团队发布的在线运行的一个组件地址),去组装页面即可。这就是近几年前端的一个研究课题微前端技术。目前的微前端技术也有不错的发展,利用Custom Element的实现方案,解决了一些基本的问题,如前面提到的:隔离性、状态管理、通讯问题、生命周期问题、不依赖前端架构体系问题。但作为能独立服务端部署提供使用的一个component还有很多问题待解决,但这是一个组件化发展的方向。

这是一个不错的微前端实现方案 https://micro-frontends.org/

工程化的乌托邦——规范化

我们前面已经提到过一些古老“法典”,如jquery时代模块定义的规则、css规范的规则,还有前面没提到的项目结构划分、代码书写规范。 大家有没有发现它们都在历史的舞台中消失或者说们不必在为规范的实现耗费精力。为什么?当一个“法典”的受管控者和执法者都是自身的时候,那法典也就成了空谈。所以我们需要一个公正的执法者——机器(自动化)。

终会让项目wiki消失的自动化

代码规范,我们拥有jslint帮我们校验,有编辑器插件帮我们根据规范自动格式化。
项目结构,我们有对应的CLI帮我们生成。
模块的定义,我们有框架帮助划分解决运行时问题,有webpack帮助解决加载问题,等等。
自动化并非真正让规范消失,而是对规范的更加强制化和易实施化,达到“无约”自制的效果。
那些wiki里规范让开发者要怎么怎么写代码的文章我觉得大可不必,话说:“能动手的不BB,能自动化的不文档”。
而对于项目wiki里那些让开发者如何与其它人合作写代码的文档我也觉得大可不必。比如:我们与后端如何对接,我们可以使用YAPI这类工具,让前后端对接口定义及数据结构一目了然和保持实时稳定性。
对于前端与前端之间如何互相调用模块或组件,我们可以利用typescript,让模块组件接口更加清晰和强类型带来的稳定性。
对于强类型带来的其它好处我举个例子:
这个是我写无ts的vue项目时一个很低级的bug


export default {
    props: {},
    data() {
        return {
            isFullscreen: false;
        }
    },
    methods: {
       toggle() {
           this.isFullScreen = true;
       }
    }
}

看似是个大小写问题,但完全是可以避免,如果这个组件是个强类型,IDE(支持ts的)会推断this类型,该字段是否声明过给予校验提示。这个是书写上的带来的好处。强类型还给我们带来很多好处与方便,比如可以很快的了解一个模块提供的API。可以在多模块引用同一个数据时,某个时期对该数据结构进行一定调整后,能立刻知道那些陈旧的代码哪些需要随着这次改动一起调整等等。

除此之外TS还能在自动化文档上起到辅助作用。我们可以看一下Angular的文档自动生成工具有多棒~
https://compodoc.github.io/co...
demo: https://compodoc.github.io/co...

未完待续...

当我们站在巨人的肩膀上时,从未觉得向前走一步是如此轻松...愿,未来的前端走得更轻松。

来源:https://segmentfault.com/a/1190000017797540

原文地址:https://www.cnblogs.com/qixidi/p/10245480.html

时间: 2024-11-06 07:20:52

前端框架的工程化之路的相关文章

Hybird框架UI重构之路:五、前端那点事儿(HTML、CSS)

上文回顾 :Hybird框架UI重构之路:四.分而治之 这里讲述在开发的过程中,一些HTML.CSS的关键点. 单页模式的页面结构 在单页模式中,弱化HTML的概念,把HTML当成一个容器,BODY中显示的主体内容才是页面,一个HTML容器中可以存放1个或者多个页面,每个页面放置于section中.而一个页面(section)中必有主体内容(content),也有可能包含头部内容.底部内容,甚至一些侧滑菜单等. 所以,以我们通常看到的一个移动应用的界面中包含了顶部Title和主体内容的页面代码如

Hybird框架UI重构之路:六、前端那点事儿(Javascript)

上文回顾 :Hybird框架UI重构之路:五.前端那点事儿(HTML.CSS) 这里讲述在开发的过程中,一些JS的关键点. 换肤 对于终端的换肤,我之前一篇文章有说了我的想法. 请查看:http://www.cnblogs.com/lovesong/p/4122262.html iscroll的问题 1.使用iscroll的页面里面有表单元素,当键盘弹出再缩回后,页面拖不到最顶地方. 这个在android上总出现,使用的iscroll版本是4.2.5. 这原来是个很棘手的问题,导致了有input

现在算法是新锐前端框架成功的重要因素

随着前端MVVM的流行,小型框架现在越来越难存活了!react, angular等打着大公司旗号的框架占了半壁江山,而avalon以其良好兼容性在国内份额不断上升. 前端也与后端一样,遵循马太效应,强者愈强,弱者愈弱.最后只剩下两种框架,不断被人发现BUG的框架与没有人用的框架.MVVM本来就是一种非常复杂的分层架构.计算属性就用了半数的Gof设计模式,双向绑定则绑定6,7种DOM事件(像angular,avalon为了兼容IE6,数量达10以上).但尽管这么复杂,只要使用者察觉不到,用得爽,对

Hybird框架UI重构之路:四、分而治之

上文回顾:Hybird框架UI重构之路:三.工欲善其事,必先利其器 上一篇文章有说到less.grunt这两个工具,是为了css.js分模块使用的.UI框架提供给使用者的时候,是一个大的xxx.js.xxx.css,但在开发时候,必须划分模块. CSS模块划分 1.variables.less 这里面是一些样式的变量.函数 例: 字体: @baseFontSize: 20px; 圆角: .rounded-corners (@radius: 5px) { border-radius: @radiu

Hybird框架UI重构之路:一、师其长技以自强

这两年在支撑公司的Hybrid框架的运维发展,让人确认这种移动开发方式确实是一条不错的路.混合应用这种开发方式降低开发难度,极大的提高开发效率,最重要的一点效果可以接近原生应用.框架的本身是需要持续不断发展的,这里开始我讲述我重构Hybird框架的UI的这三个月(2014-11——2015-1),而在重构之前,预先调查了目前所了解的几个混合应用的框架,师其长技以自强. PS:Hybrid应用是web页面与原生壳(Android.IOS)的结合最后打成安装包的应用. 重构的前奏曲: ApiClou

如何选择前端框架:ANGULAR VS EMBER VS REACT

最近一段时间是令前端工程师们非常兴奋的时期,因为三大Web框架陆续发布新版本,让我们见识到了更强大的Web框架.Ember2.0在2个月之前已经发布,从1.0升级到2.0非常简单.几周之前React发布了0.14版本.还有很多流行的前端框架,像Backbone .Knockout及Aurelia.如果你想开发一个Web app,建议采用Angular,Ember或React三种框架中的一个.这三个框架可以说是安全级别最高,技术非常成熟的框架,而且有很多技术社区支持.所以你又开始纠结了,开发Web

一名优秀的Web前端工程师的成长之路

我所遇到的前端程序员分两种: 第一种一直在问:如何学习前端? 第二种总说:前端很简单,就那么一点东西. 我从没有听到有人问:如何做一名优秀.甚至卓越的WEB前端工程师. 何为:前端工程师? 前端工程师,也叫Web前端开发工程师.他是随着web发展,细分出来的行业. Web前端开发技术主要包括三个要素:HTML.CSS和JavaScript! 它要求前端开发工程师不仅要掌握基本的Web前端开发技术,网站性能优化.SEO和服务器端的基础知识,而且要学会运用各种工具进行辅助开发以及理论层面的知识,包括

为什么要学习Vue——前端框架角度

什么是框架 框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种定义认为,框架是可被应用开发者定制的应用骨架.前者是从应用方面而后者是从目的方面给出的定义. 可以说,一个框架是一个可复用的设计构件,它规定了应用的体系结构,阐明了整个设计.协作构件之间的依赖关系.责任分配和控制流程,表现为一组抽象类以及其实例之间协作的方法,它为构件复用提供了上下文(Context)关系.因此构件库的大规模重用也需要框架. 构件领域框架方法在很大程度上借鉴了硬件技

前端框架相关

WebMIS 基于CI的PHP免费开源框架 http://www.ksphp.com/docs/WebMIS/other_chart.html Bootstrap 简洁.直观.强悍的前端开发框架,让web开发更迅速.简单. http://www.bootcss.com/ 前端开发框架对比 http://www.ibm.com/developerworks/cn/web/1404_wangfx_jsframeworks/ H-ui概述 - H-ui前端框架官方网站 http://www.h-ui.