祝女主人女神节快乐!

今天是个特别的节日,当然要有个特别的专题给特别的人,对啦,这就是花府的女主人。

忽然,思绪就被拉回到一些照片定格的时间,那时,吃货还是个时髦的词,花叔还是个瘦子。于是一个貌美如花负责吃喝玩乐,带着一个负责赚钱养家,开始了一场如星辰大海般的吃途。

随着照片的年代越久远,除了能看出当时手机摄像头的薄弱外,最明显的就是身材。以至于昨天见到老同事,那看我的小眼神。当然,上天是公平的,时光刻刀留下的痕迹也不止留在我一人身上,女主人在这个幸福的便当里光速迷失,也渐渐远离了窈窕二字。

即然是吃喝玩乐,那就要走出家门,去心中的远方,两个人的旅行,好过一个的漂流,在几年间,去了不少的地方,那些年许过的环游世界梦想,渐渐变成了现实,越来越多的小旗帜插在地图上各处,出行的劳累竟都变成时间长河中慢慢的记忆。

品尝了夜的的巴黎,踏过下雪的北京,累计了许多飞行,用心挑选纪念品,拥抱热情的岛屿,搜集了地图上每一次的风和日丽。这是陈绮贞的歌,忽然就哼了起来。

生活的琐事,总也甩也甩不掉,工作、生活、家庭。这些年,总有很多的事情,回首当时,都是一种焦灼,但如今再望时,发现不过是世间的一粒尘埃,都不值得一提。不过在这些事情的记忆中,都有一个要感谢的人,我是一个急躁的人,情商也就一般,但女主人是我的另一面,总是让人学着沉着。

中年而立,忽然对生活多了一些看法,那些以前看不惯的装饰、滤镜,现在再回首看,已经是热爱生活的标志了。在经历这么欢喜和忧伤,生活就也开着变得平淡起来,每一寸的阳光,都能改变一片的心情,于是那些还在为美动手的事,总会被拿起赞赏。于是,去年,在女主人的执(Bi)领(Po)下,装修了家里的院子,那段时间,为了装扮这个小院,家里忙碌了几个月,不断的添购,终于一个开满鲜花的地方,迎接了一次又一次的朋友来访。正是这些鲜花冠名,我们为小院起名叫花府。(这也是花叔名字的来历哦)

女主人说,一定要热爱生活,这样你才会过的有意义,所以我经常给同事安利,一定要多出去走走,这样你回首时,才不会感到青春的落寞。

回到工作,对一个码农来说,有一个设计师的老婆是一件很了不得的事,这几乎是一家创业公司的标配,况乎女主人还转型做了产品。业余的时间,差不多就是你帮我的文章配个图,我给你讲讲你前天写的三生三世组件编排。会觉得无聊,会吗?😜

回头一看,女主人正在很努力的写东西,边上放了好几支笔(败家),字写的很好看,这解决了一个大问题,将来小孩作业家长签字的问题。

热爱生活,艺术天份,努力,自然,气质,这些词送给女主人。如果要在这个节日要送一个特别的礼物,那一定是这些年来,我一直放在心里的那份感激,并附上我最高水平画像一副:

DevOps - Server Manage Practice

不要用 root

添加一个运维的组:

1
2
# deployer
$ groupadd devops

添加用户,加入到新建的组中:

1
2
3
4
# 添加一个用户 ares, -G 加到devops组里,-m 创建用户目录,-N 不创建同名 group。
$ useradd ares -G devops -N -m
# 给用户设置一个密码
$ passwd ares

## 给账号免 sudo 的能力

在运维发布时,推荐使用 passwordless sudo。这样非 root 用户也可以直接使用 sudo 命令,而不必通过 PTY 来输入密码。Guide:

其实就是在系统里,给指定用户赋上某些指令的 sudo 权限。在 Ubuntu 下,修改 /etc/sudoers 来添加要使用的命令。

1
2
3
4
5
6
7
8
9
10
/etc/sudoers

# 给指定用户,添加 passwordless 命令
ares ALL=NOPASSWD:/usr/sbin/service, /bin/ln

# 也可以设置一个组
%devops ALL=NOPASSWD:/usr/sbin/service, /bin/ln

# 也可以将所有程序都设置为不要密码,不过太不安全,不建议
#ares ALL=(ALL) NOPASSWD: ALL

## ssh-copy-id

输入服务器用户密码后就 deploy 就进行了。不想每次都输密码,ssh-copy-id 可能是你想要的。

每次运行 cap 都要输入密码,可以将本地的 ssh公钥 存到 server 上,就可以省下很多时间。

ssh-copy-id 就是这么一个将本机的公钥复制到远程机器的 authorized_keys 文件的工具,其也能让你拥有远程机器的 home, ~./ssh , 和 ~/.ssh/authorized_keys 的权利。

首先本地机器上要创建 ssh key

1
$ ssh-keygen
1
$ ssh-copy-id aers@192.168.1.1

macOS 上 ssh-copy-id 不是默认安装的,可通过 Homebrew 进行安装

1
$ brew install ssh-copy-id

Shipit Node App with Docker

上面提到如何在代码部署到 Remote Server 后,将 Sercert file link 到相应位置,然后通过 PM2 启动服务。

但我们真实的项目,是构建 Docker 镜像然后启动镜像来实现最终的发布。

这里的流程又是什么样子呢?

  1. 将代码放到 remote server 指定位置(已完成)。
  2. 在 remote server 上将 shared dirs/files 放到指定位置。
  3. 在代码目录下 build docker image。
  4. 启动。

但实践中,发现一件很麻烦的事:docker dislike symbolic link 😓

shiptit-shared-copy

首先的是,app 目录中不能含有 soft link 文件,不然不会被 copy 到 docker 镜像中。

像 config/application.yml 这种通过 link 方式存在的,就不行了。

所以,直接 fork shipit-shared 项目,把 symbolic link 改成 copy。

每次都会把文件复制到 current 对应的 release 版本中。

配置文件和 shipit-shared 保持不变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = function (shipit) {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);

shipit.initConfig({
default: {
shared: {
overwrite: true,
files: [
'config/application.yml',
'config/database.yml'
],
}
}
});
};

deploy-duplicate

解决完 app 内部 soft link 的问题后,然后在 current 下用 docker-compose 构建镜像,然后启动。发现不能重复,原因是,每次构建的目录并不是 current 这个 soft link 的目录。而是 releases/[version] 这个目录。

目录名变化后,构建出的镜像就不一致了,这就导致无法重复的在一个目录下进行多次构建。

compose 构建后的镜像是用 目录名+service 名。

同时也会引发无法销毁的问题,端口被占用。

解决办法也有,就是把releases/[version] 物理复制到另一个 current 一样的固定的位置。起名叫 deploy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.
|-- current -> releases/20170228072117
|-- deploy
| |-- app
| |-- bin
| |-- config
| |-- docker-compose.yml
| |-- Dockerfile
| |-- lib
| |-- package.json
| |-- process.yml
| |-- REVISION
| `-- yarn.lock
|-- releases
| |-- 20170228062744
| `-- 20170228072117
`-- shared
`-- config

这样,每次在 published 后,都将最新的 releases 版本复制到 deploy。然后在 deploy 下执行 docker-compose up -d --build

没有做成单独的 npm,直接放在 shipitfile 中即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = function (shipit) {
// Docker dislike soft link
// So make a physical copy (deploy) instead of softlink (current)
shipit.blTask('deploy-clean', function () {
console.log('cp -R ' + shipit.releasePath + ' ' + shipit.config.deployTo + '/deploy');
return shipit.remote('rm -rf ' + shipit.config.deployTo + '/deploy');
});

shipit.blTask('deploy-duplicate', function () {
return shipit.remote('cp -R ' + shipit.releasePath + ' ' + shipit.config.deployTo + '/deploy');
});

shipit.on('published', function () {
shipit.start(['deploy-clean', 'deploy-duplicate']);
});
}

完美。


REF:: ---

Shipit Node App with PM2

在上一篇中,已经将项目放置在 Remote Server 上了。

在如何启动时,我们有多个选择,现在,看下如何直接用 pm2 在目录下直接启动。

服务器上的目录如下:

1
2
3
4
5
6
7
.
|-- current -> releases/20170228072117
|-- releases
| |-- 20170228062744
| `-- 20170228072117
`-- shared
`-- config

配置

有了上面两个插件的配合,就省力了很多。

在项目中 config 下有两个文件,需要被忽略,所以这里通过 shipit-shared 来配置。

在这之前还有几个问题要被解决:

shiptit-shared

项目中有一些配置文件,里面会存有服务器,DB 的相关安全信息,而且这些信息是跟环境相关,也就是说在不同的环境,它的内容是不一样的。

shipit-shared 就是帮我们做这件事情的。

它可以,在 Remote Server 上建一个公共的目录,手工在里面建立起上述的文件。再在 shipitfile.js 中加入这些文件或目录的配置。

每次 deploy 时,就会自动的将这些文件或目录软链到 current 下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
module.exports = function (shipit) {
require('shipit-deploy')(shipit);
require('shipit-shared')(shipit);

shipit.initConfig({
default: {
shared: {
overwrite: true,
files: [
'config/application.yml',
'config/database.yml'
],
}
}
});
};

shipit-pm2

如果项目是在代码发布完之后,直接通过 pm2 来启动的,那这个插件就很适合。

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = function (shipit) {
require('shipit-deploy')(shipit);
require('shipit-pm2')(shipit);

shipit.initConfig({
default: {
pm2: {
json: '/data/repos/app-koa2boil/process.json'
}
}
});
};

REF:: ---

使用 Shipit 来自动化部署 Node 应用

之前一直想为 node 的发布整理出一个流程,但一直没有太多实践,后来就忙给忘却了,不过最近做了几个小东西,每次发布都要登陆服务器,终于下决心自动化这个流程。

项目结构

Node 的项目结构是这样子的,可参考 github: Koa2-Boilerplate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
├── app
│   ├── apis
│   ├── models
│   └── services
├── bin
├── config
│   ├── application.yml
│   └── database.yml
├── lib
│   └── middleware
├── Dockerfile
├── docker-compose.yml
├── process.yml
├── shipitfile.js
└── package.json

## 整理现在的发布流程

目前仍有 ES Module 不是 Node 支持,所以发布时需要 build 生成发布代码,然后将发布用的代码放到服务器,通过 pm2 启动,或构建 Docker 镜像。

为此,我们构建了两个 repo:

  1. 项目的源码,编译后,生成 dist 为发布用的代码
  2. 编译后的代码,包含各种配置文件,dockerfile, docker-compose 文件。

流程:

  • 源码项目更新,然后 build 出 dist 目录
  • 将 dist 复制到 发布项目,然后迁入 git
  • 服务器拉取发布 git
  • Docker build
  • Docker run

小的项目中,如果不需要对 docker 进行版本说明,以上流程将是一个很简单的事。

如果想要自动化的话,就需要考虑以下两个构建步骤:

  • 代码构建服务器:因为是小的项目,可以不需要中间的构建服务器,直接由本机的另一个路径,或者是服务器的一个路径来承担,建议放在本机,这样服务器就不需要 node 相关的软件了。
  • Docker 构建服务器:docker image 一定要在远程服务器本机处理的,不然传输成本就太高了,这就要求构建服务器,

## 什么是 Shipit?

Shipit 是一个用 Node 写的自动化引擎,也是一个发布工具。

说白点就是 Universal automation and deployment tool,通用自动化部署工具而已。

和 Capistrano 对比

作为 Capistrano 的 Node 版,有什么区别:

Capistrano

  • Ruby 语言(这个对我来说没问题)
  • 在服务器端拉代码,然后进行 build 的。
  • 插件多,社区完善。

Shipit

  • Pure JavaScript,在 Node 上体验会更好。
  • 本地拉取 git repo,本地打包(好处是服务器上不需要配置 node.js 了),然后 rsync 指定目录到 Server
  • 3个月未更新。
  • 支持的插件少,但可以自己写,很简单。

对比完这些,觉得还是 Shipit 更适合一些。


## Shipit Configuration

接下来,就在本机尝试安装和配置 Shipit。

安装

1
2
$ npm install --global shipit-cli
$ npm install --save-dev shipit-cli shipit-deploy shipit-shared

Create a shipitfile.js

Shipit 的运行依赖于配置文件,在项目的根目录,创建 shipitfile.js 就可以开始了。

一个简单的示例(为 staging 环境配置一台远程服务器,并新建一个叫 pwd 的 task):

1
2
3
4
5
6
7
8
9
10
11
module.exports = function (shipit) {
shipit.initConfig({
staging: {
servers: 'root@project.com'
}
});

shipit.task('pwd', function () {
return shipit.remote('pwd');
});
};

这时,就可以通过以下命令 shipit+服务器+task 来运行了。

1
$ shipit staging pwd

## 发布实战:

基于 shipit-deploy 的发布流程

当然一个完整的发布流程,会有多个 task 进行顺序执行,而 shipit 自身也只是定位于一个编排引擎,它提供了 task 的组合能力(基于: Orchestrator)同时,还提供了钩子的能力,能在一些 task 前后加入自己的task(event),这称为 Emit,接下来会用到这些功能。

我们完全有能力基于这些编排组合能力和钩子实现发布的所有流程,但重复从来都是应当被吐槽的。社区也早有一些最佳实践,shipit-deploy 就是 shipit 自己做的一个发布实践。

利用它可以很快速的完成自己的发布流程,同时,它也提供了大量的 Emitter,供我们进行扩展。

更多的可以查看官方文档:

实际项目 deploy 的扩展

对比下 shipit-deploy 的 task flow,我们需要的是在 fetch 完代码后加入以下流程:

  • npm install
  • npm run build

通过 emit 就可以实现,代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
shipit.blTask('npm-install', function () {
shipit.log('yarn install.');
return shipit.local('yarn install', { cwd: '/tmp/app-koa2boilerplate' })
});

shipit.blTask('npm-build', function () {
shipit.log('npm build start.');
return shipit.local('npm run build', { cwd: '/tmp/app-koa2boilerplate' })
});

shipit.on('fetched', function () {
console.log('itis npm build');
shipit.start(['npm-install', 'npm-build']);
});

运行以下命令,就能完成代码获取,构建,发布代码到 Server 上的流程。

1
$ shipit staging deploy

真实的启动流程

经过上面的步骤,可用于线上发布的代码已被放置在服务器上了。那项目中的一些被 gitignore 的配置文件呢。

请看下面两篇:


REF:: ---

逛街引发的数码购物单

今天陪 LD 去逛街,本想去 Line Friends 里转转,但队伍实在是太长了,瞬间没了兴趣,还没有吃到好吃的东西,感觉淮海路是为数不多的不适合吃饭的地方。

期待新 iPad Pro

新开了一家 Apple 店,是之前没有转过的,刚好转去看了一下, LD 是一位艺术家,随手画了几笔,立即把我打动了,本着每一个爱好都应被呵护的想法,准备送一个 iPad Pro + Pencil,回家做了下功课,感觉三月新品发布会应该有新款发布,取消 Home 键,更快的处理器,更大的内存,买新不买旧,那就再等等 😄😂

iMac 5K

说话,前天没有开车,坐地铁时带上了 Kindle,原来放了一年还有电,厉害。中间看了一路的书,快到 站时收起书,换上手机,竟然被 iPhone 的细腻感动到了。

这就是我对 iMac 5K 的期待吧,别挤牙膏了,出个让人满意的吧。真的想入了。

Apple-3月春季发布会-预测::Devices

设备 更新介绍 价格 上市时间
MacBook Pro 小更新 Kabylake CPU -.– 2017.03.21
iMac 27 KKK,今年终于赶上 Intel 的节奏了,KabyLake,DDR 4,USBC,AMD显卡 -.– 2017.03.21
iPad Pro 2 据说更新三款 iPad Pro 2 (12.9/10.5) 去除Home键,同时采用极窄边框。 -.– 2017.03.21
iPad Mini 应该也会更新一下。 -.– 2017.03.21

LG UltraFine 5K

除了旧例体验 iMac 27外,还多看了一眼边上的 LG 5K,比 DELL 5K 便宜了一半,效果和 iMac 27 上的一样,其实就是同一块屏。

可以上下,左右调节。不支持 DELL 那种竖屏,不过也从没有竖起用过。外观,有点太一般了,边框很宽,看起来没精神,不像 U2717d 那般好看。

相对于 iMac 的好外是,可以调节,方便外接,想想之前的 TDM 模式,真难用。
缺点就是没有 iMac 的金属边框的质感,价格也不便宜。7638。额,,有点小贵。

更多 LG UltraFine 5K 看官网:

DELL U2717d

说到 2717d,上周,我把它出掉了,原因是入了 OSMO+ 运动套件,资金有不小压力。当然不是了,只是显示器多,2515 也没怎么用到,就想出一个。

出之前,经常把笔记本背回家,现在没了显示器,也再没背过了,又开始了研究如何同步的问题。

OSMO+

话说,年前放假前两天,入了一个 OSMO+ 运动套装,本想去日本时用,结果今年临时决定在上海过年。

一直说要评价一下 OSMO+ 的,毕竟这一块没人做过,我也是用了好久,才有一些经验的。

所以,就不在这里讲了,回头有机会,专门长篇去测评一下。

如果非要给个一句话总结,就是有钱想玩,真的挺好玩,如果想干专业的事,拍照,一般,拍视频,也一般 。

Webpack 2 in Action

webpack is a module bundler. Its main purpose is to bundle JavaScript files for usage in a browser, yet it is also capable of transforming, bundling, or packaging just about any resource or asset.

传统工具中,流程是,将 js, css, html 各自合并,压缩,形式一个或多个文件,分别在各处引用。

但 webpack 相对于之前的工具区别于,所有的东西都是资源,像 css, js, image 亦或 json 等,可以通过 loader 来进行加载。
同时,它有模块机制,会根据依赖,去把代码自动放在一起,而不用开发的配置。
接下来,一起来走一个流程,来熟悉下配置。


## 安装使用 Webpack
1
2
3
4
# 更推荐使用 yarn 来进行依赖库的操作
$ yarn add --dev webpack webpack-dev-server
# 为了更方便使用 webpack,建议全局安装
$ yarn global add --dev webpack webpack-dev-server

在项目中创建 webpack.config.js 即可开启使用。

可以依据不同环境,增设不同的配置文件 webpack.production.config.js


## 一切都在**配置文件**

Webpack 所有的配置都在 webpack.config.js 文件中。其中包括以下几个大的类别:

Context/Entry/Output

这是几个必备基础配置,我们来一一讲解:

  • context: 配置 entryloader 工作所在的根目录。
  • entry: 应用的入口文件,该文件和其依赖,最终会被编译到一个文件。(可以配置为多个对象,编译出对应个数的结果文件。)
  • output: 入口文件编译后的配置项,可以是一个固定字符串,也可是以一个 [name].[hash].bundle.js 的变量配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
let config = {
context: path.resolve(__dirname, 'src'),

entry: {
app: './main.jsx'
},

output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
filename: "[name].[hash].bundle.js"
}
}

Module

Webpack 是设计为处理 JavaScript 文件的,但其也可以处理任何的文件类型,这归功于强大的 Loaders 机制。

Loader 的使用方法是,通过正则匹配到一些类型的文件,然后对其依次经过配置 loader 的处理。Loader 可以配置多个,倒序依次处理。

示例中,是对 scss 文件的处理,先由 sass-loader 进行编译,然后交由 css-loader,最后由 style-loader 来处理。

1
2
3
4
5
6
7
8
9
10
11
let config = {
module: {
rules: [{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader',
]}
]}
}

Plugins

和 Module 针对文件类型不同的是 Plugin 处理的是:下面,主要讲几个常用的 Plugin 和配置:

- webpack.HotModuleReplacementPlugin

webpack 内置 Plugin,自动热加载,就是在开发时,一旦有文件改动,浏览器会自动刷新。

- webpack.optimize.CommonsChunkPlugin

正如其名,它会让引用模块中重复的地方取出,做成一个单独的文件,这样可以将一些公共的库取出,降低改动带来的更新成本。

如果你正在将应用拆解,打包成多个 output 的话(如果应用的某部分有大量不需要提前加载的 JS 的话,这样做会很有用),那么在这些文件里就有可能出现重复的代码,因为在解决依赖问题的时候它们是互相不干预的。幸好,Webpack 有一个内建插件 CommonsChunk 来处理这个问题:

现在,在 output 的文件里,如果有任意模块加载了两次或更多(通过 minChunks 设置该值),它就会被打包进一个叫 commons.js 的文件里,后面你就可以在客户端缓存这个文件了。当然,这肯定会造成一次额外的请求,但是却避免了客户端多次下载相同库的问题。所以在很多场景下,这都是提升速度的举措。

- webpack.optimize.UglifyJsPlugin

代码压缩,用于生产环境。

- webpack.ProvidePlugin

全局挂载插件,用于挂载老的代码,如 jQuery 之类的。

- Extract Text Plugin

把 CSS 从 JS 中的 import/reuqre 中取出来,放到一个单独的 CSS 文件中。

- HtmlWebpackPlugin

不用开发人员自己在 index.html 中加 bundle.js, bundle.css 等 output 文件,因为这可能是一个 hash 值,这个插件会帮你搞定。

效果:

1
2
3
<link href="/app.4683be2.css" rel="stylesheet"></head>
...
<script type="text/javascript" src="/app.2e17047c719b4525dc77.bundle.js"></script>

- CopyWebpackPlugin

拷贝资源插件
像用了 ant.design,这里也会产生一些文件。

Resolve

最常用的,就是 alias,给一个模块路径起上一个别名,这样在每次 import 时,可以少写很多代码。

Webpack DevServer

DevServer 是一个内建的 HTTP 服务器的独立程序,可通过 webpack-dev-server 命令启动,为开发时提供方便。

它也可以使用 webpack.config 文件来进行配置,或通过命令行参数来进行配置,但有点参数只能通过命令行参数。

一种是命令行配置:

1
$ webpack-dev-server --open --host 0.0.0.0 --port 5000

另一种是在 webpack.config.js 中加入配置项目

1
2
3
4
5
6
7
let config = {
devServer: {
contentBase: path.resolve(__dirname, 'src'),
historyApiFallback: true,
hot: true
}
}

Other Devtool/Externals

Devtool 主要是配置生成何种方式的 Source Mpas。


## 其它事项

ECMAScript 2015 new syntax

一个有着代码洁癖的人,是不会让整个项目中再出现 ES 2015 前风格的代码的,如何解决 webpack.config 呢?

其实有个很简单的办法,把 webpack.config.js 改名成 webpack.config.babel.js 就可以了。

Webpack 在执行时会先用 Babel 把配置文件转成 ES5 代码再继续处理。一切 Babel 支持的语言特性都可以用。


## REF:: ---

Git 201 - Multiple Users Config


公司用 git commit 来统计数据后,一台电脑上的 git 就有了多种配置。


## 方案一、单独配置

除了 global 外,每个 repo 都会有自己的配置项,可以进行单独配置。

1
$ git config user.name "Lanvige Jiang" && git config user.email lanvige@example.com

The values will then be stored in in the .git/config for that repo rather than your global configuration file.

原理是 add following information in your local .git/config file

1
2
3
[user]  
name = Your Name
email = your.email@gmail.com

Check,确保

1
2
3
4
5
$ git config user.name
$ git config user.email

# 或者查看全部,包括 global 和 local
$ git config --list

但这个很繁琐,每个新项目都要设置一次,而且提交时没有报警,很容易忘记。


## 方案二、每次提交时带上配置
1
git -c user.name='Lanvige Jiang' -c user.email='lanvige@example.com' commit -m '...'

REF::

Koa2 Boilerplate

这是我整理的一个 koa2 + es7 的一个最佳实践,用了一些新的 Feature,完成了全部流程,从 request 到 service 和 DB(Sequlize)到 response。


## Features

koa2 & koa-router

koa 相对于 express 更吸引开发者的地方莫过于 U 型 Middleware 机制。

Babel

目前 node v6 已经支持了绝大多数新的语法,http://node.green/

目前用下来只有两个 feature,就是 asyncFuncation 和 module,所以在配置项中,只需要开启这两项就够了。async 会被编译为 generater。

1
2
3
4
5
{
"presets": ["es2017"],
"sourceMaps": "both"
}

AsyncFuncation

通过 babel 来实现了 async-await (为了 async 的美可以做出任何牺牲)。

Module

ES 6 中模块化有一些显著的变化,像 import/export,具体见

标准已经制定:修改文件名后缀为 .mjs 但目前仍需要 babel 来转。

DI Container

因为没有模块,所以大量的引用散落在各处,一量修改,真的是痛不堪言。

DI 可以统一管理这些依赖,只需要修改一处,当然最大的好处莫过于解耦,便于测试。

这里用的是 Awilix

Environment

通过 yenv 来实现环境变量管理。

Sequlize

我们在项目中大量的使用了 Sequlize,也吐槽了很多,这里只是一个最简单的结合示例。


## Directory structure

一般通过 node 创建的 web 项目,通用的作法是将源码等放在一个 src 的目录下,这样的好处是为了方便编译,感谢 babel,可以提前享受 ES 新语法。

后端项目也有一些这样的实践,但这里并没有采用,原因是随着 node 对标准的支持,在不久的将来,我们线上的代码是不再需要编译的。可以像 rails 一下直接运行(好期待那天)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
.
├── app
│   ├── apis
│   ├── beapis
│   ├── models
│   ├── services
│   └── validators
├── bin
│   ├── _babel.js
│   └── server.js
├── config
│   ├── application.yml
│   ├── database.yml
│   └── redis.yml.example
├── db
├── lib
│   ├── createContainer.js
│   ├── createServer.js
│   └── middleware
├── .babelrc
├── Dockerfile
├── yarn.lock
└── package.json

当然目前还是需要编译的,这样就不需要在服务器上跑 babel-runtime。dist 是编译后的目录,通过 npm 对具体目录做了一些单独的编译。

  • app: 项目主要的业务逻辑代码。
    • api: 本层主要处理到达的请求,将参数做整理,然后交由 service 层。
    • services: 服务层从 repo 层取数据,然后拼接加工,最后返回 api 层。
    • model: 项目的 models。
  • bin: babel 需要一个启动文件。
  • config: 环境变量配置目录。
  • db: 数据库的一些资源。
  • dist: 编译后的文件。
  • lib: 一些系统类库,处理环境变量。和工具类。
    • middleware: middleware。
  • test: 测试用例。

## `npm run` scripts

这里定义了一些常用的启动命令:

  • start: Used by the production environment to start the app. This will run a compiled version, so you need to execute build first.
  • build: Runs the babel CLI to compile the app. Files are emitted to dist/.
  • dev: Runs the app in development mode - uses babel-register to compile on-the-fly. Also uses nodemon to automatically restart when stuff changes.
  • debug: Runs the app in development mode with icebug (a combo of nodemon + node-inspector).
  • test: Runs mocha tests.
  • test-watch: Runs mocha tests in watch-mode.
  • lint: Lints the code in src and test with eslint.
  • lint-watch: Same as above, in watch-mode.

Tip: to pass additional arguments to the actual CLI’s being called, do it like in this example:

1
npm run test -- --debug

2017

正月15前的最后一个工作日,路上依然是假日状态的通畅,不过也是仅有的一天了。毕竟张江的道路已经堵了一周了。

谈谈正事吧,是时候跟旧的一年完全说再见,投入到新的一年中了。

做更好的自己

最近苦恼的事情,经常在一些地方发现白发,虽然少白已是事实,但掉的头发还几乎都是黑发。有种忽然老去的赶脚。这赶脚一来,影响了整个冬天。

有一种时光不再的感觉。忽然觉得过的很不够好,不够硬气,不够阳光。

看了下镜子,有种浪费身材的感觉。决定来年穿出精神来。

头发也是叭着,虽然白了一些,但更可怕的是没有精神。

做成一件小事情

这跟今年的年终奖有关,确实是伤心,毕竟努力了这一年,到头都没有个认可。可想想,这也许是技术人的共悲之处,有人说,三年技术,余下运营。在这个运营主导的公司,确实挺形象。

但,事实就是事实,今年的事实还会成为明年的现实。要这样吗。

所以,今天要做一件小事,当年,事情还不知道,只是有几个 side project 计划。

但凡坚持,总有回报。