原文链接: https://geeknote.net/Rei/posts/286
自 Rails 6 引入了 Webpacker 以来,Rails 的前端部分就引发了很多吐槽。吐槽主要分两类:
有关 Webpacker 的安装和使用问题,资深 Rails 开发者也不一定懂解决。遇到这些问题都建议先跳过 Webpacker。一个号称开发者友好的框架,却要在一开始跳过某个模块,这着实劝退了一些人。
不过这个问题有望在 Rails 7 解决。本文就来前瞻一下 Rails 7 的前端方案。
首先要了解一个问题,为什么前端需要构建工具?
前端构建工具是为了处理以下问题:
Rails 的 Asset Pipeline 就是为了处理这些问题而诞生。首次引入 Asset Pipeline 的 Rails 3.1 发布于 2011 年 8 月 31 日。相比之下,NPM 发布于 2010 年 1 月 12 日,当时的打包方式还没形成共识。而 Webpack 发布于 2014 年 2 月 19,比 Asset Pipeline 晚了两年半。当时 Asset Pipeline 设计是领先的。
从那以后,前端领域有了很多发展。一个是打包方式的确立,从 AMD、CMD、UMD 到 ESM;一个是 ES6 语法的普及,同时又多了 TypeScript;另外还有浏览器原生支持了 ES6,HTTP/2 实现了多文件并行下载等。
相比之下,Asset Pipeline 的打包就跟不上变化了。它基本上是把源码编译之后,进行字符串拼接。因为不是基于语义层面进行打包,所以它不理解各种打包规范的语法,也不能进行代码裁剪。
这时候一种方案是用 JavaScript 社区的打包工具替换掉 Asset Pipeline,Webpack 就是其中一个。Webpack 是前端社区打包工具的集大成者,通过插件机制可以实现各种前端代码编译打包和拆分。Rails 基于 Webpack 加上自己选择的插件和配置就是 Webpacker。
但 Webpack 也有一些问题,最主要的就是它的配置过于复杂。为了什么都能兼顾,也就什么都要配置。Rails 引入 Webpacker 之后,虽然解决了如何打包复杂前端代码的问题,但它本身也是个问题,它和 Asset Pipeline 并存也让不少原先的 Rails 开发者感到困惑。
在吸取了 Rails 6 的教训后,Rails 7 将会在前端管理方案做出改变。DHH 最近写了一篇文章描述他的设计:《Rails 7 will have three great answers to JavaScript in 2021+》。
概括来说,Rails 7 提供了三个前端方案:
下面分别介绍这三个方案。
这是 Rails 7 的默认方案。
Asset Pipeline 功能跟之前的作用类似,不同的是默认不对 CSS 和 JavaScript 进行编译和打包。不编译和打包的前提是现在的浏览器都已经原生支持 ES6,可以把 ES6 直接发送给浏览器。同时由于 HTTP/2 协议实现了多路复用,零碎的前端文件不再是问题,还可以得到细粒度缓存的好处。
不过无 bundle 方案有一个问题要解决,就是如何处理加载路径。例如对于代码:
import "stimulus"
浏览器会加载 stimulus.js
这个文件。但是为了缓存,stimulus.js
这个文件的文件名会加上一串哈希值,变成 stimulus-abcdef.js
。为了让浏览器找到需要加载的文件,出现了 ImportMap 这个标准。
ImportMap 的原理是在 HTML 的头部插入一段 json 数据,描述 ES6 模块和文件名的对应关系:
<script type="importmap">{
"imports": {
"stimulus": "/assets/stimulus-abcdef.js"
}
}</script>
这样浏览器在执行 import "stimulus"
的时候,就知道要加载 /assets/stimulus-abcdef.js
这个文件,而开发者无感知。
这个方案是否能成为以后的主流,我认为还需要观察。首先 ImportMap 还是草案标准(Import Maps),Chrome 和 Edge 以外的浏览器需要额外的库补充。其次有一些前端的库是以开发环境有打包器为前提开发的,一个库拆成了很多库分发,形成依赖的依赖。而 ImportMap 处理不了依赖的依赖。
我觉得 ImportMap 最大作用是去掉 Rails 默认栈的 Node.js 依赖,不用安装 Node 就可以基于 Rails 的默认栈进行开发。如果需要用到比较多的第三方库,就需要下面的 bundling 方案。
cssbundling-rails
和 jsbundling-rails
是 Rails 新增加的两个 gem 包,用于引入外部的前端编译/打包工具。
以前的 Asset Pipeline 是一个编译/打包/哈希一条龙的工具,但如前面提到过,编译/打包方式已经赶不上前端的变化,所以新的方案是把这部分工作交还给前端工具处理,Sprockets 只处理最后的哈希这一步。
cssbundling 默认支持 tailwind|bootstrap|postcss|sass
等 CSS 处理前端,jsbundling 默认支持 esbuild|rollup|webpack
等 js 处理前端。
没有看到需要的处理前端也没关系,其实阅读这个两个 gem 的代码可以发现,这两个 gem 内部并没有运行时代码,只是一些安装配置。自己仿照这些配置就可以任意引入其他处理器,只要把构建好的文件放入 app/assets/builds
文件夹就行。
这个方案适合多数现有需要编译前端代码的项目。相比原先的 Asset Pipeline,外置构建工具可以获得完整的前端生态支持。和 Webpacker 方案相比,这个方案把选择权交还给了开发者,不会一上来把人搞懵。
最后一个方案是 API mode,前后端分离,甚至前端部分独立一个项目,Rails 只负责 API。
API mode 其实从 Rails 5 就支持了,创建的命令是:
$ rails new myapp --api
使用 API mode,前端怎么做就与 Rails 无关了。
Rails 7 的前端方案是对过往的经验总结,找出一套渐进式的前端方案。一方面降低了新建项目的门槛,不用一上来就面对 webpack 这样的巨无霸,另一方面在引入外部编译工具的时候给开发者充分选择权。
现在 Rails 7 alpha 版已经发布,有兴趣的可以进行测试,遇到问题及时向官方反馈。
让 Rails 再次简单。