分享狼叔关于《大前端工程化的实践与思考》

前言

本文来自极客前端训练营的主题公开课,非原创。html

做者简介

桑世龙(狼叔),阿里巴巴前端技术专家,nodejs《狼书》做者。前端

快速发展的大背景

前端发展太快了,在2004年以前,大概只要会网页三剑客(一套强大的网页编辑工具,最初是Macromedia公司开发的,由Dreamweaver、Fireworks、Flash三个软件组成)就很牛了,那时候前端还比较“纯洁“。在进入以Ajax为表明的异步刷新改进用户体验的Web 2.0时代后,开始涌现出大量的库,好比Prototype、jQuery、MooTools、YUI、Ext JS、kissy等,它们都还只是对浏览器兼容性和工具类函数的封装,但是从Backbone、Angular 1.x相继出现后,前端就开始热闹起来了,出现MVC、MVVM、IOC(控制反转,Java著名框架Spring里的概念)、前端路由(相似于Express、Koa等框架的路由)、Virtual DOM(虚拟DOM,经过DOM Diff算法,减小对DOM操做)、JSON API(接口规范)、JavaScript Runtime(Coffee、Babel、TypeScrpt)等等,各类框架格式如雨后春笋同样冒出来,之前可能半年甚至更长时间才出一个框架,如今可能几周就有新的框架诞生,前端进入了空前的爆发阶段。node

图解2004-2016变化

image.png

前端经历过的几个阶段

如今前端开发也复杂到了必定程度,对比以前的开发方式,能够称为现代Web开发。这里我来作一个总结,前端发展经历了4个阶段:
1.HTML/CSS/JavaScript(基础)
2.jQuery、jQuery UI、Ext JS(曾经流行)
3.Backbone(MVC)、AngularJS、Vue.js(曾经流行)
4.组件化React、Vue.js(流行趋势)react

目前前端的发展状态

目前整个大前端还属于发展期,没有造成固定模式,因此从趋势上看是上升期,复杂、混乱、多样性的结果也致使如今的前端比较吃香,被你们戏称为“钱端”。不少同窗会问,学习前端技术是采用渐进式方式,仍是上来就直接学React/Vue.js等框架呢?实际上,我认为这两种方式都存在,若是有经济压力就向“钱“看,能够直接学习React/Vue.js等框架,但学会了以后,必定要把其余3个阶段补充学习完;若是没有经济压力,又有时间和耐心的话,按部就班的学习是最好的方式。编程没有捷径,不管是哪一种,都须要脚踏实地多多练习。webpack

当你代码写多了,就会发现:
当你们HTML写烦了,开始引入模板引擎。
当你们CSS写烦了,好比不支持嵌套,开始引入CSS预处理器SASS、Less、Stylus、PostCSS等。
当你们JavaScript写烦了,开始引入更友好的语言,熟悉Ruby的使用CoffeeScript、熟悉Java/C#的使用TypeScript。git

因而,前端开发变得复杂,并进入现代Web开发时代。github

image.png

nodejs

对于Node.js来讲,全部前端框架都是视图层(View)的展示技术而已,能够很是方便地和各类框架集成,并按照业务需求予以更好的实现。另外,全部的前端框架都采用Node.js和NPM做为辅助开发工具,使用了大量Node.js模块,但前端框架使用的模块大同小异,若是熟练掌握了Node.js和NPM,对于学习前端技术来讲,你要学的只是纯前端的部分而已,复用价值很是高。web

和Node.js相关的前端开发模块实在是太多了,这里简单列举一些:算法

image.png

由这些模块,也就引出了咱们今天要聊得话题——大前端工程化实践与思考。express

构建工具

先来讲说构建工具。预处理器是前端高级玩法。

image.png

我常常开玩笑说之前HTML/JavaScript/CSS的时代太纯洁了,如今随便写哪样都要编译/转译。好处是能够借助高级特性,提升开发效率;缺点也是极其明显的,就是人脑要有转换思惟。这实际上是蛮痛苦的,原本HTML/JavaScript/CSS就不够熟练,再转一次,对于新手来讲须要一个适应过程。因此这件事仍是要辩证地看,福祸相依。

提及构建工具,大概都会想到Make、Ant、Rake、Gradle等,其实Node.js世界里有更多实现。

image.png


构建工具的源码都不是特别复杂,因此Node.js世界里有很是多的实现,还有人写过Node.js版本的Make呢,玩得很嗨!

选用构建工具最主要的目的是为了自动化。对于须要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具能够减轻你的劳动,简化你的工做。尤为是工程越复杂,自动化的价值就越大。这里的编译包含模板、CSS预处理语言、JavaScript友好语言等编译,在源码编写时用的是高级玩法。

除了编码编译外,还有测试、代码风格检查、上线前优化(合并、压缩、混淆),能够说,构建系统在整个软件工程里无处不在。

grunt


Grunt是前端领域第一个流行的DSL(领域定义语言)风格的构建工具,它的出现对于前端工程化起到了很是好的引导做用。它经过Gruntfile来描述task,同时经过插件机制来扩展各类工程能力。
当你在Gruntfile文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工做。

Grunt除了配置复杂外,还有一个问题就性能,可能不少同窗遇不到性能问题。Grunt是读写文件的,因此在多文件、大文件处理时是有性能瓶颈的。

Grunt的设计仍是挺精巧的,但配置起来让人抓狂,天然会有不少不爽的人,因而Gulp就慢慢崛起了。

Gulp

简单来说,Gulp是一个Node.js写的构建工具,基于Stream的流式构建工具,它包含大量插件。Orchestrator是Gulp底层依赖的task相关的核心库,它定义了task执行方式和依赖,并且支持最大可能的并发,Gulp的高效即来源于此。自己Stream对大文件读写就很是棒,再加上上面说的种种特性,使得Gulp流行成为必然。

Gulp的应用场景很是广,前端项目或Node项目均可以使用,哪怕是webpack也能够和Gulp搭配使用,经过gulp-webpack模块便可。若是想深刻学习Gulp,能够看一下stuq-gulp(github.com/i5ting/stuq…),文中以WeUI里Gulp用法为例,由浅入深,从用法到原理进行了阐述。

模块化

解耦是软件开发领域永恒的主题,而模块化是目前最好的解耦方式,因此从无到有、从有到成熟的演化,必然要经历很长的路。现在的发展,源于1993年HTML建立、1995年诞生JavaScript、1996年发布CSS1,以后就进入了原始而野蛮的开发阶段。从互联网诞生到2000年泡沫破灭,Web技术才算真正崛起。那时候特别纯洁,会写的人就很牛了,以后Flash也曾超级火爆。在以后就到了Web 2.0时代,开始出现Ajax,开始有了各类兼容浏览器的库,而后开始模块化,在2009年诞生了Node.js,完全改变了JavaScript以及前端开发领域的开发方式,从浏览器端的Backbone支持MVC模式,到AngluarJS支持的MVVM,到如今的React/Vue和webpack等。

这里我尝试从更宏观的视角来进行归类,大体分5个阶段,分别是原始阶段、包管理器、模块规范、模块加载器、模块打包器。下面我来一一说明。

原始阶段

脚本加载还都比较原始,方式以下:使用多个script标签加载、手动管理顺序、手动管理加载哪些。

在Web开发里通过了不少尝试,也作过不少龌蹉的事儿,好比
动态建立Script标签XHR Eval、XHR Injection、$.getScript()、 Script in Iframe、Script DOM Element、Script Defer。

若是说加载比较恶心,那么脚本顺序更恶心,并且JavaScript有个“特性”,一处报错,全部后面的都会崩溃,因此开发会很苦的维护脚本加载的顺序。

包管理器


若是代码存在一个问题,更新jQuery UI版本怎么作呢?jQuery UI依赖jQuery,先下载jQuery UI代码,而后找到依赖的jQuery版本,再替换已有文件,以后测试,若是没问题就直接替换了。

很明显,直接进行文件操做是很是低效率的作法,对于版本、依赖都无法作更好的处理。因而就出现了Bower、NPM等包管理器,全部模块升级,依赖都有包管理负责,能够说很大程度上省去了前端的重复性工做。

模块规范

模块化加载的本质是按需加载。
比较常见的规范有3个:(1)AMD、CommonJS和ES6 Modules;(2)使用标准的模块系统来处理依赖和导出
每一个文件是一个模块;(3)使用模块加载器或打包器进行处理

模块加载器

模块加载器须要实现两个基本功能:
1 实现模块定义规范,这是模块系统的基础
2 模块系统的启动与运行

常见的好比RequireJS、Sea.js和SystemJS。以AMD的模块加载器RequireJS为例,一般使用RequireJS的话,咱们只须要导入RequireJS便可,不须要显式导入其余的JS库,由于这个工做会交给RequireJS来作。

模块打包器


模块加载器提供运行环境,可以让遵照模块规范的代码在上面跑,因此模块化的好处是很明显的。但对于真实项目来讲,你还须要构建、打包等操做。

对于开发来讲,只须要关注业务模块,不须要了解模块加载器和构建过程,很明显这是很是理想的,也所以产生了webpack这样的模块打包器。

Gulp做为通用构建工具,它已经很是完美了。但技术变革太快了,应用各类预处理器、前端组件化,致使前端无比复杂,而webpack的出现刚恰好,完美解决了前端工程化的问题。

webpack基本介绍

webpack是Node编写的著名模块,是打包器(bundler),不仅是支持CommonJS模块,并且还支持更潮的ES6模块,是目前使用极其普遍的打包器,像前端组件化的框架(React、Vue)大多都是使用webpack的。

loader && plugins

它提供了两个极其好的机制:loaders和plugins。

loaders:webpack认为每一个文件都是资源模块,针对打包构建过程当中用来处理源文件的(JSX、SCSS、Less..)统称为loader。

plugins:插件能够完成更多loader不能完成的功能。插件并不直接操做单个文件,它直接对整个构建过程起做用,大多数内容功能都是基于这个插件系统运行的;固然还能够开发和使用开源的webpack插件,来知足各式各样的需求。好比知名插件autoprefixer、html-webpack-plugin、webpack-dev-middleware、webpack-hot-middleware。

webpack打包过程


(1)从配置文件里找到entry point
(2)解析模块系统
(3)解决依赖
(4)解决依赖管理(读取、解析、解决)
(5)合并全部使用的模块
(6)合并模块系统的运行时环境
(7)产生打包后的文件

浏览器加载过程

(1)经过<script>加载webpack打包后的文件
(2)加载模块运行时环境
(3)加载entry point
(4)读取依赖
(5)解决依赖
(6)执行entry point

若是对比着理解webpack打包过程和浏览器加载过程,能够对前端模块化的演讲过程可以有更好的了解。从定义模块规范,到模块化系统的运行时环境(加载器),再到更高级的打包器,这个演进的过程,也让前端开发愈来愈简单,这才是打包器愈来愈火爆的缘由。

理解webpack的功能

image.png

事实上从结果来看也是这样的,工程化最终目的是让开发者专一于写业务模块,其余的事情让打包器来作。从这个角度讲,webpack仍是比Gulp更成功。

可是webpack学习曲线也是比较陡峭的,以点打面、不断深究,是很是好的学习方式。从基本用法、概念,到tree-shaking、code spit,再到如何打包、浏览器如何解包,到工程化,到大规模构建如何优化,考验你的是基础是否扎实、原理是否真懂、是否了解优化思路和源码。做为相似模块与Gulp进行对比,到Stream(Gulp核心),到event(Stream基类),到HTTP(Stream在HTTP里应用),到eventloop,到C++实现的libuv和v8,太可怕了,几乎把《狼书》的全部内容都涵盖了。

webpack构建大型项目

webpack封装


关于webpack 的封装实践有不少,好比知名的af-webpack、ykit、easywebpack。

af-webpack是支付宝定制的webpack,把webpack-dev-server等Node.js模块直接打包进去,同时对配置作了更好的处理,以及插件化。

ykit是去哪儿开源的webpack,内置Connect做为Web server,结合dev和hot中间件,对于多项目构建提效明显,对版本文件发布有不错的实践。

easywebpack也是插件化,但对解决方案如boilerplate等作了很是多的集成,好比egg的ssr是有深刻思考的,尽管我不赞同这种作法。

CRA和UMI


框架和基本探索稳定后,你们就开始想如何更好地使用、更简单地使用。各家大厂都在前端技术栈思考如何选型和下降成本,统一技术栈。

在Create React App(CRA)项目里使用的是react-scripts做为启动脚本,它和egg-scripts相似,也都是经过约定,隐藏具体实现细节,让开发者不须要关注构建。

UMI和CRA相似,它是一套基于蚂蚁金服技术栈总结的最佳实践,是一套零配置“约定高于配制“,开箱即用,按最佳实践进行开发的前端框架:React全家桶 + dva + jest + antd (mobile) + less + eslint。
UMI核心是chainwebpack,将webpack复杂的配置插件化,可以让多项目之间自由切换,消除各类webpack配置问题。

UMI思考得相对全面,从技术选型、构建,到多端输出、性能优化、发布等方面进行了拆分,使得UMI的边界更为清晰,做为前端最佳实践没啥毛病,目前大多数前端组也都是相似的实现方式。说白了就是现有技术栈的组合,封装细节,让开发者用起来更简单。在将来,相似的封装还会有更多,毕竟框架层面创新不那么多,你们就会将精力慢慢转到应用层面。

脚手架

cli参数处理


早期比较有名的是Commander,做者是TJ,实际上是Ruby迁移到Node的版本,著名的express-generator就是基于这个模块编写的脚手架。

它的问题在于包的依赖有点大,对于强迫症开发者来讲接受不了。因而Yargs这类的模块应运而生,强大且依赖极少。

模板方式


Yeoman是著名的脚手架模块。经过安装模板,在yo命令上进行扩展,很明显这是中心化思想的结果。优势是开发难度小,对于工程化收敛是有帮助的。

git仓库作模板


模板虽好,但仍是有点麻烦。若是模板放到Github上,更新维护都很是方便。比较典型是Vue CLI(以前版本)、saojs。

核心是ownload-git-repo,而后对里面的文件进行模板处理。这种方式的灵活度很是高,是目前比较主流的方式。
总结一下,脚手架是在一步一步的演进,但总体来讲,除了在工程化收敛上作了些优化,其余并无特别大的优化,缘由很简单,脚手架的复杂度作不上去。相似UMI够复杂吧,但CLI部份内容并很少,也不须要特别灵活的配置。
关于如何用Node构建脚手架,其实用Node.js写生成器是件很是简单的事儿。你能够参见《零基础十分钟教你用Node.js写生成器:你只须要5步》(github.com/i5ting/writ…)。

将来的端渲染和构建


下面看一下前端的演变过程:
最初的Java、PHP时代的纯服务端渲染时代。

先后端分离,即便用JavaScript运行在客户端,经过请求获取服务端接口数据,借助如JQuery、Angular、React、Vue等前端框架操做或生成页面DOM,充分利用客户端资源,减小服务端压力,先后端分工明确,一直到如今还是最经常使用的开发方式。

同构开发,如Meteor、Next.js、Nuxt.js等框架,都提供了不一样的适用场景和开发方式,但目的都是为了同一套代码能同时应用于服务端和客户端。

ssr的演变过程

JSP/ASP都算,固然Node渲染模板也算,Node世界模板最为丰富。

BigPipe,虽然很老了,但分块传输优势是很是明显的,且对浏览器友好。Facebook和微博、去哪儿都是受益者。Node自然支持,对res.write很友好。

基于组件写法的SSR,好比React SSR。时代变了,SSR也要跟上。vdom + hydrate玩的能够很嗨,连BigPipe也能够结合起来。UMI SSR和Rax SSR将来可期。

真正的同构,即CSR和SSR写法一致,将来再也不区分概念,在Servless里,API和渲染都是函数。
近几年前端技术的变化可谓翻天覆地,在选择技术栈以前应该看清本身的应用场景,没有最好的框架,只有最适合应用场景的框架,同构开发方式也不例外,下面我介绍一下使用同构开发的优势和须要注意的问题。

举一个项目的例子, github.com/ykfe/egg-re… 。它的写法是:

image.png

核心要点有:
render是React的视图渲染方法
getInitialProps是获取数据方法,将返回值赋值给组件状态
CSR经过高阶组件实现
SSR经过Node执行

image.png


CSR,其实须要开发者关心React和webpack构建
Beidou是SSR解决方案,开发者关心React、egg和webpack构建
UMI SSR得益于UMI内置webpack,因此开发者只须要关注React编写便可,部署到egg上。

在将来,咱们但愿全部服务都走Serverless,这样用户只须要关注React写法便可。构建是本地作的,相似于UMI。egg不须要关系,由于走的是Serverless的运行时环境。

CSR和SSR写法一致,又能够上Serverless,它的优势有:
C端应用,直接SSR,能够提效,性能有保障,SEO友好。
中后台应用,采用这种方式能够提效,下降开发难度和代码维护难度。每一个页面都是独立的,系统再造也是极其简单的。

上了Serverless以后,除了本地CLI构建外,还能够提供云构建。好比每一个页面都是函数,那么多个页面如何合并呢?好比UMI典型的多页应用,经过react-loadable+react-router实现的代码按需加载,这种状况就能够先在Serverless上发布多个页面,继而在云构建上,配置多个页面,最终构建成一个多页应用。

另外,渲染层作轻,对于将来上Web IDE也是有极大便利的。能够畅想一下,将来有个流程就能够完成开发,是否是很美好?阿里将Serverless和IDE做为两大方向,确实是很是用心的考虑。

先后端协做

以后咱们来聊聊先后端协做。前端原本的定义是指基于浏览器作开发的,随着浏览器应用范围愈来愈广,前端的界定也愈来愈模糊。目前前端已经涵盖PC、H五、移动端组件,几乎是全部和用户接触的带界面的都算前端,因此才有了大前端的概念,泛指全部和用户交互的终端开发。

一直以来,跨浏览器(Web View)都是开发领域折腾的方向,从Native到Hybrid,到React Native/Weex,再到Electron、PWA、小程序,你能看到你们都在往轻量级走,统一技术栈,下降成本。也就是说,端上但愿统一,又之前端为开发核心,故而统称为大前端。

JavaScript已横跨三端,再说一下Node,覆盖工程化和服务端能力。不少大公司移动端和前端已经合并一个组进行管理,大前端局面已成定局。

先后端分离

先后端分离,即便用JavaScript运行在客户端,经过请求获取服务端接口数据,借助如JQuery、Angular、React、Vue等前端框架操做或生成页面DOM,充分利用客户端资源,减小服务端压力,先后端分工明确,一直到如今还是最经常使用的开发方式。

BFF

BFF(API Proxy),独立的API层的出现缘由有不少:

移动端兴起,你们都开始面向API开发,但却忽略了大前端不仅只有移动端,还有PC Client和PC/H5 Web。主要是屏幕大小不一样而致使UI/UE上有明显差异。

后端开发API的时候,不喜欢同时维护多套API。

除了沟通成本,还有对前端实现不了解而产生的误解。

简单理解,BFF就是各端的API独立提供了。可是,这样作很明显不经济。那么,是否是要把架构升级一下呢?
因而,分开的BFF变成了一个统一的服务器端API服务。这就和Ajax原理同样,由于多了一层XHR,致使先后端能够异步处理,促使了Web 2.0的诞生。BFF升级为统一的服务器端API服务,其实也是同样的,让前端和后端能够异步开发,各自作各自的工做,全部API都注册到API层就行了。这实际上是前端架构上一次很是大的升级。

GraphQL

GraphQL是Facebook于2012年在内部开发的数据查询语言,在2015年开源,旨在提供RESTful架构体系的替代方案,既是一种用于API的图表化(可视化)查询语言,也是一个知足你数据查询的运行时。

传统Web应用经过开发服务给客户端提供接口是很常见的场景。而当需求或数据发生变化时,应用须要修改或者从新建立新的接口。长此之后,会形成服务器代码的不断增加,接口内部逻辑复杂难以维护。而GraphQL则经过如下特性解决这个问题:

声明式。查询的结果格式由请求方(即客户端)决定而非响应方(即服务器端)决定。你不须要编写不少额外的接口来适配客户端请求。

可组合。GraphQL的查询结构能够自由组合来知足需求。

强类型。每一个GraphQL查询必须遵循其设定的类型才会被执行。

也就是说,经过以上的三个特性,当需求发生变化,客户端只须要编写能知足新需求的查询结构,若是服务端能提供的数据知足需求,服务端代码几乎不须要作任何的修改。

GraphQL经过模型定义,对先后端都很是友好,无疑是一种很是好的解决方案。固然,它也有问题,约定自己就不是件容易的事儿,另外对于先后端成本仍是有的。

Serverless


那么,如何可以让前端真正解放呢?一不关心运维,二不关系扩容,三不关心Web框架。对于前端开发者而言,我只是想要个接口,或者是包装一个接口,为何必定要了解Node Web框架呢?

Node.js成也Eventloop败也Eventloop,自己Eventloop是黑盒,开发将什么样的代码堆进去你是很难所有覆盖的,偶尔会出现Eventloop阻塞的状况,排查起来是极为痛苦的。

利用Serverless,能够有效防止Eventloop阻塞。好比加密是常见场景,但自己执行效率是很是慢的。若是加解密和你的其余任务放到一块儿,是很容易致使Eventloop阻塞的。

本地开发一个函数,而后经过CLI发布到Serverless云上,一切都那么简单,必然是将来趋势。

能够看下面这张图。

image.png

前端工程化将来的理解


CRA、UMI让咱们不关心webpack配置,这是本地CLI的将来。

CSR和SSR统一,同构开发,本地CLI打包构建,发布到Serverless云上,简单高效。

API基于Serverless极其简单,不须要了解Web框架,简单组成API便可,无运维,不怕高并发场景。

这里要提一下,在Serverless这种大环境下,若是API解决了,前端天然是能够作全部业务的。前端能作的事儿愈来愈多,将来前端应用层也会更多。

将来随着经济和业务发展,好比会有更多应用也会更多端,对前端来讲是好事,由于能作的更多,价值就可以获得很是好的体现。

因此做为一个坚决的Web信仰者,我相信将来前端的前景一片大好。

更多

原文语雀链接:www.yuque.com/robinson/fe…

若是你想了解更多关于前端工程化的文章,欢迎关注个人语雀专辑,持续收集整理中:www.yuque.com/robinson/fe…

申明:本文是在掘金平台写的最后一篇文章,之后都转移到语雀和博客了。

相关文章
相关标签/搜索