@tangzx 打了鸡血的开发者,来分享一下你用sublime+node+coffeescript开发的流程吧

2013-05-30 18:29:34 +08:00
 liaa
@tangzx
First thing first: ST+node+coffeescript is "cool"
## 我的问题
1. 如何管理 *.coffee 的文件:
因为有时候他们分布在好几个文件夹中, 使用怎样的coffee命令同时管理
2. 如何设置环境变量,同时如何设置config文件的.我是这样设置的,然后在app.js中就使用config这个变量

ps: 虽然是个新手,可是总是对workflow这件事很在乎...求解答
383 次点击
所在节点    自言自语
12 条回复
liaa
2013-05-30 19:32:38 +08:00
追加:
3. what's your bash and sublime text theme and colorscheme.
tangzx
2013-05-30 21:38:52 +08:00
@liaa 好激动一定连夜写今天不写完不睡觉
liaa
2013-05-30 22:00:50 +08:00
@tangzx 感谢~ 其实自己也是个宅,技术养成中,要成为战斗力超强的那只码农.从前端杀到后端,再杀回前端,再杀回后端...谁叫我们是JSer呢~
tangzx
2013-05-31 00:17:36 +08:00
鸡血文来啦~~: 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)这套颜色,效果大致为下图↓

![ ]( )

![ ]( )
tangzx
2013-05-31 00:18:26 +08:00
@liaa
太在理了
> 要成为战斗力超强的那只码农.从前端杀到后端,再杀回前端,再杀回后端...
liaa
2013-05-31 01:05:06 +08:00
@tangzx 我刚刚上来,看了码了这么多一股股感动.不过实在等不及了,先看了再说~
liaa
2013-05-31 01:41:29 +08:00






liaa
2013-05-31 01:42:48 +08:00
@tangzx 很明了了,大号感谢送上~
lenville
2013-05-31 13:33:00 +08:00
@liaa
@tangzx

捉到两只野生萌货,此帖甚赞
liaa
2013-05-31 13:55:18 +08:00
liaa
2013-05-31 13:56:07 +08:00
lenville
2013-05-31 14:55:48 +08:00
@liaa 太棒了,感谢已发

我今天折腾下Arch, 等我回来, 如果我失败了就晚上上手机好了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/70687

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX