1. 为什么需要实时构建
In 2019, you should use a bundler because you want to, not because you need to
**打包工具(Bundler) ≠ 构建工具(Build Tools) ≠ 工程化 **
- 前端包依赖的庞大,当项目增长时依赖关系和体积指数级增长
- 传统构建速度慢,需要不断优化
- 复杂的构建工具,学习曲线,Webpack5??
- 在 ESM 出现之前,JavaScript 的模块化就有各式各样的规范,主要有 CommonJS, AMD, CMD, UMD 等规范,最为广泛的就是 Node.js 的 CommonJS,使用 module.exports 和 require 来导出导入模块,它是 npm 中的模块最主要提供的格式。由于浏览器并不直接支持这些模块,因此打包工具(Webpack,Browserify,Parcel 等)出现了。
Webpack 一方面解决了前端构建大型项目的问题,另一方面提供了插件优化 Web 前端性能。例如从资源合并以及压缩上解决了 HTTP 请求过程的问题,把小图片打包为 base64 以减少请求量,提供 Tree-Shaking 以及动态导入。伴随着 HTTP 协议的升级以及网速的不断加快,这些工作慢慢变成负担。
以 CRA 为例,只是为了运行一个 React 应用,我们居然还需要附加如此复杂的依赖。
前端的依赖比黑洞造成的时间扭曲还要大。
ESM 允许进行静态分析,从而实现像 tree-shaking 的优化,并提供诸如循环引用和动态绑定等高级功能。同时在 Node v8.5.0 之后也可以在实现标准的情况下使用 ESM,随着Node 13.9.0 版本的发布,ESM 已经可以在没有实验性标志的情况下使用。
ESM在浏览器中使用了大约5年的时间,现在在所有现代浏览器中都受支持(可追溯到2018年初)。使用ESM,不再需要打包工具。您可以在没有 Webpack 的情况下构建一个现代化,高性能,可用于生产的Web应用程序!
- 兼容性可接受:基本主流的浏览器版本都支持直接使用 JavaScript Module 了(当然,IE 一如既往除外)。
- 性能问题的改善:之前打包的一个重要原因是 HTTP/1.1 的特性导致,我们合并请求来优化性能;而如今 HTTP/2 普及之后,这个性能问题不像以前那么突出了。
- 打包的必要性:打包工具的存在主要就是为了处理模块化与合并请求,而以上两点基本解决这两个问题;再加之打包工具越来越复杂,此消彼长,其存在的必要性自然被作者所质疑。
2. 实时构建有什么解决方案——Bunless
什么是Bundless
webpack 之所以慢,主要的原因还是在于他将各个资源打包整合在一起形成 bundle,如果我们不需要 bundle 打包的过程,直接让浏览器去加载对应的资源,我们将有可能可以跳出这个循环,实现质的提升。
-
在 Bundleless 的架构下,我们不再需要构建一个完整的 bundle,同时在修改文件时,浏览器也只需要重新加载单个文件即可。由于没有了构建这一层我们将能够实现以下的目标:
极快的本地启动速度,只需要启动本地服务。
极快的代码编译速度,每次只需要处理单个文件。
项目开发构建的时间复杂度始终为 O(1),使得项目能够持续保持高效的构建。
更加简单的调试体验,不再强依赖 sourcemaps 即可实现稳定的单文件的 debug。
bundleless解决了什么问题?
bundleless 解决了大部分前端开发者 的一大痛点,就是心流。当一个程序员被打搅后,他需要 10 - 15 分钟的时间才能重新恢复到之前的编程状态。当你在完成一小块功能时候,想要去查看结果时候,发现当前的项目还在构建状态,这个时候很有可能就会中止心流。
Bundless实现
System.js 之类的 ES 模块加载器,好处是具有较高的兼容性。
直接利用 Web 标准的 Native-ESModule,面向未来,同时整体架构也更加简单。
3. 从资源加载看 Bundle 和 Bundleless 的不同
下面以大家最熟悉的 create-react-app 默认项目为例,从实际的页面渲染资源的加载过程对比 Bundle 和 Bundleless 的区别。
- 整体代码解构
-
- 加载机制
在项目启动和有文件变化时重新进行打包,这使得项目的启动和二次构建都需要做较多的事情,相应的耗时也会增长。从上图可以看到,Vite项目已经不再有一个构建好的 bundle、chunk 之类的文件,而是直接加载本地对应的文件。
从上图可以看到,在 Bundleless 的机制下,项目的启动只需要启动一个服务器承接浏览器的请求即可,同时在文件变更时,也只需要额外处理变更的文件即可,其他文件可直接在缓存中读取。
对比总结
4. Bundless实现
实现 Bundleless 的第一步是要让浏览器自主加载对应的模块。
使用 type="module" 开启 ESModule
如果type属性为module
,代码会被当作JavaScript模块 。请参见ES6 in Depth: Modules
利用 import-maps 支持 bare import
分享一个在 chrome 中已经实现了的 import-maps 的标准 ,可以让我们直接用 import React from 'react' 这样的写法,未来我们可以利用此能力实现线上的 Bundleless 部署。
面向本地开发的场景,我们只需要启动一个本地的 devServer 承载浏览器的请求映射到对应的本地文件,同时动态地将项目中 import 的资源路径指向我们的本地地址,即可让浏览器直接加载本地的文件,比如可以使用下面的写法,将入口 JS 文件直接指向本地的路径,然后 devServer 再拦截相应的请求返回对应的文件。
如何加载非 JS 的文件资源
浏览器在处理文件时是依据 Content-Type 的,不关心具体的文件类型,所以我们需要在浏览器发起请求时,将对应的资源转化为 ESModule 格式,同时设置对应的 Content-Type 为 JS,返回给浏览器执行,浏览器就会按照 JS 的语法进行解析处理
- Bundless框架介绍
- snowpack
snowpack解决了什么问题?
出于对主流浏览器的判断,SnowPack 大胆采用 ESM,其原理也很简单,内部帮助我们将 node_modules 的代码整理并且安装到 一个叫做 web_modules 的文件夹中,需要的时候直接到该文件夹中引入即可。其目标也是为了解决第三方代码的引入问题。
目前对 node_modules 的处理是做了 bundle 的
它仍然提供了 @snowpack/plugin-webpack / @snowpack/plugin-parcel 这样的插件来让你能为生产环境做打包。所以,配合 module/nomodule 技术,它将会有更强的抵御兼容性问题的能力,这也算是一种渐进式营销手段
vite
Vite was created to tackle native ESM-based HMR. When Vite was first released with working ESM-based HMR, there was no other project actively trying to bring native ESM based HMR to production.
Snowpack v2 initially did not offer HMR support but added it in a later release, making the scope of two projects much closer. Vite and Snowpack has collaborated on a common API spec for ESM HMR, but due to the constraints of different implementation strategies, the two projects still ship slightly different APIs.Both solutions can also bundle the app for production, but Vite uses Rollup with built-in config while Snowpack delegates it to Parcel/webpack via additional plugins. Vite will in most cases build faster and produce smaller bundles. In addition, a tighter integration with the bundler makes it easier to author Vite transforms and plugins that modify dev/build configs at the same.
Vue support is a first-class feature in Vite. For example, Vite provides a much more fine-grained HMR integration with Vue, and the build config is fined tuned to produce the most efficient bundle.
5. 扩展-Cloud IDE
未来趋势:Cloud + Browser Based Bundless + Web NPM
- 把服务端的能力进行输出。这种方案的优势是服务端拥有和本地研发环境一致化的环境;缺点是即时性较差、效率较差、无法离线、成本高昂。
- 把客户端的能力释放出来。这种方案的优势是无服务端依赖、即时性、高效率、可离线运行;但缺点也比较明显,所有能力建设都必须围绕着浏览器技术。
Gravity 架构大图
其实,Clever就是一个Cloud IDE
6. Reference
- 探讨不需要打包的构建工具 Snowpack
- Webpack 打包太慢?来试试 Bundleless
- Vite
- 链接