Propshaft 简介
有留意 Rails 更新的人应该会注意到,Rails 7 新增了一个组件选项 Propshaft。
$ rails new --help
-a, [--asset-pipeline=ASSET_PIPELINE] # Choose your asset pipeline [options: sprockets (default), propshaft]
# Default: sprockets
Assets Pipeline 是 Rails 从 3.1 开始内置的前端文件处理机制,它内部实现的库叫做 Sprockets。过去谈论 Assets Pipeline 跟 Sprockets 几乎不做区分,因为两者几乎重叠。而 Rails 7 开始 Assets Pipeline 提供另一个实现,那就是 Propshaft。
Propshaft 的诞生
Sprockets 是一个完整的前端构建工具,它可以对 js,css 进行编译、打包、最小化等处理,支持 CoffeeScript,Sass 编译器,还有一套自制的链接声明。如果只使用 CoffeeScript 和 Sass,并且所需的库都有对应的 gem 包,那么它的工作一直良好。
到了 Rails 7,新的前端方案是 Assets Pipeline + JS/CSSbundling,静态文件的编译、打包、最小化等处理都在 Assets Pipeline 之前进行,Pipeline 只需要做文件名哈希和提供文件名映射,这时 Sprockets 的功能就变得冗余了。
引申阅读:Rails 7 前端方案前瞻
功能的冗余有时会导致 Bug,例如已经编译好的 js 文件,再经过 Sprockets 处理会在末尾插入一个 ;
,有时会导致问题(Issue #24)。目前 Sprockets 内部有大量预设的处理器,很多都用不上。理想情况下,Sprockets 应该提供配置方法关闭内置的处理器。也许是 Sprockets 的代码历史包袱太重,DHH 选择了新建一个简化版的 Sprockets——也就是现在的 Propshaft。
Propshaft 的功能
Propshaft 只做最精简的功能,包括:
- 管理 paths:配置从哪里引用资源。
- 计算摘要:给文件名加上哈希值,并维护文件名映射。
- 开发服务器:开发环境提供静态文件。
- 基础的内容处理:替换文件内的资源引用地址。
以下功能并不包含在 Propshaft 中:
- 编译 js,css
- 打包
- 最小化
这些功能应该使用外部的编译工具完成。
如何替换 Sprockets
对于新项目,使用以下命令就可以自动配置 Propshaft:
$ rails new myapp -a propshaft
对于已有项目,先要确保不依赖 Sprockets 提供的编译功能,例如换用 Sass 编译 css,用 esbuild 打包 js。
完成 bundling 迁移后,按以下步骤迁移 propshaft:
- 在 Gemfile 中删除
sprockets-rails
,添加propshaft
。 - 运行
bundle
。 - 删除
asset/config/manifest.js
。 - 将 css 文件中的
image_url
,asset_url
等 helper 换成url
。
完成。
值得注意的变动
引用静态资源
Sprockets 在 CSS 上下文提供了一些 assets helper,例如 image_url
,asset_url
来引用静态资源。在 Propshaft 中不需要这些 helper,直接用标准的 url
,它会自行替换。
例如:
- background: image_url('hero.jpg');
+ background: url('hero.jpg');
在 view 中引用静态资源依然使用 image_url
和 asset_url
这些方法。
编译目标
Sprockets 提供了 asset/config/manifest.js
和 Rails.application.config.assets.precompile
两个方法设置编译目标。Propshaft 不提供这个设置,而是把 assets.paths
里面的所有文件当作编译目标。
你可以用以下命令检查 Propshaft 会编译生成哪些文件:
$ rake assets:reveal
如无意外,你会发现很多不需要的文件也被当作编译目标了,例如 app/assets/stylesheets
下的 scss 源文件。
可以用以下配置排除一些目录:
Rails.application.config.assets.excluded_paths = [
Rails.root.join("app/assets/stylesheets")
]
总结
Sprockets 对于已经使用的项目依然可以工作,为了兼容第三方 gem,Sprockets 还会维护很长时间,所以不必急着迁移。
如果项目正在往 bundling 方案迁移,那么不妨一同迁移 Propshaft,让 Assets Pipeline 的流程更精简,减少 bug。