大多同学的前端学习路线:三件套+框架+慢慢延伸到其他,在这个过程中,有一个词出现的频率很高:webpack 。

作为一个很出名的前端构建工具我们在网上随便一搜,就会有各种教程:loader plugin entry吧啦吧啦。

但是为什么会有它,为什么我们离不开它呢? 如何理解“构建工具”四个字?它和“打包工具”又有什么关系呢?用法和api其实很好找,但是这几个问题的答案找起来却有点难度:相关的解释都零零散散,于是决定做这么一个分享,希望能以不一样的角度带给大家新的启发。 以上就是写这篇文章的初衷

目录

何为前端构建(打包)工具

构建工具发展史

1.石器时代

2.蒸汽时代

3.近现代

4.现代

回顾


何为前端构建(打包)工具

现代的前端构建主要包括两部分:transformbundle

1.transform(代码转换): 的作用就是将 TypeScript/JavaScript/JSX 等高级语法 (es6语法浏览器直接运行可能会不兼容)转化适合浏览器/Node.js 运行的相关标准的 javascript 的过程。

2.bundle(代码打包):从开发者设置的入口出发,分析模块依赖,加载并将各类资源最终打包 成1个或多个文件。

所以,“打包工具”是“构建工具”的一部分。

构建工具发展史

接下来会按照前端发展为时间线来进行讲解,以前端大事件为节点进行分割,来分析讲解当时的前端困境以及对应的构建情况。

1.石器时代

标志性事件:1990年浏览器的诞生。

在这段时间,除了浏览器,还诞生了很多东西:WWW(World Wide Web)的诞生、JavaScript的诞生、W3C、PHP……

此时的前端:那个时候页面基本是纯静态的或者服务端输出 没有专业的前端,页面全是由后端开发 在很长的一段前端历史里,是不存在打包/构建这个说法的。

2.蒸汽时代

2.1标志性事件:2005年AJAX被拾起。

ps:XMLHttpRequest是2000年就有了,但是由于推广以及存在的问题(需要浏览器提供支持,存在跨域问题),导致它刚开始并没有被人们注意,到 2005 年 Ajax 和 Web 2.0 变得流行才被人注意。

为什么说AJAX对前端具有非凡意义呢?

想象一下,之前前端页面展示在浏览器中 是后端一整个页面发过来,有数据更改,后端改了之后,把一整个新的页面再发过来(也就指常说的:页面整个刷新)。

有了ajax之后,发过来页面之后,如果有更新,只需要网络交互有更改的地方

也就是:整个页面刷新—->部分刷新(将页面/呈现和数据分离!交互的粒度变小了)

意味着可以把以前一些服务器负担的工作转嫁到客户端

js能做的事愈来愈多,前端开发者开始往页面里插入各种库和插件,我们的 js 文件程指数倍的开始增加。

2.2此时遇到的问题

1.运行环境限制:js作为一门脚本语言,只能在浏览器运行(没有node的时候),只能通过标签 插进html去运行去引那些js文件,还得注意引用顺序和插入的位置,一方面难以维护, 一方面增加了网页加载时的请求数量。

2.代码分割管理的问题:引用一些脚本来存放每个功能;此解决方案很难扩展,因为加载太多脚本会 导致网络瓶颈。

3.可维护性:使用一个包含所有项目代码的大型 .js 文件,但是这会导致作用域、文件大小、 js文件间的文件依赖难以维护,可读性差等问题。

举个例子:比如说如果要用bootstrap,只需要在 script 标签中引入对应库的 cdn 链接即可, 然而由于 bootstrap 依赖于 jquery,我们必须把引入 jquery 的标签写在 bootstrap 的《前面》,不然就会导致报错。

如果一个网站功能很多,我要按照功能划分写15个js文件, 那我就要插入15个 去引那些js文件,还tm得注意引用顺序和插入的位置,一方面难以维护, 一方面增加了网页加载时的请求数量(15个不算多,如果是200个js文件的话,维护起来会多令人崩溃。。。)

2.3当时的解决办法:JS压缩。

压缩主要做了局部变量命名简化、空格/换行/注释消除、自动优化可简化的语法等工作

一般是通过在window上用bat脚本或者mac/linux上的shell脚本来决定合并哪些文件、用什么工具压缩、怎么压缩。

JSMin、YUI Compressor、Closure Compiler、UglifyJS 等js 文件压缩合并工具在当时陆陆续续诞生。

2.4存在的问题

但是这种解决办法依旧存在问题:

举个例子,当a文件和b文件都引用了c文件的方法时,如果把c文件分别和ab合并, 这样就只有两个文件了这就是最开始的合并方式。 工程化的项目里相互依赖关系变得很是复杂 合并的文件里可能会有不少重复/无用代码。

3.近现代

3.1标志性事件:Node.js的诞生(2009)和随之诞生的各种JS规范(commonJS AMD CMD ECMAscript等)。

之前我们说什么?js只能在浏览器里面执行 node可以在浏览器环境之外的计算机和服务器中使用。 commonjs的require机制为js引入了模块化。

3.2此时遇到的问题

1.浏览器兼容问题:尽管现如今主流浏览器的最新版本都支持这一特性, 但是在几年前的我们还无法忽略用户存在使用老版本浏览器的 case, 所以我们还需要考虑兼容问题。

2.网络性能问题:模块化的方式划分出来的模块文件过多, 而前端应用又运行在浏览器中,每一个文件都需要单独从服务器请求回来。 零散的模块文件必然会导致浏览器的频繁发送网络请求,由于上文所述的 Http1.x 的能力局限性, 进而会影响应用使用体验。

3.模块化需求:随着应用日益复杂,在前端应用开发过程中不仅仅只有 JavaScript 代码需要模块化,HTML 和 CSS 这些资源文件也会面临需要被模块化的问题。(sass ejs)

4.打包时候的额外工作: ES6 -> ES5 ,TS -> JS, less / scss -> css等

3.3当时的解决办法:颇具代表性的构建工具webpack来了!(2014)

(ps:同时期还有其他也很优秀的构建工具,如rollup等,这里挑的是比较有代表性的webpack来讲解)

我们上文提到,构建工具包含transform 和 bundle两部分,webpack主要负责打包(bundle),同时它那些loader/plugin让他能够去转化代码(transform)。

所以如果我们回看此时的困境,webpack其实差不多都能解决的7788了(webpack有大量的plugin和loader兼容性问题,代码转换问题 以及webpack还引入了异步地加载 chunk 和预取等等来进行性能优化,来弥补网络性能问题等等)

3.4存在的问题:主要是dev环境(即开发环境)下的问题

我们项目中的所有代码最终都被打包到了一起,如果我们应用非常复杂, 模块非常多的话,我们的打包结果就会特别的大,加载时间就会很长。 项目的启动速度也会越来越慢(因为每次都要重新打包)。

为了解决这个问题,我们可以分包,HMR(模块热替换Hot Module Replacement),以及还有其他优化方法,就不多赘述。

4.现代

我们想要的:让我们在生产环境下,更快的构建出对应的产出文件

上文我们提到了dev环境下构建工具存在的缺陷,那么为了解决这个缺陷,一个概念被提出:bundleless

bundleless:顾名思义,就是不打包。

颇具代表性的就是vite

这里的不打包,侧重的是dev环境下的不打包,生产环境该打还得打(vite打包使用的是RollUp)。

基本原理:依赖浏览器原生支持esm 去解析模块。

为什么快:vite可以不用打包,只需要更新修改过的文件即可

PS:在查资料的时候,觉得vite和和webpack的一个plugin很像:webpack-dev-server

都是用在开发环境的,提高开发效率的(把代码读取到内存中)。

查了一下:大致过程和webpack-dev-server的差不多,但是vite可以不用打包,只需要更新修改过的文件即可

而和webpack-dev-server最主要区别则是:每次更新都会重新打包编译,所以没有vite快。

回顾

总结一下,不外乎这几种原因催,生了技术一次又一次的革新和发展:

需求,语言越来越多样化

对性能要求越来越大

项目(代码量)复杂度越来越大

其他技术(如硬件等)的发展

。。。。。

最后,希望这次“另辟蹊径”的分享能带给大家不一样的启发。