搭建清晰的前端技术体系

搭建清晰的前端技术体系

目的

如果你有以下类似的问题,那么本篇文章可能会对你有所帮助:

  • vue, react 框架?express, koa框架?这些都是前端开发常用的框架,都是啥作用?有啥区别?
  • javascript,typescript , ES6,CommonJS 还有node.js 这些都是啥关系?
  • node.js到底是干嘛的?node.js给前端带来了什么?
  • 为什么使用 webpack 打包工具?经常用到的babel是干嘛的?
  • 我知道module.export = {} 是CommonJS规范,export default 是ES6规范,怎么有的项目里两种都有呐?两种规范不会冲突吗?
  • … … 等等诸如此类的问题

本篇文章更多地是面向初学者或者已经有一定前端开发经验但是并未捋清前端众多技术之间的关系架构的开发者,本文将循序渐进将前端技术体系捋一捋,从整体上看看各个技术栈在前端技术架构中所处的位置以及发挥的作用,不会过多的深入讲解某一项技术栈。

若有阐述不妥当或错误的地方,敬请订正。若有疑问,欢迎交流。(一篇长文,但是如果你心中有以上疑问,希望耐心看下去,肯定会有一定收获)

前端技术架构解析

架构概览图

搭建清晰的前端技术体系
画图能力差,略丑,将就看看。

接下来我们将循序渐进,一点点的引出架构图中的各个技术,概念。

传统前端开发的问题

前端三大基石html,css,和javascript;html和css分别处理页面视觉内容和样式,而javascript则是处理交互事件,获取信息,操作DOM等。我们也经常使用到jQuery.js,bootsrtap.js等等js库,这些别人造好的*,我们直接拿来使用,大大的方便了开发,提升了效率;但是这种传统开发也有许多各方面的问题:

  • 页面视图,逻辑,数据揉杂在一起混乱,维护困难
  • 复用性低:页面中某一块反复用到的代码或者想要实现的效果只能通过粘贴复制来解决
  • 页面性能:传统库都是直接操作DOM,这相当消耗CPU,影响页面响应性能,降低用户使用体验
  • 开发效率:传统后端开发很多采用MVC架构,前后端耦合在一起,这样前端开发也必须搭建后端的开发环境,无疑大大增加了前端开发的难度;许多场景下前后端开发的分工也容易混在一起,交流成本更高等等,大大降低开发效率,这也是传统开发为人诟病已久的地方
  • … …

为什么出现vue,react等框架

为了解决上述视图,逻辑,数据揉杂、复用性低、页面性能差等等问题,vue,react等前端框架应运而生。为什么说他们解决了这些问题呐,因为它们:

1.落实组件化思想,提高代码复用率,降低维护成本
2.将视图,数据,逻辑分离;数据驱动,响应式更新视图,让开发者只需要关注数据
3.引入虚拟DOM,在绝大多数场景下大大降低了页面渲染耗时,提升了性能

vue,react 等就是javascript库,我们遵循它的规范开发,它就替我们做了很多事。本质上与jQuery,bootstrap等没有区别。

为什么出现Node.js

为了解决上述开发效率的问题,我们迫切需要将前后端分离,理性的前后端分离是:后端提供RESTful接口,前端实现web服务(来完成路由控制、缓存、日志、代理等等)、视图和交互(为什么说这样是理想的?这样以来,是不是前端已经不在乎后端是谁,甚至是对接多端,只要后端提供正确接口,即使后端换了一套代码,前端也无感知,实现真正的前后端分离。而反之如果不这样,比如:如果路由依然由后端控制,那么这即意味着页面渲染视图切换依然受后端控制,并没有实现前后端分离)。

为了达到这种理想效果,显而易见,我们需要一个web服务来做路由控制等一系列的事情;但是前端三大基石唯一看起来能做这件事的javascript只能运行在客户端浏览器上,难道前端开发人员还得学个其它的后端语言来做这件事,虽然也不是不可以,python,java这些也都可以,但是如果可以直接用javascript,那岂不是更好,无须增加其他技术栈,开发中遇到的问题也更少,效率更高。

为此,node.js横空出世,使得服务端运行javascript成为现实。

为什么node.js可以让服务端运行javscript?这就要简单说说node.js的原理,node.js是基于google的v8引擎开发的;那么v8引擎是什么?v8引擎就是Google的Chrome浏览器里的javascript引擎,负责页面中javascript代码的解释执行。说白了,node.js把v8引擎这个javascript执行环境从浏览器移植到服务器中,使得服务器可以运行javascript。

注意:虽然vue.js,react.js 和 node.js 都是 .js结尾,但是他们由本质的区别。node.js 是服务器程序,在服务器上提供javascript的运行环境,就像jvm为java提供运行环境。而vue.js,react.js 是javascript库,相当与java开发的一个第三方jar包。

为什么出现express,koa

现在环境有了,可是之前没用过javascript创建一个http服务。不用担心,*又有大佬们造好了,那就是express,koa等一系列node框架。这些框架能够帮你快速创建一个web应用,并提供丰富的 HTTP 快捷方法和中间件(妈妈再也不用担心你写不好一个node web服务了)。

例如app.js文件内容如下,执行node app.js安装好express),即可创建一个web服务;并且访问http://localhost:3000页面就会返回Hello World!,是不是超级方便。

//引入
var express=require("express");
//创建app应用
var app=express();

app.get('/', (req, res) => res.send('Hello World!'))
//监听
app.listen(port, () => console.log(`Example app listening on port ${port}!`))

所以现在清楚了:express,koa是node框架,用于构建web服务和API;而vue,react是javascript库,用于页面开发。

怎么安装express

你可能已经发现了前面说:如果javascript对应java,那么node.js就对应jvm,可是java安装三方包有Maven*仓库,那我要安装express,node.js是不是也有它的“Maven”?

当然有,那就是大名鼎鼎的npm,全名Nodejs Package Manager(Nodejs包管理器),顾名思义,不多解释。使用也相当简单:

# 全局安装,例如mac,会安装到:/Users/YourUsername/node_modules 下
npm install express -g 
# 局部安装,在当前目录的node_modules下
npm install express 
# 使用淘宝的源下载更快
npm install express -g --registry=https://registry.npm.taobao.org
# 卸载
npm uninstall express 

当然还有yarn包管理器,并行下载,下载速度更快,有缓存机制,版本锁定,看起来比npm更好,但是npm也在更新中加入版本锁定等,且在大多数情况都能给你不错的体验,所以具体用哪个就仁者见仁,智者见智了。

require(“express”) 引发的思考

为什么别人的代码,我下载下来后用个require(“xxx”)就能直接使用了?

这涉及javascript模块化,就像javaimport xxx, cinclude xxx.h,这些都是模块化的表现,javascript希望类似的方式来减小耦合,利于复用,方便开发和维护,利于分工。

模块化在浏览器端可以通过require.js,seaJS等来达到模块化的效果。

而在node.js的环境下,大家如果想要引入使用彼此写的javascript文件,就得遵从相同的规范。node.js里这个规范就是CommonJS。

CommonJS

这个require()CommonJS的模块规范的导入模块的API,使用它就可以引入其他文件的变量方法并使用。你会说等等:模块能理解,CommonJS何许人也?

CommonJS是一套规范,定义了一套在浏览器之外运行javascript的API和规范;而node.js正是CommonJS的实现,就类似java里的class实现了interface。例如nodejs的内置模块path(路径处理模块),fs(文件操作系统模块)等等,就是对CommomJS API的实现。

而CommonJS的一个重要规范就是模块规范

1.CommonJS的每个文件都是一个模块,所有模块都有一个模块标识module代表模块本身
2.module有一个模块定义属性module.exports用于到处模块中的变量/方法;
3.全局的引入模块的API:reqiure()
4.模块的变量作用域

node.js实现了ComonJS,作为node.js的包管理器自然得遵循CommomJS的模块规范;所以上面代码中的reqiure("express")就是node.js对CommonJS全局导入模块API的实现。

如下 a.js:

var a = 1;
 
function add(value1, value2) {
    return value1 + value2;
}
 
//变量导出
exports.a = a;
//方法导出
exports.add = add;

b.js如下:(a.js, b.js同一目录)

// 引入 a.js
const aModule = require("a.js")
 // 打印 1
console.log(aModule.a)

AMD

CommonJS是浏览器之外的javascript规范,那浏览器要使用模块化,怎么办,也使用这种规范?等等,我们看看上面b.js中的require(“a.js”)是同步加载,但是有很多问题:

1.浏览器最容易的方式是在document中插入script 标签。但脚本标签天生异步,传统CommonJS模块在浏览器环境中无法正常加载。
2.多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
3.js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

因此需要一个适用于浏览器的模块规范,正是AMD(Asynchronous Module Definition)见名知意,就是异步模块定义,当然是为了解决上述同步加载问题。AMD的实现主要是require.js。

还有一种CMD,与AMD很类似,seajs是的代表型实现。

但是这里不会详细讲解AMD、CMD,因为有更好的方案:ES6模块化

ES6

还有一种ES6模块化规范在现在实际开发中逐渐使用广泛。ES 是ECMAscript的缩写。ECMAscript 全名European Computer Manufacturers Association(欧洲计算机制造商协会) Script。1996年,javascript的开发公司Netscape将javascript提交给欧洲计算机制造商协会进行标准化。javascript和ES6的关系就像java和java8的关系

1997年,第一版javascript标准ECMA-262被推出,后续持续更新,直到2015年,ES6(也就是: ECAMAScript 2015),别称为下一代javascript标准。ES6也有它的模块化标准:

1.导出export :

 //esA.js
 //es6 的导出模块写法有
 export default 123;  //一个文件里只能又一个 export default
 export const a = 123;  //导出变量
 const b = 3;
 const c = ()=> {console.log("es6")};
 export { b, c }; //导出变量,函数

2.导入import:

 //esB.js (与esA.js同目录)
 //导入上面esA.js的变量,函数
 import x from "./esA.js"  //x为123;导入esA中export default 的变量
 import {b, c} from "./esA.js" //导入esA中的b,c
 import * as A from "./esA.js" //导入esA中所有export的变量,函数放在A对象上

ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案

但是正如上面所说ES6是下一代javascript标准,所以现在各大浏览器对ES6的兼容还是问题。而且开发运行时都是在nodejs环境下,自然要遵循CommonJS的模块化规范,那这两个岂不是会冲突?

webpack

是的,是有冲突。但是webpack的出现,让这一切不再是问题。

webpack是前端资源打包构建工具,可是它的工作可不止是打包,它会完成很多东西:

  • 1.将浏览器不认识的语法编译成浏览器认识的语法。比如less编译成css,ES6 语法 转成 ES5(这里就解决了ES6兼容性的问题)等等。
  • 2.将同一页面的静态资源合并打包,减少页面静态资源的请求次数
  • 3.tree shaking:打包时将没用到的资源去掉,减小资源的体积
  • 4.压缩打包:减小资源的体积
  • 5…等等

简而言之,wbpack就是将你开发的代码全都转换成浏览器可以
执行的代码,并且减小资源体积,优化页面性能。

但是这也没说为啥webpack解决了CommonJS和ES6模块规范的冲突啊?别急,现在来说说:webpack 内置一套独立的模块系统,支持CommonJS, AMD,和ES6这三种标准,见他们统统转换成符合自己标准的模块

具体怎么转的呐?那就涉及到前端开发者低头不见抬头见的babel

babel

babel是webpack中经常用到的插件。因为目很多主流浏览器对不支持ES6,所以编写代码时用到的许多ES6的语法需要转成ES5代码,而babel就是做这件事的,显然ES6的importexport也需要转换,babel 则能提前将 es6 的 import 等模块关键字转换成 CommonJS 的规范和加以处理,然后webpack就像处理CommonJS模块一样处理ES6模块。这就是为什么经常在同一个项目里可能同时存在module.exports (CommonJS)和 export default (ES6)。

javascript和typescript

如果按照前面的内容,我们发现一步步的解决了各种问题:

  • vue,react等的出现让前端开发迈入组件化时代;数据驱动,让我们把精力更多的放在数据以及数据变更逻辑上
  • node.js则让前后端分离成为可能;node.js基于v8引擎,并且实现CommonJS,内置模块诸如http,path,fs等让使用javascript搭建一个web服务成为可能。
  • koa,express则进一步降低了前端开发人员构建一个web服务的难度
  • javascript模块化各种规范在webpack下得以兼容
  • webpack打包构建,优化性能

整个开发流程都有了较为合适的解决方案,这时候如果还像继续优化,我们的目光就要回到javascript。

javascript是一门面向对象的,弱类型的,解释型语言;但是javascript并不支持其它面向对象语言所具有的继承和重载功能

我们要想看看javascript作为语言有什么可以继续改进的,只看上面这句话可能没啥感觉。

设想一下,前后端分离后,后端开发人员给你提供接口、接口调用方式、接口入参、接口返回的Model,你在开发中拿到返回Model使用javascript处理,获取Model中信息时用response.data.createAt获取创建时间,可是不小心写错了写成response.data.createat,你在打包时,甚至再回来找问题时找几次都没发现问题。再或者model比较复杂,你需要一次又一次的去看后端同时提供的文档去解析数据;等等问题。这无疑会带来很多烦人的问题,降低效率,而问题的原罪就是javascript是弱类型语言,编码时并没有类型,所以response.data对象上没有createat这个属性也无法体现;而且javascript运行时去决定类型无疑会加大代码执行耗时,降低性能。

上面这种情形,typescript就能很好的解决。

typescript是javascript的超集,增加了类型系统和对ES6的支持。它可以编译成纯 javascript。编译出来的 javascript 可以运行在任何浏览器上。typescript 编译工具可以运行在任何服务器和任何系统上。

类型系统使得typescript成为强类型的语言,就像java一样,在编译阶段就已经确定类型。这会带来很多好处:

  • 可以在编译阶段就发现大部分错误,这总比在运行时候出错好
  • 增强了代码的可读性,降低了维护难度

而对ES6的支持则让它成为拥抱未来的不二之选,毕竟ES6是下一代javascript标准嘛,ES6的众多语法糖 会让你直呼真香。

typescript还有一项受人喜爱的优势:增强了编辑器和 IDE 的功能,包括代码补全、接口提示、跳转到定义、重构等,主流的编辑器都支持 typescript。

结语

建立一个清晰的技术知识体系让你在开发中更加得心应手,这篇文章是我在开发实践中逐渐理解的架构体系,我在相当一段时间内对这个体系是认知模糊的,随着实践学习,一点一点的揭开它的面纱。如果你读完了,希望你有所收获,如果你有什么问题,欢迎交流讨论,互相提高。

上一篇:ES6模块和Commonjs的差异


下一篇:用monit监控系统关键进程