鸡血文来啦~~:
http://posts.micy.in/2013-05-31-managing-coffee-project.html # 俺是咋管理CoffeeScript项目的
First thing first: ST+node+coffeescript is "cool", 俺大部分的项目是服务端的nodejs项目,故俺这次分享的方法也许不太适用于其他类型的项目。
## 俺是咋管理这堆`.coffee`文件的
首先、你需要在使用`coffee-script`模块还是发布前编译`.coffee`文件之间做一个选择,首先让俺来说下俺的观点吧,俺是推荐在nodejs项目中使用前一种方法的,即:
1. 将`coffee-script`模块加入到你的`package.json/dependencies`中去
2. 在入口文件(默认情况下为`./index.js`)中使用如下语句:
```js
// ./index.js
require('coffee-script'); // 引用`coffee-script`模块会加一个对应`.coffee`扩展名的require钩子
module.exports = require('./app'); // 于是在这里就可以像引用`xxx.js`文件一样地引用`app.coffee`了
```
这样做显而易见的优点是:
* 方便,不需要本地安装coffee命令(其实是全局(`npm install -g`)安装`coffee-script`模块)
* 源代码管理也方便
不过之前看到过一些对此做法的反驳,故俺一一解之
* 一个项目由许多人共同完成,有的人只想写js,有些人想写coffee
真心不影响哦,你只要在项目的最初入口出有`require('coffee-script');`过一次,之后再`require`时便`js`和`coffee`都能引用了,在`coffee`里一样能引用`js`,写法也不变(`db = require './db' # 引用了./db.js`);你甚至可以用`coffee`来重构别人写好的`js`,或者反其道而行(所以`require`时最好不要带扩展名,这样重构之后就不用更改引用的语句了)
* 实时编译`.coffee`会有效率问题
正如上所述,`coffee-script`模块加了一个`require`钩子,`require`时编译`.coffee`文件,故和`require`普通`js`文件一样,该编译操作只会执行一次,并且该操作后,被`require`的模块便以函数或者对象的形式被缓存了,所以之后再调用时会和普通`js`效率是一样的。
不过,在第一次`require`时,确实是需要花一些时间的,所以咱可以做的事儿就是尽量在代码的最外层`require`,即让程序启动时编译所有的`coffee`,免得之后再编译影响用户体验了。编译大概要多少时间呢?俺觉得还是可以接受的,俺这里有个数据给你参考一下:
俺现在所在公司的一个小项目的服务端代码是用`IcedCoffeeScript`编写的,有**42**个`.iced`文件(`find . | grep .iced | wc -l`),这些`.iced`文件中代码总行数为**2862**行(<code>cat `find . | grep .iced` | wc -l</code>),在俺的2011未升级的硬盘快装满的老爷最低配mbp上启动要大约要3~4秒(包括连接本地mongodb和绑定http端口)
### 假如你的项目为前端项目或者你就是不想依赖于`coffee-script`模块
如果你一定需要将这堆`.coffee`编译成`.js`的话,我这里推荐你使用 Makefile ,不过 Makefile 在 Windows 上就很是捉急了,如果你的项目组里有成员使用 Windows 作为开发机,你就得考虑给他安装`cygwin`,并且随时注意你写的 Makefile 中调用的工具链的cygwin兼容性了。
虽然前端工程师们自己也有创造许多优秀的工具如`yoeman`、`Grunt`还有国内那些厂商做的一堆啥啥之类的,但是俺在这里还是推荐挺原始的Makefile([TJ也推荐咱用Makefile](
https://groups.google.com/forum/#!topic/express-js/me3FL5wY7RE)),因为:* make 是极其简单而且成熟的产品,不会动不动改动升级,不带有任何编程语言和行业偏见(尽管它对Windows有偏见)
* Makefile 是描述式语言而非流程式语言。
* [不是make独有的特性] make 根据文件的mtime决定了哪些文件需要编译,便会只编译那些新更改过的文件,所以写一个好的 Makefile,便可以实现永远地增量编译。更好的是,咱可以用 `watch make`命令达到类似于“实时编译”的效果而不占用多余cpu。
* [不是make独有的特性] make 可以分析依赖关系,管理多线程同时编译,最大化你的多核机器的效率(或者节省等待io时阻塞浪费的时间)。
俺在这里举个栗子吧,首先做出一个假设:某个项目中的服务器端代码全部是 CoffeeScript,则`Makefile`应该包含:
```makefile
COFFEEBIN = node_modules/coffee-script/bin/coffee # 用**安装的模块中包含的coffee命令**代替**全局安装的coffee命令**
COFFEE = $(shell find . -name '*.coffee') # `find`和`ls`的区别就是: `find`列出当前目录和所有子孙目录下的文件,而不仅仅是当前目录下的文件
COFFEEJS = $(COFFEE:.iced=.js)
# 以上这三个变量均在 make 载入时确定其值
all: $(COFFEEJS) # 此处定义了第一个目标(默认目标)为所有 coffee 对应的 js
%.coffee: %.js
$(COFFEEBIN) -c $< # `$<`是一个 [Makefile的特殊变量](
http://www.gnu.org/software/make/manual/html_node/Static-Usage.html#Static-Usage)
```
于是你便可以使用`make`命令将项目中的所有(更改过的)`.coffee`文件编译成`.js`文件了。故你还需要一部:别将这些编译出来的`.js`文件提交到代码仓库里面(它们只是编译结果,不应该被提交)
```
...
# 确定你的`./.gitignore`中包含这一行:
*.js
...
```
## 俺怎样使用环境变量配置nodejs程序
Windows和xNIX中都有“环境变量”这个概念,但是Windows的环境变量不管是用法还是规则都有些特别,故这里暂只讨论`POSIX环境变量`(适用于OSX和linux)
首先,俺推荐使用环境变量而非配置文件来配置应用程序,Heroku和CloudFoundary都采用这两种方法来配置和传递应用程序的服务接入点,并且Heroku在其发布的[12 Factors App宣言](
http://www.12factor.net/config)中也说明了这样做的好处: 配置随着代码走既不方便调试也容易产生安全问题。
例如,Heroku和CloudFoundary都采用`PORT`环境变量标示Web应用程序应该监听的端口,所以我们代码中应该这样写(Express的官方示例也是这样写的):
```
server.listen (Number process.env.PORT||3000), (e)->
throw e if e
console.log "俺跑在了#{server.address().address}:#{server.address().port}上"
```
而我们在本地调试需要启动程序时,如果想把上述程序跑在**8000**端口上,则需要执行命令
```
# 一条命令
PORT=8000 node ./index.js
# 或者两条命令
export PORT=8000 # 注意这里一定要加export,因为在 interactive bash 中,每敲一下回车会启动一个子shell,不export的话,子shell中的环境变量便不能导出到当前会话中
node ./index.js
```
使用`export PORT=8000`,将会把`PORT`变量设置到当前的终端会话中;直接使用`export`命令可以查看当前会话中所有环境变量的值
### 其实可以永远将开发环境中所用的值作为默认值
正如以上使用`Number process.env||3000`作为端口一样,为了方便,可以使用开发环境的值作为默认值(express也是这样做的:如果不设置`NODE_ENV`环境变量,express就是用`development`配置,否则就使用`NODE_ENV`指定的配置)
所以俺的代码中便出现了以下片段:
```
# 配置数据库
dburi = process.env.DBURI
dburi?= "mongodb://localhost/ForensicHub-development"
```
```
# 配置OAuth服务器
process.env.AUTHSERVER?= 'http://192.168.18.187:8001/' # 公司内网给开发测试们用的OAuth服务器
process.env.CLIENT_ID?= 'ForensicHubTEST' # 开发专用ID/SECRET,OAuth重定向到 http://localhost:3000/oauth_callback
process.env.CLIENT_SECRET?= 'TESTSECRET' #
```
## 俺的ST和bash用啥color colorscheme
其实俺对这个也没太大讲究,其实是用一段时间看得有些累了就换一个,个人喜欢比较柔和一些的颜色搭配,写下这篇分享时俺的iTerm2和SublimeText都在用[Solarized(Light)](
https://github.com/altercation/solarized)这套颜色,效果大致为下图↓![
]( )
![ ]( )