Skip to main content

现代前端开发简述

· 约30分钟
Proca

引言

想象一下,你是一个刚刚开始学习前端开发的新手,你打开了一个教程网站,想找到一些基础的知识和技巧。你点击了一个看起来很有用的文章,结果发现里面充满了你从来没听说过的术语和缩写:webpack, npm, yarn, angular, vue, react, typescript...你感到一阵头晕,不知道这些东西是什么,为什么要用它们,怎么用它们!

你不是例外。许多想要入门前端开发的人都会遇到这样的困惑和挑战。前端开发技术在过去几十年里发生了巨大的变化和进步,从最初的“三剑客”:HTML, CSS, JavaScript,演化到了今天的多样化和复杂化的技术栈。如果你想要跟上这个变化的步伐,你需要了解这些技术栈是如何出现的,它们各自的优势和用途,以及如何选择和使用它们(然而,这一点限于篇幅我们不会展开讲)。

在这篇文章中,我将从 依赖管理语言特性软件框架Node.js大发展浏览器发展 五个方面介绍前端开发技术的演化历程,帮助你理清上面提到的那些眼花缭乱的名词,最重要的,让你对现代前端开发有一个基本的印象和认识。

依赖管理

假设你是一个刚入门前端开发的新手,正要在你的HTML文件中引入一些别人写好的JavaScript脚本,比如jQuery,Bootstrap等。于是,你HTML文件的 <head> 标签可能是这样的:

<head>
<title>My Website</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">

<!-- 引入 jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>

<!-- 引入 BootStrap -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>

</head>

过程中,你可能会遇到许多问题:

首先,在HTML文件中使用<script>标签引入这些依赖的顺序和位置需要注意。

比如,你想要使用Bootstrap来美化你的网页,但你先写了引入Bootstrap的代码,再写引入jQuery的代码, 或者干脆忘了引入jQuery,于是,你的Bootstrap绝对完全无法正常工作!(毕竟Bootstrap要基于jQuery才能正常工作)

其次,像 https://code.jquery.com/jquery-3.6.0.min.js 这样的地址,你需要自己去找,并且确定它们的版本是否适合你的项目。 比如,你想要使用jQuery的某个插件,但是它只支持jQuery 1.x版本,而你却下载了jQuery 2.x版本,这样就会导致插件无法正常工作!

还有,你需要自己检查这些依赖是否有冲突或错误,并且调试和修复它们。

比如,你想要使用两个不同的JavaScript库(即引入了两个不同的JavaScript库)来实现不同的功能, 但是它们都使用了同一个全局变量或函数名,这样就会导致其中一个库覆盖另一个库的定义,产生一些意想不到的错误!

此外,你需要自己优化这些依赖的大小和数量,并且考虑它们对网页加载速度的影响。 比如,你想要使用一些非常酷的动画效果,但是你引入了很多不必要的脚本文件,这样就会增加网页的体积和请求数量,从而降低网页的加载速度和用户体验。 网站的用户在等待网页加载好之前可能已经把网页关掉了。

如果你要引入的真的只有jQuery和BootStrap这两个库就还好,但随着你网站内容的不断丰富、规模的不断扩大,你需要的可不仅仅是两个库。 依赖管理问题会不断地找上你,这不仅浪费时间和精力,而且会降低代码质量和可维护性。

为了解决这些问题,聪明的前端开发者开始使用一些更加智能和自动化的依赖管理工具:

npm(Node Package Manager)

yarn(Yet Another Resource Negotiator)

webpack(Web Application Bundler)等等

有了这些工具,我们可以通过命令行或配置文件来安装、更新、删除依赖。

你只需要在命令行中输入

npm install jquery bootstrap --save

就可以自动下载并保存 jQuery 和 Bootstrap 到你的项目目录中,它们的版本信息则会被记录到 package.json 文件中。

同时,版本问题和兼容性问题也得以解决!比如,你可以在 package.json 文件中指定依赖的版本范围, 比如 ^1.0.0 表示兼容 1.x.x 版本,~1.0.0 表示兼容 1.0.x 版本等。 这样,在更新依赖时,就可以避免引入一些不兼容或有bug的版本。

至于webpack,它可以通过模块化和打包机制来加快我们项目依赖的加载和执行速度。 例如,你可以使用webpack来将多个JavaScript文件合并为一个文件(如 bundle.js ),并且去除一些无用的代码和注释。 像我们上面示例中需要用到的jQuery和BootStrap,通过webpack打包后,两个 script 就会被合并为一个文件,无关的代码也会被去除。

如此这般,网络请求也只需要请求这一个文件,速度快了,体积小了,何乐而不为呢?

语言特性

最初,JavaScript只是一门很简陋的语言,他只花了10天就被设计出来了。 但它也是一门不断发展的语言,每年都会有新的语法和功能被提出和标准化。这些新的语言特性可以让我们写出更简洁,更优雅,更强大的代码,提高我们的开发效率和质量。 例如,2015年推出的ES6标准引入了许多新的特性,如在其他编程语言常见的类,以及箭头函数,模板字符串,解构赋值,模块化等等。

然而,并不是所有的浏览器和环境都能支持这些新的语言特性。 有些浏览器可能需要很长时间才能更新和兼容最新的标准,有些浏览器可能永远不会更新。 如果我们想要使用这些新的语言特性,而又不想牺牲我们的用户体验和兼容性, 我们就需要一个工具来帮助我们把新的JavaScript代码转换成旧的JavaScript代码,让它们能够在任何浏览器和环境中运行。

这个工具就是Babel。 Babel是一个JavaScript转译器,它可以把最新的JavaScript代码转换成向后兼容的JavaScript代码, 让我们可以使用所有的新语法和功能,而不用担心浏览器的支持问题。Babel还可以通过插件来扩展它的功能, 让我们可以使用一些还没有被标准化的实验性特性,或者一些其他语言(如TypeScript或Flow)提供的类型注解等等。

例如,下面是一个使用ES6类语法定义一个Person类并创建一个实例的代码:

// ES6 类语法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}

greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}

let alice = new Person("Alice", 25);
alice.greet();

如果我们用Babel转译这段代码,它会变成这样:

// 由Babel转译后的代码,符合ES5标准
"use strict";

function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}

var Person = (function () {
function Person(name, age) {
_classCallCheck(this, Person);

this.name = name;
this.age = age;
}

Person.prototype.greet = function greet() {
console.log(
"Hello, my name is " + this.name + " and I am " + this.age + " years old."
);
};

return Person;
})();

var alice = new Person("Alice", 25);
alice.greet();

可以看到,Babel把类语法转换成了原型链和构造函数的方式,并且添加了一些辅助函数和严格模式。 这样就可以保证这段代码能够在不支持ES6类语法的浏览器中正常运行。

ES6之后,JavaScript的标准还在不断地更新和扩展,每年都会有新的特性被提出和采纳。例如,ES7(也叫ES2016)引入了指数运算符和数组的includes方法, ES8(也叫ES2017)引入了async/await语法和对象的entries和values方法,ES9(也叫ES2018)引入了对象的扩展运算符和正则表达式的改进等等。

为了能够使用这些新的特性,我们同样需要Babel来帮助我们转译代码。Babel提供了不同的预设(presets)来让我们选择要转译的目标版本。例如,@babel/preset-env可以让我们根据浏览器或者环境的兼容性来自动选择要转译的特性,而不用手动指定。 (这是在Babel配置文件中实现的)

除了JavaScript本身的特性之外,还有一些其他语言可以编译成JavaScript来运行。 其中最著名的一个就是TypeScript。 TypeScript是由微软开发和维护的一门开源语言,它是JavaScript的一个超集,也就是说它包含了JavaScript所有的语法和功能 ,同时还添加了一些新的特性,最主要的就是类型系统。

note

所有JavaScript代码都是合法的TypeScript代码,所以TypeScript也是弱类型的。

所谓弱类型,就是说变量的类型不是在编写代码时指定的,而是在运行时确定的。而TypeScript在这一点和JavaScript是一样的。

类型系统可以让我们在编写代码时给变量,函数,参数等指定类型, 从而让编译器或者编辑器可以检查代码中是否有类型错误或者不匹配的情况。 这样可以提高代码的可读性和可维护性,减少运行时错误和调试时间。TypeScript还支持一些JavaScript还没有实现的特性,如枚举,泛型,命名空间等等。

Babel也可以用来转译TypeScript代码,只需要安装@babel/preset-typescript预设, 并在Babel配置中添加它即可。Babel会把TypeScript代码转换成普通的JavaScript代码,并且去掉类型注解。例如:

// TypeScript 代码
function add(a: number, b: number): number {
return a + b;
}
// 经过Babel转译后的JavaScript代码
function add(a, b) {
return a + b;
}

当然,Babel只是负责转译代码,并不会做类型检查。如果我们想要检查类型是否正确,我们还需要安装并使用TypeScript编译器或者编辑器。

软件框架

HTML是一种用来描述网页结构和内容的标记语言,它最初是为了表示文档而设计的,而不是应用程序。 HTML使用一系列的标签(tags)来定义不同的元素,如标题,段落,列表,链接,图片等等。 这些元素构成了一个文档对象模型(DOM),它是一个树形的数据结构,表示了文档中的所有元素及其关系。

note

选中本页的任意内容,单击右键,选择“检查”,然后切换到“Elements(元素)”标签,就可以看到你选中的内容在DOM结构中的位置。

DOM提供了一种编程接口,让我们可以使用JavaScript等脚本语言来操作文档中的元素,改变它们的属性,样式,内容,或者响应用户的交互事件。这样就可以实现一些动态的效果和功能,让网页变得更加生动和有趣。

然而,随着网页变得越来越复杂和丰富,仅仅使用原生的HTML和JavaScript来开发网页应用程序就显得力不从心了。我们需要一些更高层次的抽象和工具来帮助我们组织和管理我们的代码,提高我们的开发效率和质量。这就是软件框架(frameworks)的作用。

软件框架是一种软件开发工具,它提供了一套预先定义好的结构,模式,方法,函数等等,让我们可以在其基础上快速地构建我们自己的应用程序。软件框架通常会封装一些底层的细节和复杂性,让我们可以专注于业务逻辑和用户界面。软件框架还可以提供一些通用的功能和组件,如路由,状态管理,数据绑定,表单验证等等,让我们可以重用已有的代码,避免重复造轮子。

在前端开发领域中,有许多不同类型和风格的软件框架可供选择。其中最流行和最有影响力的几个就是React ,Vue ,Angular 等等。这些框架都有各自的优势和特点,但它们也有一些共同的目标和理念:

  • 提供一种声明式(declarative)的方式来定义用户界面,让我们可以描述界面应该呈现什么样子,而不是怎么呈现。

  • 提供一种组件化(component-based)的方式来构建用户界面,让我们可以把界面分解成可复用的小块,并且管理它们之间的数据流和交互。

  • 提供一种响应式(reactive)的方式来更新用户界面,让我们可以自动地根据数据变化而更新界面,而不需要手动操作DOM。

这些框架都是基于JavaScript语言开发的,并且使用了JavaScript最新的语法和特性。因此,在使用这些框架之前,我们通常需要使用Babel或者其他工具来转译我们的代码,以保证它们能够在不同浏览器中运行。

同时,这些框架也都遵循了前端社区中流行的一些哲学和原则(有些是从Unix社区继承而来的)。我们以React为例,看看它遵循了什么样的哲学和原则:

  • “小即是美”(small is beautiful)

React是非常轻量的,它只提供了创建和渲染组件的核心功能,而不涉及其他方面,如路由,状态管理,数据获取等等。这样可以让React更容易理解和使用,也可以让开发者有更大的灵活性和自由度,根据自己的需要选择和组合其他的库和工具。例如,React Router ,Redux ,Axios 等等。

note

正因如此,有些人并不称React为框架,而是称它为库(library)。React与Redux、React Router等库一起使用,才可以构成一个完整的应用程序框架。

  • “每个程序只做一件事并做好”(make each program do one thing well)

React专注于解决用户界面的问题,它提供了一种声明式的方式来定义用户界面,让我们可以描述界面应该呈现什么样子,而不是怎么呈现。React还提供了一种组件化的方式来构建用户界面,让我们可以把界面分解成可复用的小块,并且管理它们之间的数据流和交互。React还提供了一种响应式的方式来更新用户界面,让我们可以自动地根据数据变化而更新界面,而不需要手动操作DOM。React不试图涵盖所有的方面和功能,而是专业和高效地解决用户界面的问题。同时,React也可以与其他的框架和库协作和互通,形成一个生态系统。

Node.js大发展

Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,它可以让我们在服务器端使用JavaScript来开发应用程序。Node.js是开源的,跨平台的,事件驱动的,非阻塞的I/O模型,使它非常轻量,高效,适合开发实时和高并发的应用程序。

Node.js的出现和发展,对前端开发产生了巨大的影响和改变。我们来看看它带来了哪些好处:

前后端同构

Node.js让我们可以使用同一种语言(JavaScript)来开发前端和后端,这样可以减少学习成本,提高开发效率,增强代码的一致性和可维护性。同时,也方便了前后端的协作和沟通。更进一步,Node.js还让我们可以实现前后端同构(isomorphic),也就是说我们可以在服务器端和客户端使用相同或者类似的代码来渲染用户界面。这样可以提高用户体验,优化性能,增强SEO等等。

前端工程化

Node.js拥有一个庞大而活跃的社区,为它提供了大量的库,框架,工具,资源等等。其中最著名的就是npm ,它是一个包管理器,可以让我们方便地安装和管理我们需要的依赖。npm拥有超过100万个包,覆盖了各种各样的功能和需求。借助于npm和其他工具,我们可以实现前端工程化(engineering),也就是说我们可以使用模块化,组件化,自动化等技术来提高前端开发的质量和效率。例如,我们可以使用Babel ,Webpack ,Gulp 等工具来转译,打包,压缩,热更新等等。

全栈开发

Node.js非常适合开发实时和高并发的应用程序,如聊天室,视频会议,直播平台等等。这是因为Node.js支持WebSocket协议,它可以实现双向通信(full-duplex communication),让服务器和客户端可以实时地交换数据。同时,Node.js也支持流(stream)API,它可以让我们以数据流的形式处理输入输出(I/O),提高数据处理的效率和速度。借助于Node.js和其他框架和库,我们可以实现全栈开发(full-stack),也就是说我们可以使用JavaScript来开发前端和后端,并且实现数据的同步和共享。

浏览器发展

狭义上,浏览器是指Web浏览器,它是一种客户端软件,用于访问和浏览网页。你设备上安装的如Chrome,Firefox,Safari,Edge,IE,Opera,甚至360极速浏览器、QQ浏览器、UC浏览器等等,都是浏览器。

而广义上,我们手机中的微信、淘宝等软件也属于浏览器。通过Webview技术,它们可以在自己的应用程序中嵌入一个浏览器,让我们可以在其中访问和浏览网页、应用程序。

接下来,我们看看浏览器各个方面的发展对前端开发带来了哪些影响:

图形能力

刀耕火种时代,浏览器只能显示简单的文本和图片,后来网页变得越来越丰富和复杂,浏览器也不断提升了它们的图形能力,支持了更多的样式,布局,动画,特效等等。例如,CSS3引入了许多新的属性和模块,如渐变,阴影,圆角,弹性盒子,网格布局,动画,过渡等等。这些特性让我们可以创建更美观和更灵活的用户界面,提高用户体验,推动前端的发展。

多媒体能力

随着网页变得越来越多媒体化,浏览器也不断提升了它们的多媒体能力,二者相辅相成,相互促进。于是,浏览器支持了更多的格式,编解码器,API等等。例如,HTML5引入了 <video><audio> 元素,让我们可以在网页中嵌入音频和视频,并且通过JavaScript控制它们的播放和交互。HTML5还引入了 <canvas> 元素,让我们可以在网页中绘制图形和动画,并且通过JavaScript操作它们。这些特性让我们可以创建更丰富和更互动的多媒体内容,提高用户参与度。

网络能力

世纪伊始,浏览器通过HTTP协议发送请求和接收响应,但在技术、产品发展的过程中,网页对实时与高并发的需求日益增长,浏览器也不断提升了它们的网络能力,支持了更多的协议,API等等。例如,WebSocket协议让我们可以实现双向通信(full-duplex communication),让服务器和客户端可以实时地交换数据。WebSocket还支持二进制数据传输,让我们可以发送和接收图片,音频,视频等数据。这些特性让我们可以创建更实时和更流畅的网络应用程序,如聊天室,视频会议,直播平台等等。

沙箱能力

浏览器最初在运行一些简单的脚本语言时(如JavaScript),受到很多安全限制。正如浏览器其他方面因网页的复杂化而不断发展,沙箱能力(sandboxing)也得到了提升,支持了更多的语言,API等等。例如,WebAssembly让我们可以在浏览器中运行其他编程语言编译出来的二进制代码,并且保证安全性和性能。WebAssembly还支持与JavaScript互操作,并且可以利用浏览器提供的API。这些特性让我们可以创建更高效和更强大的网页应用程序,并且拓展了浏览器的功能范围。

离线能力

在人们的印象中,浏览器只能在联网的情况下访问网页和应用程序,但实际上,浏览器也在不断提升了它们的离线能力(offline capability)。例如,Service Worker让我们可以在后台运行一些脚本,即使用户关闭了浏览器。Service Worker还可以拦截和处理网络请求,实现缓存和离线访问。IndexedDB让我们可以在浏览器中存储大量的结构化数据,并且支持事务和索引。这些特性让我们可以创建更智能和更可靠的网页应用程序,并且提高用户体验。

总结

在这篇博客中,我们回顾了前端开发的历史和现状,探讨了前端开发的各个方面和层面。

我们从依赖管理开始,介绍了使用npm和其他工具来安装和管理我们需要的库和框架的必要性。

接着我们讲解了语言特性,介绍了JavaScript的历史发展,认识到这样的发展会导致的兼容性问题。而Babel等转译工具正是解决这些问题的抓手。

然后我们认识了软件框架,列举了几个流行的前端框架,如React ,Vue ,Angular等等,侧重于介绍它们所秉持的理念、遵循的哲学原则。遵循这样的原则,对前端开发是大有好处的。

在Node.js的大发展中,我们认识到它对前端开发的影响和改变(前后端同构、前端工程化),也认识到这对全栈开发的贡献。

最后,我们了解了浏览器在图形能力,多媒体能力,网络能力,沙箱能力,离线能力等方面的进步和创新,这些进步和创新从前端发展中来,也会到前端发展中去。

此外,本文中涉及较多的陌生名词,如npm,Babel,React,Vue,Angular,Node.js,WebAssembly,Service Worker,IndexedDB等等,这些名词在此后前端开发的学习中会不断地出现,在我们对此“见多不怪”之前,只需对其有一个大致的认识即可。

支持一下

暂无评论,来留下友好的评论吧