前言
之前好友希望能介绍一下 webapck 相关的内容,所以最近花费了两个多月的准备,终于完成了 webapck 系列,它包括一下几部分:
webapck 系列一:手写一个 JavaScript 打包器
webpack 系列二:所有配置项
webpack 系列三:优化 90% 打包速度
webpack 系列四:优化包体积
webapck 系列五:优化首屏加载时间与页面流畅度
webapck 系列六:构建包分析
webapck 系列七:详细配置
webapck 系列八:手写一个 webapck 插件(模拟 HtmlWebpackPlugin 的实现)
webapck 系列九:webapck4 核心源码解读
webapck 系列十:webapck5 展望
所有的内容之后会陆续放出,如果你有任何想要了解的内容或者有任何疑问,关注公众号【前端瓶子君】回复【123】添加好友,我会解答你的疑问。
作为一个前端开发人员,我们花费大量的时间去处理 webpack、gulp 等打包工具,将高级 JavaScript 项目打包成更复杂、更难以解读的文件包,运行在浏览器中,那么理解 JavaScript 打包机制就很必要,它帮助你更好的调试项目、更快的定位问题产生的问题,并且帮助你更好的理解、使用 webpack 等打包工具。
在这章你将会深入理解 JavaScript 打包器是什么,它的打包机制是什么?解决了什么问题?如果你理解了这些,接下来的 webpack 优化就会很简单。
一、什么是模块
一个模块可以有很多定义,但我认为:模块是一组与特定功能相关的代码。它封装了实现细节,公开了一个公共API,并与其他模块结合以构建更大的应用程序。
所谓模块化,就是为了实现更高级别的抽象,它将一类或多种实现封装到一个模块中,我们不必考虑模块内是怎样的依赖关系,仅仅调用它暴露出来的 API 即可。
例如在一个项目中:
<html>
<script src="/src/man.js"></script>
<script src="/src/person.js"></script>
</html>
其中 person.js
中依赖 man.js
,在引用时如果你把它们的引用顺序颠倒就会报错。在大型项目中,这种依赖关系就显得尤其重要,而且极难维护,除此之外,它还有以下问题:
一切都加载到全局上下文中,导致名称冲突和覆盖
涉及开发人员的大量手动工作,以找出依赖关系和包含顺序
所以,模块就尤其重要。
由于前后端 JavaScript 分别搁置在 HTTP 的两端,它们扮演的角色不同,侧重点也不一样。 浏览器端的 JavaScript 需要经历从一个服务器端分发到多个客户端执行,而服务器端 JS 则是相同的代码需要多次执行。前者的瓶颈在于宽带,后者的瓶颈则在于 CPU 等内存资源。前者需要通过网络加载代码,后者则需要从磁盘中加载, 两者的加载速度也不是在一个数量级上的。 所以前后端的模块定义不是一致的,其中服务器端的模块定义为:
CJS(CommonJS):旨在用于服务器端 JavaScript 的同步定义,Node 的模块系统实际上基于 CJS;
但 CommonJS 是以同步方式导入,因为用于服务端,文件都在本地,同步导入即使卡住主线程影响也不大,但在浏览器端,如果在 UI 加载的过程中需要花费很多时间来等待脚本加载完成,这会造成用户体验的很大问题。 鉴于网络的原因, CommonJS 为后端 JavaScript 制定的规范并不完全适合与前端的应用场景,下面来介绍 JavaScript 前端的规范。
AMD(异步模块定义):被定义为用于浏览器中模块的异步模型,RequireJS 是 AMD 最受欢迎的实现;
UMD(通用模块定义):它本质上一段 JavaScript 代码,放置在库的顶部,可让任何加载程序、任何环境加载它们;
ES2015(ES6):定义了异步导入和导出模块的语义,会编译成
require/exports
来执行的,这也是我们现今最常用的模块定义;
二、什么是打包器
所谓打包器,就是前端开发人员用来将 JavaScript 模块打包到一个可以在浏览器中运行的优化的 JavaScript 文件的工具,例如 webapck、rollup、gulp 等。
举个例子,你在一个 html 文件中引入多个 JavaScript 文件:
<html>
<script src="/src/entry.js"></script>
<script src="/src/message.js"></script>
<script src="/src/hello.js"></script>
<script src="/src/name.js"></script>
</html>
当浏览器打开该网页时,每个 js 文件都需要一个单独的 http 请求,即 4 个往返请求,才能正确的启动你的项目。
我们知道浏览器加载模块很慢,即使是 HTTP/2 支持有效的加载许多小文件,但其性能都不如加载一个更加有效(即使不做任何优化)。
因此,最好将所有 4 个文件合并为1个:
<html>
<script src="/dist/bundle.js"></script>
</html>
这样只需要一次 http 请求即可。
如何打包到一个文件喃?它