CoffeeScript袖珍手册

自动编译CoffeeScript

CoffeeScript的一个问题在它在你和JavaScript之间又放置入了一层,并且你需要在CoffeeScript文件变化时重新手动编译. 幸运的是,CoffeeScript的有可选的编译方式, 使得你可以在修改和编译之间顺利的进行开发.

我们在第一章已经说过, 我们可以使用coffee命令进行CoffeeScript文件的编译:

coffee --compile --output lib src

事实上, 在上面的例子中, 所有在src文件夹中的.coffee文件都会被编译成JavaScript并被存放到lib目录下面.不过一直的这样运行有一些没效率,那我们就来看看自动化编译吧.

Cake

Cake是一个通过MakeRake实现的非常简单的构建系统. 它是捆绑在coffeee-script包上面的一个库,我们可以通过cake命令来使用它.

你可以创建 cakefile来定义构建的任务.通过cake [task] [option]的方式,Cake可以在会在当前目录自动寻找配置,并执行构建任务.要列出所有的任务和选项,只需输入cake即可.

我们可以通过task()函数来定义任务,它接受一个名称参数,一个可选描述和一个回调函数.举一个例子, 我们创建一个Cakefile和两个目录, libsrc. 并把下面的这些添加到Cakefile中:

fs = require 'fs'

{print} = require 'sys'
{spawn} = require 'child_process'

build = (callback) ->
  coffee = spawn 'coffee', ['-c', '-o', 'lib', 'src']
  coffee.stderr.on 'data', (data) ->
    process.stderr.write data.toString()
  coffee.stdout.on 'data', (data) ->
    print data.toString()
  coffee.on 'exit', (code) ->
    callback?() if code is 0

task 'build', 'Build lib/ from src/', ->
  build()

在上面的例子中,我们定义了一个任务叫build,只要通过cake build的命令就可以执行了.这个例子的运行效果和之前的例子一样,它会把所有src中的CoffeeScript文件都编译成lib目录中的JavaScript文件.你可以在HTML文件中引用lib目录下面的JavaScript文件.

<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<script src="lib/app.js" type="text/javascript" charset="utf-8"></script>      
</head>
<body>
</body>
</html>

当我们的CoffeeScript代码变化的时候,我们还是要手动调用cake build命令,这和理想的情况还有差距.幸运的是, coffee 命令支持一个 --watch选项, 它会监听目录的变化并会实时的做重编译.让我们再定义另一个任务:

 task 'watch', 'Watch src/ for changes', ->
    coffee = spawn 'coffee', ['-w', '-c', '-o', 'lib', 'src']
    coffee.stderr.on 'data', (data) ->
      process.stderr.write data.toString()
    coffee.stdout.on 'data', (data) ->
      print data.toString()

如果一个任务依赖于另一个任务, 你可以使用invoke(name)的方式来运行另一个任务. 让我们在我们的Cakefile中添加一条任务,它可以打开index.html并开始监听他引用的源文件的变化.

task 'open', 'Open index.html', ->
  # First open, then watch
  spawn 'open', 'index.html'
  invoke 'watch'

你也可以使用option()函数来定义任务的选项,一个选项包含一个参数短名称, 一个参数全名和描述.

option '-o', '--output [DIR]', 'output dir'

task 'build', 'Build lib/ from src/', ->
  # Now we have access to a `options` object
  coffee = spawn 'coffee', ['-c', '-o', options.output or 'lib', 'src']
  coffee.stderr.on 'data', (data) ->
    process.stderr.write data.toString()
  coffee.stdout.on 'data', (data) ->
    print data.toString()

你可以发现, 任务的上下文获取了一个包含用户数据的options对象.如果你直接使用cake命令而没有加上其他的参数, 所有的任务和选项都会被列出了.

Cake的伟大之处在于它可以编写各种自动化任务,例如自动编译CoffeeScript而不经过bash命令或者Makefile. Cake的源文件也很值得一读, 它本身就是包含CoffeeScript的表现力, 并且它的注释也写得很漂亮.

服务器端的编译支持

使用Cake的方式来编译对于静态站点来说很合适,但是对于动态站点,我们可能就需要把CoffeeScript的编译过程整合在请求\响应的过程中.目前在一些框架中已经出现了一些整合方案,例如RailsDjango.

在Rails 3.1中, 可以通过Sprockets & the asset pipeline来支持CoffeeScript.在app/assets/javascripts目录下面存放你的CoffeeScript文件, Rails可以很智能的在文件请求前预处理. JavaScript文件和CoffeeScript文件都通过特殊的注释指令被串联和打包在一起, 这意味着你可以在一次请求中获取所有的的JavaScript文件. 而对于生产代码,Rails会把编译后的文件输出在硬盘中, 保证它可以被缓存并被快速的访问.

如果你的应用不需要其他的 Rails 特性以及相关的功能, 那么对于Ruby来说,像内置了Rack服务的37signal的Pow和Joshua Peek的Nack都是很好的选择.

Django通过特殊的模块标签也对CoffeeScript提供了支持,它同时支持行内脚本和外部脚本.

不管是Ruby还是Python编译,最终都会输出到Node中,然后通过CoffeeScript库来进行编译,因此在开发时要确保这些都已经安装了. 如果你的网站直接是用Node搭建的, 整合Coffeescript就更简单了,你也可以在前后端同时使用CoffeeScript.我们会在下一章详细介绍这个, 并使用Stitch来提供客户端的CoffeeScript服务.