本周,我将继续就前端之变阐述自己的思考,这一次讲到前端之变的重点:变革与突破
这是前端之变系列的第三篇文章,前两篇分别是:
- 前端之变(一):技术的变与不变
- 前端之变(二): "不变"的前端
同样,在具体说到前端究竟发生了哪个改变前,我们要理解变化的本质原因是什么
被限于浏览器的支持中
回到上一篇我讲的不变前端中,我在文章中明显的指出了,前端的变化会有一个分界线,在这个分界线之前,前端有一个最大的困境,就是:
前端技术始终被限制在浏览器的范围之内,无法突破
无论是HTML,CSS或是JS,它们的能力永远限制在浏览器这个容器内,当然前些年流行的JQuery,Boostarp这一类的技术框架也是这样,如果认真分析,会发现它们的能力始终在浏览器之内。
我们可以逐一分析前端的核心技术来窥视这种能力限制。
HTML
html主要是来展现内容的技术,最简单的一个HTML如下:
代码语言:javascript复制<!DOCTYPE html>
<html>
<head>
<title>html示例</title>
</head>
<body>
<h1>Hello,Html</h1>
</body>
</html>
如果我们把HTM与非前端的一些技术框架,比如后端的FreeMarker脚本技术相类比
代码语言:javascript复制<html>
<head>
<title>freemarker示例</title>
</head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
显而易见,如果我们抛开JS的能力,单纯就HTML来说,它的不足与限制非常明显
- 本身不具备动态渲染能力,简单的变量,if,for循环完全做不到。
- 难以将一个复杂的页面拆成不同的小页面来实现。一个页面就是一个HTML,甚至在一个HTML中引入另一个HTML中这种简单的事都做不到(不依赖JS)
根本原因在于,浏览器只提供了根据HTML内容渲染出页面展现用户的能力,浏览器并未向HTML提供任何动态能力,如基本的if,else,for等能力支持。HTML不可能脱离浏览器而发展出任何类似的能力。
这也是为什么前些年,页面是由后端技术把持的原因所在,单纯的HTML能力实在太差,就算结合JS的动态能力,也根本无法应对复杂页面。大而划小,分而治之在那个时候对前端来说是压根不可能做到的事情。
JavaScript
当然,浏览器是用另一种方案来解决这个问题的,也就是JavaScript,由于HTML本身只能做内容展现,其能力实在有限,解决方案是,提供一种脚本语言,这就是JavaScript的来源。
JavaScript最初的设想非常简单,提供一些浏览器客户行为支持,以避免昂贵的服务端渲染,比如提交数据前验证数据是否完整,准确等。基于这种简单的设想,JavaScript的设计也非常简单,就做成了一个简单的脚本式语言,没有块级作用域、模块、子类型等现代语言的一些特性。
出于这种最初的设计的原因,JavaScript于是始终表现的不像一个现代语言,其各种设计与语言特性,用好听的词来形容就是:"别树一帜"。
我们可以将Java与Swift去比较,也可以与OC,Kotlin去比较,因为它们很像,都属于同一阵营。但与JavaScript相比,没有任何必要,因为没法比较。
事实上,JavaScript连一种基本的能力在很长的时间内都不具备:
在一个JS中引入另一个JS
终于在ES6的时代,JavaScript设计与引入了modules的概念,支持import了。
但如我在上一篇文章所讲,真正来说,现在互联网的主流还是ES5,而不是ES6。
原因在于:浏览器不支持
CSS
再来说,CSS是样式。CSS的能力与HTML基本一致,就是简单的样式定义
代码语言:javascript复制body {
background-color: lightblue;
}
h1 {
color: white;
text-align: center;
}
与HTML一样,在CSS的世界中
- 没有任何动态能力,if,for等基本语法不被支持
- 谈不上将复杂的样式大而划小,分而治之。当然你可以将一个CSS拆成很多小CSS,但第一它们相互之间无法引用,只能统一被HTML引用,更者也谈不上相互之间存在任何继承,接口或抽象实现等概念,比如定义一个基本色,在其它CSS中引用这个基本色,这个在CSS中居然都无做到,因为CSS没有变量的概念
所以,我们可以明显看出,在『前』前端的时代,前端各种技术发展的能力始终受限于浏览器的支持。被困于浏览器之中。浏览器因为安全的问题,甚至连读取本地操作系统文件的能力都不会提供给这些技术。
由于浏览器提供的能力有限,这就造成了前端始终难以发展现能与其它现代语言相比的语言设计与框架,比如
- 面向对象的能力特性,继承,封装,多态在前端技术中不知道如何实现
- 很像将一些设计原则应用到前端,如单例,工厂,观察者等
- 谈不上在应对复杂软件时的核心解决方案:『大而划小,分而治之』
当然,这些已经成为过去式,由于一个本质的突破,就是
突然有一天,前端发现自己的技术不再受到浏览器的限制
突破,与浏览器说拜拜
终于,在越过一条明显的分界线后,前端技术的发展出现了突破:
虽然在最终产物阶段,仍受限于浏览器,但在编码阶段,技术的发展与能力与浏览器再无关联
由于不再受到浏览器的限制,前端的技术开始突飞猛进,五花八门,包括但不限于:
- 由于JavaScript比较糟糕,出现了TypeScript这样的与Java现代化语言非常相近的技术替代JavaScript
- 在HTML方向,出现了React,Vue等组件式的框架
- 为应对复杂样式的需要,演进出了具备编程能力的样式,如less,sass等
我们还是从前端的三个核心技术逐一分析
HTML
React与Vue等类似框架在编码阶段彻底取代了单纯的HTML,一个简单的React的页面可能是这样:
代码语言:javascript复制const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
ReactDOM.render(
<ul>{listItems}</ul>,
document.getElementById('root')
);
就算从上面简单的代码也可以看出,与HTML相比,React等这些技术能做到
- 支持基本的编程能力,if,for等都可以使用
- 支持组件化能力,把一个大的页面拆成不同的组件与页面。
比如在PCX中,对于聊天,聊天分很多种类,比如文本,图片,语音,在React中,你可以将这个复杂的页面大而划小,分而治之
image-20210529135659298
如上图所示:每一种消息类别 ,使用一个独立的子类来实现。
这种就完全具备了现代化语言的能力。在以前的HTML JS的时代,完全没有办法做到。
JavaScript
在『后』前端的阶段,并不能说JavaScript是被TypeScript取代了,现状只能说是TypeScript更流行,越来越受到欢迎。但JavaScript仍然大量存在,仍然是不可替代的。
TypeScript虽然最终仍然被翻译成JavaScript,它也无法取代JavaScript,但相比JavaScript,TypeScript对前端仍然具有里程碑的意义,从某种程度上说:
TypeScript使得前端第一次也具有了面向对象的语言
代码语言:javascript复制export class SessionRepository extends ISessionRepository {
protected getRepository():IRepository{
return BaseRepository.getInstance().getRepository();
}
/**
* 删除一个会话
* @param sessionId
*/
public async deleteSession(sessionId:string):Promise<boolean>{
const deleteSQL = "delete from session_ where identifier = $sessionId";
return this.getRepository().executeUpdate(deleteSQL,{
$sessionId:sessionId
});
}
}
上面的TS代码来自于我在20年的PCX中的代码片段。
我们可以完全看到,相比于JavaScript,TypeScript更像Java。如果让一个后端Java人员和一个前端JavaScript人员同时来学习,Java人员会学习的更快,因为TypeScript是类似Java的面向对象的语言。
理所当然的,包括面向对象的五大基本原则:
- 单一职责原则
- 里氏替换原则
- 开闭原则
- 依赖倒转原则
- 接口隔离原则
以及大家熟悉的二十多种设计模式,如工厂模式,观察者模式,命令模式等,在TypeScript都可以没有障碍的使用。
但在JavaScript的语言中,至少我不太清楚要怎么才能做到。
CSS
在『后』前端时代,由于突破了浏览器的限制,自然出现了更好的css的替代者。
比如less
其实less总体上与css基本一致,它也并未提供任何新的css样式,它的区别只是在单纯的静态CSS样式基础上,添加了一些动态能力,比如变量,函数等
代码语言:javascript复制@width: 10px;
@height: @width 10px;
#header {
width: @width;
height: @height;
}
.class {
//通过函数来计算
width: percentage(@width); // returns `50%`
color: saturate(@base, 5%);
background-color: spin(lighten(@base, 25%), 8);
}
更多
即然突破了浏览器,那自然整体技术发展也不会只局限在HTML,JS以及CSS三个维度了,因为没有了浏览器的限制,在编码阶段,前端出现了更多的突破性的技术,最典型的代表就是:npm依赖管理
其实,区分你是在『前』前端阶段,还是在『后』前端阶段的一个最简单的识别手段就是:
你是否使用了npm依赖管理
因为:
在『前』前端阶段,这个是绝无可能做到的。npm依赖管理需要大量的读取及分析本地文件,在这个基础之上才能做到
代码语言:javascript复制{
"name": "taoofcode",
"version": "1.0.0",
"private": true,
"description": "微言码道",
"author": "lingen.liu",
"keywords": [
"gatsby"
],
"license": "0BSD",
"dependencies": {
"@fika/gatsby-source-cockpit": "^1.1.2",
"@material-ui/core": "^4.11.2",
"@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.57",
"@mdx-js/mdx": "^1.6.22",
"@mdx-js/react": "^1.6.22",
"@types/react-helmet": "^6.1.0",
"gatsby": "^2.26.1",
"gatsby-image": "^2.8.0",
"gatsby-plugin-css-modules-typings": "^1.0.1",
"gatsby-plugin-google-analytics": "^2.9.0",
"gatsby-plugin-less": "^4.4.0",
"gatsby-plugin-manifest": "^2.9.1",
"gatsby-plugin-material-ui": "^2.1.10",
"gatsby-plugin-mdx": "^1.7.1",
"gatsby-plugin-react-helmet": "^3.7.0",
"gatsby-plugin-sharp": "^2.11.2",
"gatsby-plugin-sitemap": "^2.9.0",
"gatsby-remark-prismjs": "^3.10.0",
"gatsby-source-filesystem": "^2.8.1",
"gatsby-transformer-remark": "^2.13.1",
"gatsby-transformer-sharp": "^2.9.0",
"prismjs": "^1.22.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-helmet": "^6.1.0"
}
}
现在,你通过npm来申明与管理你的各种依赖了。
这会令你想到什么?在其它方向都有自己的依赖管理
- 后端是使用maven或gradle来进行依赖管理
- iOS最流行的是cocoapods
- Android是gradle来管理依赖
看到没,前端终于和其它技术方向站在同一起跑线上了。
转换技术
我在前面的文章也说过,前端其实并未改变,它仍然主要是由HTML,JS以及CSS组成。
在『后』前端阶段,编码已经发生了极大的改变,但最终产物仍然是这三个,并未改变。
那究竟它是怎么做到的?
那就是依赖--转换技术
由于突破了浏览器的限制,使得一切皆有可能,那当然也可以添加翻译这个能力。因此前端出现了一些翻译转换技术,它们的作用就是将前端各种花式的新技术的玩意转换成HTML,CSS,JS三个东西。
也就是,事实上,不管前端有了多少新技术,概念,最终仍然依赖于转换技术,仍然需要转换成HTML,JS以及CSS。
也就是:
- React,Vue这些代码只存在于编码阶段,最终它是HTML JS
- TypeScript只存在于编码阶段,最终它是JavaScript
- Less,Sass也同样只存在于编码阶段,最终它是CSS
是不是很有意思的现象?
主流的转换技术包括:
- babel -- 这是将es6及以上的一些新特性转换成es5的语法
- Webpack -- 它远比babel复杂,babel只做一件事,webpack则是做一堆事,它会使用ts-loader去转换typescript,使用less-loader去转换less,也会使用balbel去转换es6以上的语法。它有很多插件。
当然webpack也有一些同等级的技术,但论流行度,还是以Webpack为主。
所以,现在前端开发,基本不可能脱离webpack,有些整合的框架或技术,比如gatsby,你从代码中看不到Webpack的存在,但这不代表它不存在,而是被gatsby给隐藏到后面去了。它在Webpack之上,构建了一套自己的规则,使得开发人员不用关心WebPack的配置而已。
另外,create-react-app也是这种方式。
前端,王者的归来
我们不得不去询问一个问题?
这一切究竟是如何发生的?
从『前』前端阶段到『后』前端阶段,是谁让这一切发生了?
下一篇继续,前端之变(四):王者归来