前言
现代的前端开发,框架帮助我们做了许多的事情,我们只需要通过一行命令就可以生成一个符合工程化的项目,借此我们可以进行快速开发。本文想通过前端工程化的进程来帮助大家理清到底是怎么回事。从一开始的静态页面,html,css,JS这前端三板斧。到后面的jQuery这个函数库之后就直接跳到了vue,react等现代MVVM框架。在后面学习的过程中感觉非常的疑惑,.vue文件是什么鬼?为什么在一个.vue文件中写一些hmtl和js,浏览器就能实时渲染出效果来,浏览器不是只认识.js文件的吗?今天就带着这些问题来聊一聊前端工程化的前世今生。
一、青铜时代:前后端不分离
在web1.0时代,早期的网页开发基本是由后端所主导的,因为当时的浏览器性能弱,标准化程度低,导致前端能做的事情很少。那时候的前后端是不分离的,一般都是由美工出好了图,前端切图以及还原设计图为一个静态网页的模板交给后端,由后端负责最终的渲染,俗称切图仔。
MVC模式
以后端为主导的时代,遵循的是后端的MVC模式。前端只负责View层的实现。
经典MVC模式中,M是指业务模型,V是指用户界面,C则是控制器,使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式。其中,View的定义比较清晰,就是用户界面。
MVC示意图:
当时的前端页面是借助JSP等技术来实现的,本质上还是由后端渲染前端的文件,例如HTML,在.JSP文件当中能使用Java变量,在编译阶段往页面中注入Java变量来实现。例如:
<html>
<head><title>An Include Test</title></head>
<body bgcolor="white">
The current date and time are
<%@ include file="date.jsp" %>
</font>
</body>
</html>
date.jsp
<%@ page import ="java.util.*" %>
<%= (new java.util.Date()).toLocaleString() %>
以上代码通过编译后产生的页面会在浏览器中展示如下类似的信息:
The current date and time are
Aug 30,1999 2:38:40
而里面的<%@ page import ="java.util.*" %>,<%= (new java.util.Date()).toLocaleString() %> 是JSP的include指令。大致如此,当时存在的问题:因为前端只负责模板界面的编写,以及前后端不分离,导致修改起来十分的困难。需要前端调试好了之后再由后端进行打包、编译、发布。随后再由前端进行验证,这导致了开发效率低下,沟通成本高的问题。
二、白银时代:Ajax的到来
在后端主导的时代,往往需要通过刷新整个页面的方式来获取最新的数据,在用户交互体验的立场上是非常糟糕的。
时间来到了2004年,Google先后发布了Gmail和Google Map两款web产品。这两款产品都大量使用了Ajax技术,不需要刷新页面就可以使得前端与服务端进行网络通信。
Ajax即Asynchronous Javascript And XML(异步JavaScript和XML)在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合的‘新’方法,包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的
XMLHttpRequest。使用Ajax技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面,这使得程序能够更快地回应用户的操作。
随着Ajax的流行,前端从web网页迈向了web应用,标志着web2.0时代的到来。在Ajax的帮助下,前后端分离的时代到来了。
前后端分离
前后端的分离,使得前端后端工程师的分工明确了起来:前端工程师负责UI的还原以及用户的交互,后端工程师负责数据的支持,而他们交互的节点在接口。这也使得很多逻辑转移到了前端,前端工程师终于站了起来。
虽然现在已经实现了前后端的分离,但是新的问题出现了。随着浏览器性能的提升以及普及,前端在web应用中扮演着越来越重要的角色。前端需要负责更多的业务逻辑以及UI渲染,越来越复杂的交互逻辑使得前端的代码越来越重。
众所周知,JavaScript是一种解释型的脚本语言,当时JS中没有模块化。随着项目越来越大,前端代码的维护也变得越来越困难。想象一下,各种JS文件共享一个全局环境,在多人开发的场景中是多么的让人头皮发麻。虽然可以通过语法层面进行约定封装,比如使用 Script 标签、目录文件的组织、闭包、IIFE、对象模拟命名空间等方法,但是还是治标不治本。有问题就需要去解决问题,所以模块化它来了。
三、黄金时代:Node的问世
2008年谷歌问世V8引擎,2009年,美国程序员Ryan Dahl基于谷歌的V8创造了Node.js,这是一个JavaScript的运行环境,可以使得JS跑在服务端。而Node采用了CommonJS模块化规范。至此,前端开发迎来了一个蓬勃发展的时代,也进入了属于前端的黄金时代。
而在当时前端原生语言和浏览器还不支持模块化的时候,如何在前端项目中使用模块化呢,这就引出了前端的打包工具webpack,Rollup等。本文重点介绍下webpack。
webpack
webpack是基于node.js的一个前端打包工具。有了webpack我们便可以做很多事情,工程化的模块化、组件化、规范化、自动化都可以借助它实现。要使用webpack,需要电脑安装node环境,node相当于Java的jvm。那么,webpack到底做了什么呢?
如上图所示,我们可以使用webpack进行打包、编译、合并各种文件,最终生成浏览器认识的css,js,png等文件。有了webpack和npm这个包管理工具,我们可以轻松的基于模块化开发。
那么webpack是如何把各种不同类型的文件转换成浏览器能识别的.js、.css等文件的呢? 它是通过loader来转换各式文件的。前面提到过的.vue文件,就是通过一个叫vue-loader的函数转换成JS文件的。而各种各样的文件需要各种对应的loader来进行转换,常用的有sass-loader,url-loader等。
那么webpack又是怎么把转换好的文件按照预定规则生成dist文件夹的呢? webpack在运行时生命周期会广播出来一些事件,plugin监听这些事件,在特定的阶段执行自己的插件任务,从而实现插件的功能。
在浏览器(现在高版本谷歌浏览器已经支持模块化了)以及JS语言本身还不支持模块化(ES6之前没有ES6Module支持)的条件下,webpack又是如何实现模块化的呢? 带着这个问题,我们来看一下前端工程化在webpack等打包工具中的体现。
工程化的体现
1. 模块化: webpack是通过模拟module,exports,require等变量,将我们的模块代码打包成一个文件,让浏览器可以运行我们的模块代码。通俗的讲就是webpack把我们的每个文件当作一个个模块,包上了一层函数,入参是module,exports,require等变量,在每个模块被加载时缓存一份module.exports到cache中来实现的。具体是如何实现CommonJS的,后续会另写一篇文章来详细介绍。webpack可以帮助我们转换各种模块化提案,如CommonJS、AMD、CMD等,后续ES6的ES6Module也可以通过webpack在不支持模块化的浏览器中实现。
webpack的模块化实现基于缓存,如果一个项目的模块太多,会导致其编译、打包时间过长,启动会变得很慢,打包时间也会变得很长。所以现在出现了基于ES6Module的新的打包工具vite,点击这里可以看下本人写的基于vite2.x+vue3搭建项目,并使用jsx开发的一个项目,感兴趣的同学可以去看看。
2. 组件化: 在开发过程中,会遇到反复出现的UI,他们的功能都是一样的,比如导航栏,通用的按钮组件等。如果在每个页面都写这样的代码,岂不是要累死人?模块化是从文件层面上对代码或者资源的拆分,而组件化是更细分到了业务层面。所以可以把这类每个包含模板(HTML)+样式(CSS)+逻辑(JS)功能完备的结构单元给抽出来封装成为组件。就像组装汽车一样,如果每生产一辆汽车就从零件开始组装,那一定是非常低效的。所以可以借助组件化的思想,把轮胎、车窗、车门等抽取出来当作一个组件,流水线生产(代码复用),再进行组装,事半功倍。
3. 规范化: 软件开发的过程是一个多人协作开发的过程,因此规范化是非常重要的。目录结构、代码规范、文档、前后端接口规范以及提交日志等都需要制定一个规范。规范化其实是工程化中很重要的一个部分,项目初期规范制定的好坏会直接影响到后期的开发质量。
4. 自动化: 借助webpack等打包工具,我们可以实现自动化构建、自动化测试、自动化部署等功能。通过webpack-dev-server可以在开发环境编译、打包,它会生成一个dist静态资源文件夹,以及启动一个本地服务去访问它。我们可以轻松在本地就可以看到最终生成的页面效果。而通过HMR模块可以实现热更新,原理是webpack与页面建立了一个websocket服务,当编译器保存编辑后,会重新编译,并通过websocket来更新页面。前端自动化测试能够提高代码质量、减少人肉测试等。自动化部署也可以通过相关插件以及配置来实现。
MVVM框架
在现代出现了很多优秀的MVVM框架,如react,vue等。他们可以借助webpack进行编译、打包,给我们的开发带来的很大的改变。虚拟DOM的出现(通过JS对象去描述一个DOM对象),可以让我们以很小的开销去做DOM操作,因为操作一个真实DOM的开销是很大的(浏览器的DOM对象是一个很大的对象)。而借助react,vue等框架,我们可以借助它们规定的语法来轻松使用虚拟DOM,对于虚拟DOM后续也打算写一篇文章来着重介绍。
而相关的脚手架工具的出现,如vue-cli,能帮助我们快速的搭建一个符合工程化标准的项目。
只需要在本地下载一个全局npm包
npm install -g @vue/cli
# OR
yarn global add @vue/cli
通过一行命令vue create hello-world以及选择配置项就可以快速搭建一个项目,来帮助我们进行快速开发。而vue-cli脚手架是基于webpack的,它对webpack进行了二次封装,在这里就不展开了。
结语
前端发展日新月异,前端工程师所需要具备的技能也越来越多,在项目开发过程中也扮演着越来越重要的角色。在使用现代化的框架的同时,我们一方面感受到了它所带来的便利以及强大,另一方面我们也要知道它是如何工作的以及它的由来。如果本文有什么不对的地方或者是说的不够好的地方,欢迎各位小伙伴在评论区指出。