浏览器模块化的局限
前面一篇文章详细介绍了 ESModule 的使用和特点,现在各大主流浏览器都支持了 ESModule,因此可以直接在script标签中引入ESModule模块化的文件,只需要加上type = module即可。
<script type="module" src=""></script>
但是直接在浏览器中使用 ESModule 有很多局限。
必须引入所有文件
不能只引入入口文件,还需要把入口文件引入的依赖都要引入。入口文件 entry.js 引入了两个依赖文件,当在index.html 引入entry.js 的时候,也需要把依赖文件 api.js 和 sum.js 也引入。
// entry.js
import m from './api.js'
import sum from './sum.js'
index.html
<script type="module" src="./sum.js"></script>
<script type="module" src="./api.js"></script>
<script type="module" src="./entry.js"></script>
ESModule 不像 Commonjs 那样只需要引入入口文件即可。当模块文件变多的时候,而且模块是分散在各个目录当中,我们就非常不好管理。另外,在大型项目中,每次都要加载这么多文件,导致性能非常差,所以这种开发模式无法满足需求。
必须完整引入文件地址
// 错误
import handle from './handle'
// 正确 后缀不能省略
import handle from './handle.js'
针对上面的问题,于是就出现了npm和webpack。
npm
npm 的全称是Node Package Manager,是一个 NodeJS 包管理和分发工具。
- npm 是由程序员 Lsaac 发明
- 初步思路:
- 集中管理所有的模块,所有的模块都上传到仓库(registry)
- 模块内创建 package.json 标注模块的基本信息
- 通过 npm publish 发布模块,上传到registry
- 通过 npm install 安装模块,模块安装到node_modules目录
- npm 于 2014 年商业化,2020年被 Github 收购
针对模块分散在各个项目中无法管理的问题,我们可以使用 npm 来解决。npm 解决的核心问题是模块管理的问题,npm 原理分析如下图:
首先通过 npm init 初始化一个项目,在这个项目中的 package.json 写上该项目的信息,比如name, version等,在项目中可以通过npm install 安装其他依赖,做完之后通过 npm publish 发布到仓库registry中,仓库主要分为 public 和 private 两个部分, npm 公司主要通过 private来收费的。公有仓库又分为 normal 和 organization(组织)。
npm 的局限
- npm 只能解决模块的高效管理和获取问题
- npm 无法解决性能加载的问题
- 模块发明以后,制约其广泛使用的因素就是性能问题
webpack
性能加载慢的问题要由于模块太多,导致每次加载的时候发送很多请求。那能不能把模块全部打包到一个 bundle.js 文件中,然后进行加载,这样不是就可以解决性能慢的问题了吗?
因此,webpack 就这样诞生了。
- webpack 2012年3月10号诞生,作者是Tobias(德国)
- 移植了 GWT(Google Web Tookit) 的功能(code spliting)
- 2014年 Instagram 团队分享性能优化时,提到使用 webpack 的 code spliting 特性
- webpack 的出现模糊了任务和构建的边界,融为一体
最初 webpack 核心解决的问题就是代码的合并和拆分,它的核心理念是将资源都视为模块,统一进行打包和处理,它同时提供了 loader 和 plugins 进行功能的扩展。webpack 之所以能像今天这么火,是因为它提供了 loader 和 plugins 两个能力,让它的功能得到了极大的扩展。可以参考下图,webpack 具体做了什么。
我们可以看下 webpack 官网的图,就能知道 webpack 能做的事情只有两个,先打包,后分割。首先把不同的资源进行打包成一个文件,然后根据规则再拆分为js css 图片等。
一句话概括今天的内容就是: 模块化提升了开发效率,但是牺牲了访问性能,所以就出现了npm和webpack。