万神劫

万物天地为剑,神鬼妖邪为剑
劫波万渡,宇宙苍穹尽为剑
是为万神劫!

0条评论 2013-06-08

Sea.js 如何与 Rails 结合

前言

Rails 从 3.0 开始提供 Asset Pipeline 来管理静态资源,其中一个重要的功能就是可以通过注释的方式来申明 JS 文件依赖,随后通过服务器端的支持来进行依赖文件的加载。
不过随后纯前端的 JS 依赖管理器大量涌现,比如 RequireJS 和 Sea.js,前端开发人员可能更偏好这种方式。但是功能上来说, Asset Pipeline 更为强大,除了 JS 之外,图片和 CSS 都很好地处理,而且有完善的打包和缓存机制。
所以很自然的我就开始思考如何将这两者结合起来: 既能用 Sea.js 来处理 JS 的依赖,又能享受 Asset Pipeline 的其他功能

说实话,这是我折腾的比较久但是成就感却不高的一件事,目前的解决方案我依然不太满意,所以我的建议是:

  1. 如果你从未听说过 Sea.js 或 RequireJS,请继续使用 Asset Pipeline ,因为对你来说,他已经能够满足你的需求
  2. 如果你很喜欢用 Sea.js 来管理依赖,但又不希望跟后端绑死,那么在 public 目录下新建一个子目录用来放 CMD 模块的代码,然后用我的 spm-chaos-build 来打包
  3. 如果以上都不是你想要的,请往下看

使用方式

请先确保 spm-chaos-build 已经安装(>0.2.2),因为后面的打包依然依赖于它,这里就不赘述了,可以参考我之前的文章

npm install spm -g
npm install spm-chaos-build -g

seajs-rails 这个 gem 加到 Gemfile 里

gem 'seajs-rails'

执行下 bundle install 安装好它,然后执行以下命令初始化项目

rake seajs:setup

这会安装最新版本的 Sea.js 到相应目录下,并在 config 目录生成 seajs_config.yml

目录结构

先看目录结构的约定
与以往的开发一致,普通的业务代码依然放置在 app/assets/javascripts 下,CMD 模块或非 CMD 文件可以混在一起,没有限制
重点是在 javascripts 目录下多了一个 sea-modules 子目录,这是 Sea.js 的 base 目录
刚才的脚本会把 Sea.js 文件安装到这里,你也应当将 jQuery 之类的公用模块通过 spm install 安装到这里

your-rails
├─app
│  ├─assets
│  │  ├─images
│  │  ├─javascripts
│  │  │  ├─a.js    <-- your js code
│  │  │  └─sea-modules    <-- seajs base 目录
│  │  │      ├─gallery
│  │  │      └─seajs
│  │  │          └─seajs
│  │  │              └─2.0.0
│  │  └─stylesheets

seajs_config.yml 配置

自动生成的文件大概是这个样子

seajs_path: seajs/seajs/2.0.0/sea.js
family: klog
output:
  relative:
    - application.js
  all: []
alias:
  $: $
  • seajs_path 配置 seajs 的路径,一般来说不用改动,注意的是这个路径相对于 sea-modules 目录
  • family 配置所有业务模块的 family ,这是从你的 Rails 项目名自动生成的,一般也不用改动
  • output 用于配置合并策略,其实就是 package.json 中的 spm.output ,可参见 spm-chaos-build,简单的说就是 relative 下的文件只合并相对路径的模块,而 all 下的文件会合并所有模块
  • alias 也是合并策略的一部分,其实就是 package.json 中的 spm.alias,你可以啥也不配,不过打包时会有很多 warn

实际的案例,可以参考 https://github.com/edokeh/klog/blob/master/config/seajs_config.yml

加载 Sea.js 模块

seajs-rails 提供了两个 helper 方法,用来引入 Sea.js 和加载模块

<%= seajs_tag %>
<%= seajs_use 'blogs/show' %>
  • seajs_tag 用于引入 seajs ,并且会根据是否合并引入必要的配置
  • seajs_use 用于加载 CMD 模块,支持传递多个模块名称,模块名只需要传入相对 javascripts 目录的路径即可,而且可省略后缀,像示例代码中的 blogs/show

合并发布

seajs-rails 会将 seajs 的打包合并过程嵌入到 assets:precompile 任务中,所以执行以下命令即可

rake assets:precompile

CMD 模块的合并过程不会与原有的 assets pipeline 冲突,但是请将配置分开:

  • 需要合并的 CMD 模块文件请在 seajs_config.yml 中配置
  • 非 CMD 模块的文件请依然通过 config.assets.precompile 配置

合并完成后,不需要改动页面,两个 helper 方法能够自动处理

Precompile的过程

众所周知,rake assets:precompile 的工作原理是将 app/assets 下的文件合并、压缩后丢到 public/assets 目录下,并且会将文件名打上戳,然后通过 manifest.yml 文件记录打戳后的文件名与原文件名之间的关系
这样当你用 javascript_include_tag 的时候,会先判断下是否有 manifest.yml 文件,如果有就生成相应的 script tag html

seajs-rails 做的事情类似,但是对于 CMD 模块是全部由它自己处理,与 assets pipeline 分割开
具体过程是如下:
1. 将 app/assets/javascripts 目录拷贝到 public/assets/ 下,并自动生成 package.json
2. 在 public/assets 目录下执行 spm-chaos-build 命令完成整个打包
3. 将被打包模块的文件名映射关系写入 seajs-map.json 文件中
4. 将内部的 sea-modules 子目录拷贝到 public/assets 下,业务模块已经被打包到这里面了
5. 做一些清理,删除 public/assets/javascripts 目录

comments powered by Disqus