Vincent's waking life

他是彭于晏?
那我是谁?


  • Home

  • Footprint

  • Cheat sheet

rime 鼠须管配置备忘

Posted on 2023-04-07 | In 前端 , power user of everything , tool chain

安装鼠须管

1
2
# Install via [Homebrew](https://brew.sh/): 
brew install --cask squirrel

安装东风破

1
2
3
4
# 东风破
# https://github.com/rime/plum
# 安装到这个目录:~/plum
curl -fsSL https://raw.githubusercontent.com/rime/plum/master/rime-install | bash

安装雾凇拼音

1
2
3
4
5
6
7
8
9
10
11
12

# 安装雾凇拼音 https://dvel.me/posts/rime-ice/

# 安装
rime-install iDvel/rime-ice:others/recipes/full
# 更新
rime-install iDvel/rime-ice:others/recipes/all_dicts

# 配置文件:
/Rime/default.custom.yaml
/Rime/rime_ice.custom.yaml
/Rime/squirrel.custom.yaml

备份配置

1
2
3
4
5
6
7
8
9
10
11
# 备份配置
mv ~/Library/Rime ~/code/config/Rime
ln -s ~/code/config/Rime ~/Library/Rime

# vim ~/.gitignore_global, 添加:
**/Rime/build/**
**/Rime/**/*.log
**Rime/*.userdb/**

# .zshrc 配置:
export PATH="/Users/hexing/plum:$PATH"

npm / yarn / pnpm 研究

Posted on 2022-01-05 | In 前端 , js

banner

横向对比

依赖管理 问题
npm node_modules 树形结构 隐藏依赖重复安装
npm > v3 node_modules flatten mode 重复引用
yarn node_modules flatten mode 重复引用
yarn2(berry) Plug’n’Play 每个包压缩成 zip, **.pnp.js 纪录包版本和磁盘映射位置 vue 生态支持欠佳
pnmp node_modules 树形结构,操作系统级别 hard link 避免重复安装

yarn2 探索

yarn2 目测是最好的方案, 且背后有 fb 背书.
使用 pnp 改造后项目也能正常运行

改造步骤如下:

  1. 查看当前 yarn 版本
1
2
$ yarn --version
1.22.11
  1. 设置使用 yarn2
1
$ yarn set version berry
  1. 设置完了之后,查看 yarn 的版本号,>3 是正常情况:
1
2
$ yarn --version
3.0.0
  1. 配置yarn-berry.cjs
1
$ yarn config set npmRegistryServer https://registry.npm.taobao.org
  1. 删除旧的 node_modules 文件夹和 yarn.lock 文件,并重建整个项目:
1
2
3
$ rm -rf node_modules
$ rm -f yarn.lock
$ yarn
  1. 启动项目 yarn serve/start/build …, 处理 yarn 报的依赖错误, 通常是因为之前的一些依赖没有在 package.json 中显示的声明, yarn install xxx就能解决

  2. shell 错误处理完之后如果浏览器能正常跑起来项目, 则改造完毕. 若浏览器 console 报错:

1
Error: Your application tried to access xxxxxx, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.

如果 package.json 不包含, yarn install 之, 若安装后还报错, 修改.yarnrc.yml, 添加如下:

1
2
3
4
5
# 包名/版本号自理
packageExtensions:
'mmnn@*':
dependencies:
'xxyy': '*'

添加完了执行yarn install, 再重新跑项目

  1. yarn2 插件
    插件一览
    建议至少安装 typescript 插件
1
2
# 自动添加 @types 依赖
$ yarn plugin import typescript
  1. ide 支持: 以 vscode 为例:
1
$ yarn dlx @yarnpkg/sdks vscode

then: Change your VSCode workspace configuration to add the following:
“typescript.tsdk”: “.yarn/sdks/typescript/lib”

至此, ide 能正常对 ts 进行静态类型推断, 也能都 js 依赖进行解析, 上述步骤中如果需要修改 tsconfig.json 之类的过程不赘述.

但是, 问题来了: vue 文件中 vetur 提供的类型推断全部都不生效了

yarn2 vue 生态支持欠佳

猜测如下:

  • yarn2 pnp 文件系统 是基于 zip 压缩包, vetur 并未且没有计划提供支持1 2 3
  • yarn2 是 react 的东家 fb 开源的, 默认不照顾 vue 也正常?

[1]Vetur cannot use Prettier installed via Yarn Berry (PnP) #2092

[2]yarn@berry support

[2]support yarn pnp mode

yarn2 暂时玩不转, 考虑 pnpm

pnpm vs npm(使用边端项目演示, 项目较小, 效果不是很明显)

pnpm npm
node_modules 体积
node_modules 文件数
dev server 启动时间
dev server 单次编译
打包

迁移到 pnpm

开发环境

几乎不用改动, 安装 pnpm, 移除 node_modules 文件夹, pnpm install即可, 日常使用与 npm 几乎无异

github webhooks 简明教程

Posted on 2021-09-29 | In power user of everything

服务器侧配置

Goal: 以本博客为例, 本地 hexo 写完文章, hexo g d => 自动 deploy 到 github pages => 触发个人网站服务器自动更新静态文件

涉及到的技术栈:

  • node(pm2)
  • nginx
  • github pages
  • github hooks

自动部署脚本

这里自理一下, 对于我来说只需要从 github 拉取最新的静态文件即可, 不需要打包

网站根目录新建deploy.sh内容如下:

1
2
3
4
5
6
7
8
9
10
#!/bin/bash

SITE_PATH='/www/wwwroot/trainspott.in'

cd $SITE_PATH
git reset --hard origin/master
git clean -f
git pull
git checkout master

设置可执行

1
chmod 775 ./deploy.sh

webhookHandler 配置

服务端需要跑一个监听的程序

npm 安装依赖github-webhook-handler

1
npm i github-webhook-handler -S

网站根目录新建webhookHandler.js内容如下:

需要注意的是第 7/8/18 行的 3 个字段

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
var http = require("http");
var spawn = require("child_process").spawn;
var createHandler = require("github-webhook-handler");

// 下面填写的myscrect跟github webhooks配置一样,下一步会说;path是我们访问的路径
var handler = createHandler({
path: "/auto_build",
secret: "{{secret}}", // 自己生成一个秘钥字符串, 自己记住别忘了, 待会github配置要用
});

http
.createServer(function (req, res) {
handler(req, res, function (err) {
res.statusCode = 404;
res.end("no such location");
});
})
.listen(6666); //此处与

handler.on("error", function (err) {
console.error("Error:", err.message);
});

// 监听到push事件的时候执行我们的自动化脚本
handler.on("push", function (event) {
console.log(
"Received a push event for %s to %s",
event.payload.repository.name,
event.payload.ref
);

runCommand("sh", ["./deploy.sh"], function (txt) {
console.log(txt);
});
});

function runCommand(cmd, args, callback) {
var child = spawn(cmd, args);
var resp = "Deploy OK";
child.stdout.on("data", function (buffer) {
resp += buffer.toString();
});
child.stdout.on("end", function () {
callback(resp);
});
}

// 如果需要监听issues,打开下面的代码
// handler.on('issues', function (event) {
// console.log('Received an issue event for %s action=%s: #%d %s',
// event.payload.repository.name,
// event.payload.action,
// event.payload.issue.number,
// event.payload.issue.title)
// });

启动监听服务

1
2
3
4
5
6
node /{{your-path}}/webhookHandler.js

# OR

pm2 start /{{your-path}}/webhookHandler.js
pm2 save

Nginx 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
location /auto_build {
proxy_pass http://127.0.0.1:6666;
}


location ~ ^/(deploy.sh|hexo-webhookHandler.js) {
return 404;
}

# `location` 与 webhookHandler 中
# createHandler({
# path: "/auto_build",
# secret: "{{secret}}",
# }); 的 path 一致

# `proxy_pass` 的端口与webhookHandler中配置的http.createServer().listen(6666) 中的端口一致

如果成功,访问 https://{your-domain}/auto_build 会显示如下图:


github 配置

  1. 进入https://github.com/stariveer/{{your-repo}}/settings/hooks
  2. 点击Add webhook
  3. 如下图配置
  4. 本地执行一次git push
  5. 如果上面所有步骤都成功, 返回https://github.com/stariveer/{{your-repo}}/settings/hooks, 将显示如下

EOF

关于时间格式,时区

Posted on 2020-09-04 | In 前端 , js

基本概念

GMT时间:格林尼治标准时间(英语:Greenwich Mean Time,GMT)是指位于英国伦敦郊区的皇家格林尼治天文台当地的平太阳时,因为本初子午线被定义为通过那里的经线。

由于地球每天的自转是有些不规则的,而且正在缓慢减速,因此格林尼治平时基于天文观测本身的缺陷,已经被原子钟报时的协调世界时(UTC)所取代。

UTC时间:协调世界时(英语:Coordinated Universal Time,法语:Temps Universel Coordonné,简称UTC)是最主要的世界时间标准,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间。

对于大多数用途来说,UTC时间被认为能与GMT时间互换,但GMT时间已不再被科学界所确定。

UNIX时间戳:Unix time又叫POSIX time或UNIX Epoch time,是从UTC时间1970年1月1日起到现在的秒数,不考虑闰秒,一天有86400秒。

划重点

  • GMT就是0时区的时间,以前是标准,但现在国际上已经用UTC取代他了。在写程序时,可以认为UTC和GMT是等价的。为了严谨只需要关心UTC时间。

  • UNIX时间戳是程序中最常用的,和时区无关,无论在地球上的那个角落,同一时刻,UNIX时间戳都是一样的。是一个通用的时间偏移度量,计算每个时区当地时间时,都可以用时间戳推算出来。

  • 涉及到多个时区的转换,统一使用unix时间戳存储或交互,或者使用带有时区信息的字符串。

  • 尽量在上层的代码层面修改时区配置,不要修改系统或软件的配置,防止其他程序因为修改受到影响。

UTC格式

UTC在时间后面直接加上一个“Z”(不加空格),“Z”是协调世界时中 0 时区的标志。比如,“09:30 UTC” 写作 “09:30Z” 或是 “0930Z”。“14:45:15 UTC” 写作 “14:45:15Z” 或 “144515Z”。因为在北约音标字母中用 “Zulu” 表示 “Z”,所以 UTC 时间也被称做祖鲁时间。

Dayjs Format cheat-sheet

占位符 输出 详情
YY 18 两位数的年份
YYYY 2018 四位数的年份
M 1-12 月份,从 1 开始
MM 01-12 月份,两位数
MMM Jan-Dec 缩写的月份名称
MMMM January-December 完整的月份名称
D 1-31 月份里的一天
DD 01-31 月份里的一天,两位数
d 0-6 一周中的一天,星期天是 0
dd Su-Sa 最简写的星期几
ddd Sun-Sat 简写的星期几
dddd Sunday-Saturday 星期几
H 0-23 小时
HH 00-23 小时,两位数
h 1-12 小时, 12 小时制
hh 01-12 小时, 12 小时制, 两位数
m 0-59 分钟
mm 00-59 分钟,两位数
s 0-59 秒
ss 00-59 秒 两位数
SSS 000-999 毫秒 三位数
Z +05:00 UTC 的偏移量,±HH: mm
ZZ +0500 UTC 的偏移量,±HHmm
A AM PM
a am pm

参考

https://zhuanlan.zhihu.com/p/50799585

https://zhuanlan.zhihu.com/p/110630502

BEM 举例

Posted on 2019-10-17 | In 前端 , css

via BEM by Example 侵删

带单个修饰符的组件

一个组件可能有不同状态。状态应该使用修饰符类来实现。

1
2
3
4
5
6
7
8
9
10
11
12
<!-- 这样写 -->
<button class="btn btn--secondary"></button>

<style lang="scss">
.btn {
display: inline-block;
color: blue;
&--secondary {
color: green;
}
}
</style>

不要单独使用修饰符。修饰符的作用是增加而不是替换基类。

1
2
3
4
5
6
7
8
9
<!-- 别 -->
<button class="btn--secondary"></button>

<style lang="scss">
.btn--secondary {
display: inline-block;
color: green;
}
</style>

带子元素的组件

更复杂的组件含有子元素。
原则上不要使用标签选择器,你不知道<li>里面是否还会出现嵌套的<ul><li>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 这样写 -->
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">Look at me!</figcaption>
</figure>

<style lang="scss">
.photo { /* css权重 of 10 */
&__img { } /* css权重 of 10 */
&__caption { } /* css权重 of 10 */
}
</style>

<!-- 别 -->
<figure class="photo">
<img src="me.jpg">
<figcaption>Look at me!</figcaption>
</figure>

<style lang="scss">
.photo { /* css权重 of 10 */
img { } /* css权重 of 11 */
figcaption { } /* css权重 of 11 */
}
</style>

如果您的组件的子元素有几个层次,请不要尝试在类名称中表示每个层次。
BEM并非旨在传达结构深度。
表示组件中子元素的BEM类名称应仅包括基本/块名称和一个元素名称。
在下面的示例中,请注意photo__caption__quote是BEM的不正确用法,而photo__quote更合适。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!-- 这样写 -->
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">
<blockquote class="photo__quote">
Look at me!
</blockquote>
</figcaption>
</figure>

<style lang="scss">
.photo {
&__img { }
&__caption { }
&__quote { }
}
</style>


<!-- 别 -->
<figure class="photo">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">
<blockquote class="photo__caption__quote"> <!-- 在类名中永远不要包含多个子元素 -->
Look at me!
</blockquote>
</figcaption>
</figure>

<style lang="scss">
.photo {
&__img { }
&__caption {
&__quote { } // 在类名中永远不要包含多个子元素
}
}
</style>

带修饰符的组件

在某些情况下,您可能希望更改组件中的单个元素。在这些情况下,请向元素而不是组件添加修饰符。
我发现,修改元素比修改整个组件要少见得多,也没什么用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<figure class="photo">
<img class="photo__img photo__img--framed" src="me.jpg">
<figcaption class="photo__caption photo__caption--large">Look at me!</figcaption>
</figure>

<style lang="scss">
.photo{
&__img--framed {
/* 新增样式修改 */
}
&__caption--large {
/* 新增样式修改 */
}
}
</style>

基于组件修改器的样式元素

如果你发现正在以相同的方式修改同一组件的元素,则可以考虑将修改器添加到组件本身。
并基于该修改器为每个子元素调整样式。这将增加css层级,但使修改组件变得更加简单。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!-- 这样写 -->
<figure class="photo photo--highlighted">
<img class="photo__img" src="me.jpg">
<figcaption class="photo__caption">Look at me!</figcaption>
</figure>

<style lang="scss">
.photo{
&--highlighted {
.photo__img { }
.photo__caption { }
}
}
</style>

<!-- 别 -->
<figure class="photo">
<img class="photo__img photo__img--highlighted" src="me.jpg">
<figcaption class="photo__caption photo__caption--highlighted">Look at me!</figcaption>
</figure>

<style lang="scss">
.photo__img--highlighted { }
.photo__caption--highlighted { }
</style>

多词名称

BEM名称有意使用双下划线和双连字符而不是单个来分隔块元素修饰符。原因是可以将单个连字符(-)用作单词分隔符。
class名称应易于阅读,慎用缩写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- 这样写 -->
<div class="some-thesis some-thesis--fast-read">
<div class="some-thesis__some-element"></div>
</div>

<style lang="scss">
.some-thesis {
&--fast-read { }
&__some-element { }
}
</style>

<!-- 别 -->
// These class names are harder to read
<div class="somethesis somethesis--fastread">
<div class="somethesis__someelement"></div>
</div>

<style lang="scss">
.somethesis {
&--fastread { }
&__someelement { }
}
</style>

一周网摘2019-02-w4

Posted on 2019-02-25 | In 杂

Can’t Unsee - 告诉你为什么魔鬼在细节

选出你认为合适的设计。前端/客户端开发都强烈建议来看下,虽然有的题很像大家来找茬,做完后可以少和设计狮撕逼。

Can't Unsee

[Can’t Unsee]点这里


全局变量最好加什么前缀?

global_var


一个根据文本内容随机生成 svg 矢量图花纹背景的 JS 库

GeoPattern

可以拿来当banner,空了研究下原理


Ant Design of Vue

Ant Design of Vue

貌似是一个个人开发者的项目被阿里收编了,先悄悄观望下不着急

链接:Ant Design of Vue


一句话见闻

  • Emoji是当代语法的语气助词👀
  • 产品和笑话的共同点:如果需要解释就不好了
  • css trick 1: {color:rgba(255,255,255,0.5)} === {color: #ffffff50}
  • css trick 2: css动画transition对height:auto;的元素不生效,可以用max-height属性替代之,虽然效果不能100%完美,够用就行

每月电影2018-11 & 12

Posted on 2018-12-22 | In movies

特工 공작 (2018))

特工 공작 (2018)

豆瓣评分: 8.4/10
个人评分: 8.0/10

good: 真实事件改编, 剪辑凌厉, 让人紧张同时又有点感动

bad: 反派有点脸谱化


风骚律师 第四季

风骚律师 第四季

豆瓣评分: 9.6/10
个人评分: 9.0/10

这部剧, 一个字, 高级. 大段留白, 大段细节, 情节在剧情片里最慢没有之一. 导演意思就是爱看看不爱看滚


海王 Aquaman (2018)

海王 Aquaman (2018)

豆瓣评分: 7.9/10
个人评分: 8.5/10

温子仁证明了自己不光能拍恐怖片…个人感觉本片美学造诣可以和<潘神的迷宫>, <阿凡达>一拼


请回答 1988 응답하라 1988 (2015)

请回答1988 응답하라 1988 (2015)

豆瓣评分: 9.7/10
个人评分: 8.8/10

整个 12 月都在看这部剧, 100min * 20, 只想说入坑需谨慎.

德善性格好像我老婆啊哈哈哈

这部剧让我想起童年小伙伴

翻译小哥请把翻译歌词的力气用在翻译屏幕文字上,辛苦了


需避坑:

  • 影 (2018), 不管国师审美有多强大, 再怎么找矮大紧造势, 再怎么找水军刷分(也有可能是买通豆瓣). 但这部电影槽点还是太多, 千万别看

[译]635000 个 npm 包中我应该用哪个

Posted on 2018-12-20 | In 前端 , tool chain , js

[英文原文] Which of the 635000 npm modules do I choose? - Corey Cleary

原创翻译,如有谬误,恳请指正

如果您曾在 Node 或 JavaScript 前端开发中投入过时间和精力,那么您就知道 npm 中有数以十万计的模块可供您选择

开发者不停的寻求帮助/抱怨:

“对模块的选择困难正在蚕食我们”

“X 模块和 Y 模块有什么区别?哪一个更好?”

“npm 很棒,但是这些模块可能在一年半载后失效,取决于模块维护者是否积极”

通常在提出这样的问题时,您会得到十个不同的答案。每个人都会给您推荐自己喜欢的模块,接下来就演变成争论哪一个是最好的。

选择 npm 模块时很容易面临纸上谈兵。选择太多,而新来者在鼓吹“快上车”,为您的项目选择合适的 npm 模块可能是有难度的。而且这些模块中有许多做类似(或相同)的事情,这也没有帮助。

与其浪费时间在 google 上搜索,在 npmjs.org 上搜索,或者浪费更多的时间不构建您的项目,还不如搞清楚什么时候该选择哪些模块。

精选清单

为了帮助解决这个问题,您将在下面找到针对最常见问题类型(即 web 框架、模板、身份认证等)的 npm 模块列表,以及何时使用这些模块。

这里有一些注意事项:您可能熟悉其中一些模块,甚至许多模块,但是有时候您面对的是您还没有接触到的技术栈(可能是身份验证或 Websocket 之类的东西),您需要知道有哪些备选模块可以完成这项工作。您可能有您认为更好的模块,或者可能有一个用例/需求没有包含在这里。我没有列出相同类别的 10 个不同模块,而是缩小了范围,这样您就可以避免分析瘫痪的陷阱。如果您认为自己的用例未被涵盖,请务必自行研究解决。本清单的目的在于让您能更快地启动和运行。

这些模块的选择依据如下:

  • 它们完成工作的能力如何
  • 社区规模(对于支持/故障排除很重要)
  • 积极维护

如果您发现自己仍然没有足够的信息做出决定,我建议使用slant.co和nodejs.libhunt.com来帮助进行比较。

注意:为了保持范围的合理性,这些模块都考虑到了服务器端。它们中的一些可以同时在客户机或服务器上使用,但我的原则是“服务器优先”。

HTTP requests (HTTP 请求)

  • Request:
    • 当您需要基于回调的 HTTP 请求时可选择它,例如从一个 REST 服务连接到另一个。
  • Axios
    • 当您需要基于 Promise的 HTTP 请求时可选择它
    • 注意:您可以使用request-promise,但是 axios 的依赖更少,并且基于原生 Promises

Web frameworks (Web 框架)

  • Express:
    • 如果您想为 API、网站或单页应用程序使用轻量级 web 框架,请使用它
    • 您不介意使用回调作为默认的异步处理方式
    • 使用该框架的模块生态极为繁荣
    • 您需要一个支持和故障排除的大型社区
  • Koa:
    • 当您想要一个比 Express 更简洁的框架时使用
    • Koa 更像是一个中间件层,它不提供模板或开箱即用的路由,因此更适合 API 开发
    • 要想支持开箱即用,您需要 async / await
  • Hapi
    • 如果您想要一个比 Express 或 Koa 更“自带电池”(译者注:原文”batteries”意为您不必重复造轮子,大多数您需要的功能都能通过(已有)库完成。您能导入并使用它们。)的框架,但又不像 Sails 那么多,那就使用它
  • Sails
    • 当您需要像 Rails 这样的东西时,请使用它,它具有几乎所有功能(但是根据您的应用程序可能不需要那么多)

Validation (前端验证)

  • Ajv
    • 在需要验证 JSON 时使用(比如来自 web 请求)
    • 您希望与应用程序的其他非 JS 部分共享这些验证规则(因为它是 JSON,所以您可以这样做)
  • Joi
    • 在需要验证输入时使用,并且喜欢链式调用的风格(译者注:代码见下方),而不是在 JSON 中定义验证规则
    • 您正在使用 Hapi(Hapi 自带 Joi)
1
2
3
4
const schema = joi.object().keys({
id: joi.string().guid().required(),
username: joi.string().alphanum().min(8).required()
});

Authentication (身份认证)

  • Passport:
    • 当您需要为您的网站或 API 使用身份验证中间件时使用
    • 您希望能够在多种身份验证类型(Oauth,Facebook 等)之间进行选择
    • 您需要管理会话

Asynchronous (异步)

  • Async (library):
    • 当您需要使用旧版本的 Node,而该版本的 Node 支持只支持回调而不支持 Promises 时
  • ES6 原生 promises (原生 JS, 非 npm):
    • 在使用大于 0.12 的 Node 版本时使用
    • 另一件需要考虑的事情是您的团队对 Promises 的接受程度。在 2018 年,大多数开发人员应该没问题了
  • async / await(原生 JS,非 npm)
    • 当您为了逃脱“回调地狱”却又误闯“Promise 地狱”
    • 您有很多来自 Promises 的.then 和.catch

Database (数据库)

下面是数据库驱动程序、ORM 和查询生成器的组合。在使用 ORM 之前,我强烈建议您首先确保需要使用它。当您可以只使用原始 SQL 或查询生成器时,它们通常会添加另一层抽象,这层抽象不一定能够提供足够的回报。

  • mysql, node-postgres:
    • 当您不需要完整的 ORM,而是需要使用原始 SQL 查询数据库时使用(这些是驱动程序)
  • node-mongodb-native:
    • 当您不需要一个完整的 ORM,而是要直接查询 MongoDB 时使用
  • Mongoose:
    • 当您希望为 MongoDB 使用 ORM 时使用
  • Knex:
    • 当您不需要一个完整的 ORM 解决方案,而只是需要一些工具使编写查询代码更容易,可以使用它
    • Knex 是一个生成 SQL 的查询生成器
    • 您拥有 Postgres、MSSQL、MySQL、MariaDB、SQLite3、Oracle 或 Amazon Redshift 数据库
  • Objection.js:
    • 您希望 ORM 支持 Knex 支持的所有东西,不使用查询 DSL(因此您编写的代码更接近原始 SQL),具有基于 Promise 的 API 和良好的文档

Process management (进程管理)

这个网址提供了部分进程管理器的横向比较http://strong-pm.io/compare/。注意:它们还包括了 StrongLoop Process Manager,这是一个不错的工具,但是有点笨重。我建议您在决定使用 StrongLoop 之前先查看一下解决方案。

  • PM2:
    • 当您希望进程管理器在服务崩溃时处理重新启动,并允许您控制集群时使用
    • 注意:PM2 所依据的 AGPL 许可证存在一些潜在的违规行为。这里有一些讨论。我的看法是它最有可能被使用。但如果您有任何问题,请咨询您的法律部门,因为我不是律师。
  • forever:
    • 当您需要进程管理器来处理在服务崩溃时重新启动服务时使用
    • 您的部署规模较小(pm2 及其集群支持用于更大规模的部署)。如果您只有少量的服务/进程,那么您可能可以使用它
  • nodemon:
    • 当您希望监视应用程序中的任何代码更改时使用,并在本地开发时自动重启服务器
    • 非常适合用于开发!

Web Sockets

对于 Web Sockets,我只是推荐 primus,而不是列出一个列表。它支持所有主要的 Web Sockets 实现,并且维护者十分积极。如果您需要换成其他的库,您可以通过一行代码更改轻松地更换。

  • Primus:
    • 当您需要 Web Sockets 但又不想被束缚在特定的 Web Sockets 实现时使用

API documentation (API 文档)

  • Swagger-node:
    • 当您需要记录 REST API 并能够针对端点测试请求时使用

Utilities/misc (通用工具/杂项)

  • Lodash:
    • 当您需要 JS 实用程序库时使用
    • 您使用了大量的 OOP(面向对象编程)
  • Ramda:
    • 当您希望使用函数式的编程风格时,请使用
    • 您想要像 lodash 这样的东西,但是在函数式编程范式中
  • Moment:
    • 在需要解析、验证、操作和显示日期/时间时使用
  • UUID:
    • 当您需要随机的、唯一的、难以破解的 id 时使用
  • NVM:
    • 当您希望能够在环境中安装的多个 Node 版本之间切换时使用
  • Fs-extra:
    • 当您需要能够递归地使用mkdir、rm -rf和 Node 中缺少的其他文件系统级功能时,请使用
  • Nodemailer:
    • 当您需要从 Node 发送电子邮件时使用
  • Dotenv:
    • 当您需要将.env 文件中的环境变量加载到 process.env 时使用

CLI (命令行界面)

  • Commander:
    • 当您要构建一个 CLI 程序时使用,该程序将所有参数作为命令行上的标志
  • Inquirer:
    • 当您想要构建一个按顺序获取选项的“交互式”CLI 程序时使用(类似于运行 npm init 时的方式,它会询问您生成 package.json 文件的一系列问题)

Logging (日志)

  • Winston:
    • 当您需要一个日志库并需要不同的日志输出格式时使用
  • Bunyan:
    • 当您需要一个日志库,并以 JSON 作为唯一日志输出格式时使用
    • 您希望为不同的组件、请求或函数使用不同的日志记录器(也就是说,这些日志记录器可能以不同的方式解析事件)
  • Morgan:
    • 当您使用 Express 并且想要记录 HTTP 请求时使用
    • 注意:这将与 Winston 或 Bunyan 一起使用。由于它是中间件,它知道如何处理请求并记录它,但不处理 Winston 和 Bunyan 所做的日志输出的传输。

Templating (前端模板)

  • Pug (原 Jade):
    • 当您需要服务器端模板引擎时,请使用该引擎,该引擎易于阅读,并且支持开箱即用的子组件代码块
    • 您只需要输出 HTML
  • EJS:
    • 当您需要一个服务器端模板引擎,该引擎完全使用 JS,并且允许空格缩进(Pug 不允许)
    • 注意:不支持异步 JS 函数

Testing (测试)

  • Mocha:
    • 在需要编写和运行单元测试时使用
  • Chai:
    • 当您需要证明您的单元测试中的断言时,请使用
    • 注意:这将与 Mocha 一起使用
  • Chai-as-promised:
    • 当您希望在 promises 上证明您的断言时,而不是将断言放在 then 或 catch 中使用
  • Sinon:
    • 当您需要用于测试的 mock 库时使用

Tooling (开发工具)

  • ESdoc:
    • 当您想从您的代码中生成 API 文档,并且您正在使用最新的 JS 版本时,请使用
    • 默认情况下支持当前版本的 JS(支持 class),因此如果在代码中使用 prototypes,请使用 JSdoc
  • JSdoc:
    • 当您需要支持 ES6 的代码 API 文档生成器时使用
    • 支持classes 和 prototypes
  • ESlint:
    • 当您需要一个 linter 来自动查找(和修复)代码中的语法和代码格式问题时使用(译者注:可参考本人博文vscode + vetur + eslint + prettier 实现团队代码风格统一)

Debugging (调试)

现在,原生 Node 调试现在已经够用了,我的建议是直接使用它。几年前,引入一些 npm 模块是很有帮助的,而且您可能有一个特定的用例需要一个 npm 模块,但是现在已经有了足够的本地支持,如果您对调试没有任何太疯狂要求,请务必忽略掉额外的依赖项。

结论

挑选模块可能很难,但您只需要一些方法点来解决它。当您正在为如何抉择浪费时间,或者甚至不知道从哪里开始时,请使用本指南来帮助您。

一周网摘2018-12-w1

Posted on 2018-12-09 | In 杂

见微知著,Google Photos Web UI 完善之旅

Google 工程师撰文《Building the Google Photos Web UI》,里面详细介绍了 Google Photos for Web 是如何在几千上万张用户照片的体量下,做到自适应布局、高性能加载、60fps 流畅滚动,并提升页面速度的,干货不少值得一读!中文翻译:

zhuanlan.zhihu.com


为什么我们活得越来越像一只信息量过载的猪

智谷趋势

这篇文章本身也是信息过载/贩卖焦虑吧,有时候需要反省下自己到底想要什么


Parked cars covered by the season’s first snowfall in Moscow

Parked cars covered by the season’s first snowfall in Moscow

vscode + vetur + eslint + prettier 实现团队代码风格统一

Posted on 2018-12-07 | In 前端 , tool chain

vscode + vetur + eslint + prettier 实现团队代码风格统一

如果你也是 front-end coder,也采用 ES6、vue 单文件、css 预编译,希望实现团队代码格式/风格统一,可参考本文。

值得参考并执行的规范

  • 谷歌 HTML/CSS 规范
  • Airbnb CSS / Sass 指南
    • zh_CN
  • Airbnb JavaScript 风格指南
    • zh_CN
  • Eslint rules(强烈推荐)
  • 使用 ES6 进行开发的思考(via Baidu EFE)
  • Vue.js 风格指南

落地方案

  • IDE: vs code
    • ESLint // ide lint 报错/warning 要靠它
    • Prettier - Code formatter // 格式化 html/css/less/scss etc…
    • Vetur // 这里只用来语法提示,代码格式化交给 eslint(npm)
  • npm:
    • eslint
    • eslint-config-airbnb-base
    • eslint-config-prettier
    • eslint-plugin-import
    • eslint-plugin-vue
    • eslint-plugin-prettier
    • prettier
  • 关键配置文件(in git repo)
    • .vscode/setting.json // ESLint(ide 插件),vetur(ide 插件)配置在这里
    • .editorconfig // 字符集配置,缩进等配置
    • .eslintrc.js // eslint(npm)配置,ide eroor/warning 信息在这里配置
    • .eslintignore // eslint 排除文件,如一些库文件
    • .prettierrc.js // prettier 配置,如逗号分号规则
    • .prettierignore //prettier 排除文件

简单说下思路

  • eslint 优先级最高,装插件eslint-config-airbnb-base,eslint-config-prettier,eslint-plugin-vue,可以覆盖 prettier 的设置
  • eslint 主要负责 vue/js 的格式化
  • prettier 主要负责 html/css/less/scss… 的格式化
  • Vetur 也有格式化功能,直接 disable 掉,我们用更高级的
  • prettier 不支持 stylus,但是 Vetur 的依赖包括了stylusSupremacy,可以解决
  • 所有的配置都可以放在项目 repo 里,且优先级会高于 coder 本地的设置,保证团队所有成员提交的代码一致
  • 如果装了其他 format 插件,请在本项目中 disable 掉,我们不需要

附:配置文件

EditorConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
root = true # 表明是最顶层的配置文件,发现设为true时,才会停止查找.editorconfig文件。

[*]
charset = utf-8 # 编码格式,支持latin1、utf-8、utf-8-bom、utf-16be和utf-16le,不建议使用uft-8-bom。
indent_style = space # tab为hard-tabs,space为soft-tabs。
indent_size = 2 # 设置整数表示规定每级缩进的列数和soft-tabs的宽度(译注:空格数)。如果设定为tab,则会使用tab_width的值(如果已指定)。
end_of_line = lf # 定义换行符,支持lf、cr和crlf。
insert_final_newline = # 设为true表明使文件以一个空白行结尾,false反之。
trim_trailing_whitespace = true # 设为true表示会除去换行行首的任意空白字符,false反之。

[*.md]
insert_final_newline = false # 设为true表明使文件以一个空白行结尾,false反之。
trim_trailing_whitespace = false # 设为true表示会除去换行行首的任意空白字符,false反之。

.eslintrc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
*
* 规则说明见 https://cn.eslint.org/docs/rules/
* eslint-plugin-import 规则见 https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/default.md
* eslint-plugin-vue 规则见 https://github.com/vuejs/eslint-plugin-vue
*
* "off" 或 0 - 关闭规则
* "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
* "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
*
*/

module.exports = {
extends: [
// add more generic rulesets here, such as:
// 'eslint:recommended',
"airbnb-base", // airbnb lint规范
"plugin:vue/essential", // eslint-plugin-vue
"plugin:prettier/recommended" // eslint-config-prettier
],
// settings: {
// 'import/resolver': {
// webpack: {
// config: 'build/webpack.base.conf.js',
// },
// },
// },
// plugins: ['vue'],
rules: {
"prettier/prettier": 1,
"no-undef": 2, // 禁用未声明的变量,除非它们在 /*global */ 注释中被提到. e.g. /* global Stomp SockJS */ in .vue file's <scrpit>
"no-extend-native": 2, // 禁止扩展原生类型
"no-return-assign": 2, // 禁止在 return 语句中使用赋值语句
"import/order": 0, // Enforce a convention in module import order
"import/no-extraneous-dependencies": 0, // 禁止导入未在package.json的依赖项,devDependencies,optionalDependencies或peerDependencies中声明的外部模块。将使用最接近的父package.json。
"import/no-dynamic-require": 1, // CommonJS的require方法用于从不同文件导入模块。与ES6导入语法不同,可以为其提供将在运行时解析的表达式。虽然这有时是必要且有用的,但在大多数情况下并非如此。使用表达式(例如,连接路径和变量)作为参数使得工具更难以进行静态代码分析,或者在代码库中找到使用模块的位置。
"import/extensions": 0, // 某些文件解析算法允许您在导入源路径中省略文件扩展名。例如,节点解析器可以将./foo/bar解析为绝对路径/User/someone/foo/bar.js,因为默认情况下会自动解析.js扩展名。根据解析程序,您可以配置更多扩展程序以自动解决。
"import/no-unresolved": 0, // 确保导入的模块可以解析为本地文件系统上的模块,如标准Node require.resolve行为所定义。
"import/prefer-default-export": 1, // 当模块中只有一个导出时,更喜欢使用默认导出而不是命名导出。
"vue/no-async-in-computed-properties": 1, // 计算属性应该是同步的。其中的异步操作可能无法按预期工作,并可能导致意外行为,这就是您应该避免它们的原因。如果您需要异步计算属性,可能需要考虑使用其他插件[vue-async-computed]
"vue/no-side-effects-in-computed-properties": 1, // 在计算属性中引入副作用被认为是一种非常糟糕的做法。它使代码无法预测且难以理解。
"vue/no-reserved-keys": 1, // 此规则阻止使用保留名称以避免冲突和意外行为。
"vue/require-v-for-key": 2, // 当v-for写在自定义组件上时,它需要同时使用v-bind:key。在其他元素上,v-bind:key也最好写。
"vue/require-valid-default-prop": 1, // 此规则检查每个prop的默认值是否对给定类型有效。当使用函数未返回类型Array或Object的默认值时,它应报告错误。
"no-unused-vars": 1, // 禁止出现未使用过的变量
"generator-star-spacing": 0, // 强制 generator 函数中 * 号周围使用一致的空格
"no-plusplus": 0, // 禁用一元操作符 ++ 和 --
"func-names": 0, // 要求或禁止使用命名的 function 表达式
"no-console": 0, // no-console
radix: 0, // 强制在parseInt()使用基数参数
"no-control-regex": 0, // 禁止在正则表达式中使用控制字符
"no-continue": 0, // 禁用 continue 语句
"no-debugger": process.env.NODE_ENV === "production" ? 2 : 0,
"no-param-reassign": 1, // 禁止对 function 的参数进行重新赋值
"no-underscore-dangle": 1, // 禁止标识符中有悬空下划线"_"
"global-require": 1, // 要求 require() 出现在顶层模块作用域中
"no-var": 1, // 要求使用 let 或 const 而不是 var
"vars-on-top": 1, // 要求所有的 var 声明出现在它们所在的作用域顶部
"prefer-destructuring": 1, // 优先使用数组和对象解构
"no-useless-concat": 1, // 禁止不必要的字符串字面量或模板字面量的连接
"no-shadow": 1, // 禁止变量声明与外层作用域的变量同名
"guard-for-in": 1, // 要求 for-in 循环中有一个 if 语句,旨在防止使用for in循环而不过滤循环中的结果时可能出现的意外行为。
"no-restricted-syntax": 1, // 禁用特定的语法
"global-require": 1, // 要求 require() 出现在顶层模块作用域中
"consistent-return": 1, // 要求 return 语句要么总是指定返回的值,要么不指定
eqeqeq: 1, // 要求使用 === 和 !==
"no-unused-expressions": 1, // 禁止出现未使用过的表达式
camelcase: 1, // 强制使用骆驼拼写法命名约定
"block-scoped-var": 1, // 强制把变量的使用限制在其定义的作用域范围内,旨在减少绑定上下文之外的变量的使用,并从其他语言模拟传统的块范围。这是为了帮助语言新手避免变量提升的难题。
"no-redeclare": 1, // 禁止多次声明同一变量
"prefer-arrow-callback": 1, // 要求回调函数使用箭头函数
"array-callback-return": 1, // 强制数组方法的回调函数中有 return 语句,Array有几种过滤,映射和折叠的方法。如果我们忘记return在这些回调中写入语句,那可能是一个错误。
"default-case": 1, // 要求 switch 语句中有 default 分支
"no-loop-func": 1, // 禁止在循环中出现 function 声明和表达式
"no-fallthrough": 1, // 禁止 case 语句落空
"no-multi-assign": 1, // 禁止连续赋值
"no-lonely-if": 1, // 禁止 if 作为唯一的语句出现在 else 语句中.如果一个if陈述是该else块中唯一的陈述,那么使用一个else if表格通常会更清晰。
"no-irregular-whitespace": 1, // 禁止在字符串和注释之外不规则的空白
"prefer-const": 1, // 要求使用 const 声明那些声明后不再被修改的变量.如果一个变量从不重新分配,使用const声明更好。const 声明告诉读者,“这个变量永远不会被重新分配,”减少认知负荷并提高可维护性。
"no-use-before-define": 1, // 禁止在变量定义之前使用它们
"no-useless-escape": 1, // 禁用不必要的转义字符
"no-array-constructor": 1, // 禁用 Array 构造函数,由于单参数的缺陷以及Array全局可能被重新定义,所以通常不鼓励使用构造函数来构造新Array数组,而是倾向于使用数组文字符号。例外情况是Array构造函数用于通过给构造函数一个数字参数有意创建指定大小的稀疏数组。
"object-shorthand": 1, // 要求或禁止对象字面量中方法和属性使用简写语法
"no-prototype-builtins": 1, // 禁止直接调用 Object.prototypes 的内置属性.当假定对象将具有属性时,这可能导致错误Object.prototype。此规则可防止Object.prototype直接从对象调用方法。
"no-nested-ternary": 1, // 禁用嵌套的三元表达式.嵌套三元表达式会使代码更难理解。
"no-new-wrappers": 1, // 禁止对 String,Number 和 Boolean 使用 new 操作符.没有任何理由将这些基本包装用作构造函数
"prefer-promise-reject-errors": 1, // 要求使用 Error 对象作为 Promise 拒绝的原因
"no-labels": 1 // 禁用标签语句
}
};

.prettierrc

1
2
3
4
5
6
7
8
9
10
module.exports = {
printWidth: 80, //一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, //一个tab代表几个空格数,默认为80
useTabs: false, //是否使用tab进行缩进,默认为false,表示用空格进行缩减
singleQuote: true, //字符串是否使用单引号,默认为false,使用双引号
semi: true, //行位是否使用分号,默认为true
trailingComma: "es5", //是否使用尾逗号,有三个可选值"<none|es5|all>"
bracketSpacing: true //对象大括号直接是否有空格,默认为true,效果:{ foo: bar }
// parser: 'babylon', //代码的解析引擎,默认为babylon,与babel相同。
};

.vscode/setting.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
{
// 使用2个空格作为tab,并将对齐基准线设置为2个字符test
"editor.tabSize": 2,
// 保存文件时自动格式化,主要针对html/css/less/scss等eslint未覆盖的文件格式
// "editor.formatOnSave": true,
// 保存文件时按照eslint配置自动处理vue/js/jsx/ts/json文件格式
// "eslint.autoFixOnSave": true,
// 打开对vue的lint,并自动fix
"eslint.validate": [
"javascript",
"javascriptreact",
{
"language": "vue",
"autoFix": true
}
],
// 对于.vue文件,关闭prettier,交给eslint fix
"vetur.format.defaultFormatter.css": "none",
"vetur.format.defaultFormatter.html": "none",
"vetur.format.defaultFormatter.js": "none",
"vetur.format.defaultFormatter.less": "none",
"vetur.format.defaultFormatter.postcss": "none",
"vetur.format.defaultFormatter.scss": "none",
"vetur.format.defaultFormatter.stylus": "stylus-supremacy",
"vetur.format.defaultFormatter.ts": "none",

/* stylus 配置 start */
// 是否插入冒号
"stylusSupremacy.insertColons": false,
// 是否插入分号
"stylusSupremacy.insertSemicolons": false,
// 是否插入大括号
"stylusSupremacy.insertBraces": false,
// import之后是否换行
"stylusSupremacy.insertNewLineAroundImports": false,
// 两个选择器中是否换行
"stylusSupremacy.insertNewLineAroundBlocks": false
/* stylus 配置 end */
}


后记

  • 代码格式化相关的文章已经汗牛充栋,关键点不在于各种圣战,而在于团队风格统一
  • vue 格式文件格式化比较特殊,template/script/style 部分由不同的插件来完成
  • 通过统一 IDE/插件/配置文件实现:
    • 自动格式化前端开发常见文件,实现团队代码风格统一
    • 杜绝因格式问题导致的提交冲突
    • 统一配置,团队共享,实现同步
  • 搞清楚各种 linter/formater/IDE 插件/npm 插件的分工/优先级很重要
  • ts 解决方案/git commit lint/eslint webpack loader 应该是更好也是更严格的方案,目前暂未涉及,将会是以后努力的方向

欢迎拍砖,欢迎交流

本文完

12345

48 posts
10 categories
46 tags
GitHub E-Mail Twitter Douban Zhihu
© 2014 — 2025 Vincent He