10 个 Node Hacker 的习惯(2016)

2016/5/14 posted in  Javascript comments

翻译自:http://blog.heroku.com/archives/2015/11/10/node-habits-2016

在 2015 年的尾声,JavaScript 开发者有着过剩的工具,现今,我们很容易在巨大的 JavaScript 生态系统中迷失,所以成功的团队遵循指南,以最大限度的利用他们的时间,并保持他们的项目的健康。

这是在 2016 年的来临之际为快乐的 Node.js 黑客们提供的十个习惯,尤其是为应用程序开发人员,而不是模块的作者,因为这些群体有不同的目标和约束。

1. 使用 npm init 开始每一个新工程

mkdir my-awesome-app
cd my-awesome-app
npm init --yes

使用 yes 标记可以直接生成 package.json 文件,生成 package.json 后的第一件事就是指定你当前使用的 node 版本1

"engines": {
  "node": "4.2.1"
}

2. 灵活的使用 .npmrc

npm 不会自动将依赖包信息保存至 package.json

如果使用 --save 标记自动更新 package.jsonnpm 将使用 ^ 安装包,这会使你依赖的模块版本不固定,这适用于模块开发,但不适合应用开发,因为我们想在所有的环境中保证依赖的一致性2

解决方法一:

npm install foobar --save-exact

更好的方法,你可以通过设置 ~/.npmrc 的选项来改变安装的默认动作:

npm config set save=true
npm config set save-exact=true

这样 npm install foobar 将会自动添加 foobar 至 package.json 中,并且将安装固定的版本3

3.搭上 ES6 的火车

Node 4+ 加入了 ES6 的很多特性。不要被一些更复杂的特性吓到,你可以边用边学。ES6 包含很多令人兴奋的小改进:

let user = users.find((u)=> u.id===ID);
console.log(`Hello, ${user.name}!`);

4. 坚持使用小写

有些语言鼓励文件名和类名保持一致,例如 MyClassMyClass.js,不要在 node 中这样命名,而是使用小写文件:

let MyClass = require('my-class');

Node.js 是一个以 Linux 为核心的跨平台工具。OSX 和 Windows 会将 'myclass.js' 和 'MyClass.js' 视为相同,但 Linux 不会,编写跨平台的代码时,需要在 require 表达式中包含确定的大小写。

最简单的方式是:一切文件都坚持使用小写文件名,例如:'my-class.js'

5. 使用集群

node 运行环境被限制为单 CPU 和 1.5GB 内存,在一个大型服务器上部署一个非集群 node app 十分浪费资源。

为了充分利用多核以及超过 1.5GB 的内存,让你的 app 支持集群 吧。即便是你现在只是在一个小硬件上运行一个单进程的应用,集群让你将来更容易扩展。

测试是决定应用理想集群进程数的最好方式,但最好有一个 合理的默认值 ,例如:

const CONCURRENCY = process.env.WEB_CONCURRENCY || 1 

选择一个 集群抽象化工具 而不是重新造一个进程管理的轮子。如果你想分开 master 和 worker 的文件,你可以尝试 forky。如果你喜欢单一入口文件和函数,看看 throng 吧。

6. 注意你的环境

不要使用指定环境的配置文件使你的工程变得混乱!而是充分利用环境变量。
首先,安装 node-forman

npm install foreman

然后,创建一个 Procfile 指定应用的进程类型:

web: bin/web
worker: bin/worker

现在你可以使用 nf 来启动你的 app:

"script":{
    "start": "nf start"
}

提供一个本地开发环境,创建一个被 .gitignore.env 文件,将会被 node-forman 加载:

DATABASE_URL='postgres://localhost/foobar'
HTTP_TIMEOUT=10000

现在,一个简单的命令(npm start)将会在当前环境中同时启动一个 web 进程和一个 worker 进程。并且,当你部署你的工程时,它将 自动适配 新主机的环境变量。

这是一个比 'config/abby-dev.js', 'config/brian-dev.js', 'config/qa1.js', 'config/qa2.js', 'config/prod.js' 更简单也更容易扩展的方案。

7. 避免垃圾

Node(V8) 使用一个懒惰和贪婪的垃圾回收器。默认限制为大概 1.5 GB,它有时会等待到不得不回收内存的时候。如果你内存用量在不断增加,可能不是发生泄漏,而是 node 的 平常偷懒行为

如果想对应用程序的垃圾回收获得更多的控制,你可以通过 Procfile 配置 V8 :

web: node --optimize_for_size --max_old_space_size=920 --gc_interval=100 server.js

如果你的应用跑在一个可用内存小于 1.5GB 的环境上,这一点尤其重要。例如,如果你想将 node 设置成一个 512MB 的容器:

web: node --optimize_for_size --max_old_space_size=460 --gc_interval=100 server.js

8. 将动作关连起来

npm 的 生命周期脚本 为自动化提供很好用的钩子。如果你想在开发你的脚本之前运行一些代码,你可以使用 preinstall 脚本。需要使用 grunt ,gulp,browserify,webpack 来编译资源 ?在 postinstall 里执行脚本吧。
在 package.json 中:

"scripts": {
  "postinstall": "bower install && grunt build",
  "start": "nf start"
}

你也可以使用环境变量控制这些脚本:

"postinstall": "if $BUILD_ASSETS; then npm run build-assets; fi",
"build-assets": "bower install && grunt build"

如果你的脚本太长,可以将他们移到文件中:

"postinstall": "scripts/postinstall.sh"

package.json 的脚本会自动将 ./node_modules/.bin 添加至他们的 PATH 中,所以你可以直接执行 bower 或者 webpack 这种二进制包。

9. 只用 git 管理重要的资源

应用基本上都是由必要的文件和生成的文件组成。当使用 git 这样的源码控制系统时,你不应该管理任何生成的资源。

例如,node app 可能有一个 node_modules 依赖资源目录,你应该从 git 中将它忽略。只要每个依赖都列在 package.json 中,其他人都可以通过执行 npm install 来创建一个此应用的本地副本 - 包括 node-modules

追踪生成的文件会导致不必要的麻烦,并且会让你的 git 历史记录膨胀。更糟的是,由于有些依赖是在本机上编译生成的,将他们加入版本控制会降低你的应用的可移植性,因为你提供了一个单一的,可能错误的构建环境。
同理,你也不应该添加 bower_components 或者 grunt 编译生成的资源。

如果你之前不小心添加了 node_modules,你可以通过这样删除它:

$ echo 'node_modules' >> .gitignore
$ git rm -r --cached node_modules
$ git commit -am 'ignore node_modules'

我还忽略了 npm 的日志文件,防止它们弄乱我的代码:

$ echo 'npm-debug.log' >> .gitignore
$ git commit -am 'ignore npm-debug'

通过忽略这些不必要的文件,你的仓库将会变得更小,提交将会更简单,也能避免生成目录中的冲突合并操作。

10. 简化

技术预言是出了名的不准,但是我还是为即将到来的一年提出一条。我预言:2016 年将会是 JavaScript 简化之年。

越来越多的开发者们都已简化其架构。不再使用庞大的 MVC 架构,他们 构建静态的前端项目 ,可以通过 CDN 部署,动态数据由 Node.js API 提供。

我们也开始看到复杂构建系统对我们项目的阻力。领先的开发者们正在简化他们的构建,例如使用一个”普通“的构建,而不需要 bower, gulp, grunt

最后,我们将在 2016 年简化我们的代码,一方面会从移除一些特性着手,就像 Douglas Crockford 的 "The Better Parts.",另一方面会从增加特性着手,就像我最喜欢的回调代替方案:Async/ Await。async-await 暂时还不能在 Node 中使用,但是通过 Babel 你可以现在就使用它。

不要在看你能一次塞入多少个工具和框架了,尝试简化你的工作吧!


  1. 固定的 node 版本往往可以避免很多麻烦事,最好让团队内部都使用同一个 node 版本。 

  2. 我在开发中确实遇到各种环境问题,大部分都是因为依赖的版本号不确定,导致安装了不同的版本而造成的。 

  3. 如果你不想改变全局的设置的话,可以在 package.json 所在目录新建一个 .npmrc 文件,并添加 save=true 以及 save-exact=true 配置,这样在执行npm i foobar 时便会安装固定的依赖版本,并将安装的依赖自动保存至 package.json 中。