monorepo commit 加速【第二弹】
随着业务的发展,monorepo 工程越来越大~
- 在
git commit
时耗时会比较久,耗时是大概 1min+; - 在
git merge release
分支时耗时会更久,常常是 5min+;
所以在实际开发过程中,会发现有部分同学偶尔会跳过 git hook,跳过 lint 校验拦截,提交有类型报错的代码。
为什么会这么慢?
根据以往的工作经验,在没有用 ts 的工程里 lint 执行都是比较快的,所以这里猜想是 ts 的某些 rule 影响了整体的执行速度,终于在 typescript-eslint 找到了原因:Troubleshooting & FAQs | TypeScript ESLint
如果我们在工程里开启了type-aware lint,那么执行 lint 的时间将会和构建时间一样长。
typescript-eslint 的一些 rules 是依赖 type information,所以在执行 lint 前会先编译一遍ts
Linting with Type Information | TypeScript ESLint 官网这里具体描述了type-aware 是如何开启的:
- 配置
parserOptions
(tsconfigRoot、project) - 配置
type-aware
相关 rules
解决 monorepo 工程 husky 提交慢的问题
业务发展了一年多,随着工程越来越大,发现在提交代码的时候,耗时会很久。最近在业务需求不是很紧的时候,就抽空研究了一下。
在提交代码的时候,触发了 husky 配置的 pre-commit
的 git hooks。相信大家对于这个 git hook 不会很陌生,我们大部分需要团队合作的项目,为了约束大家的代码规范,通常会选择使用 husky 并且在提交前进行代码校验拦截,这个时机就刚好是 pre-commit
git hooks 的时机。
所以问题一下就变得清晰起来,是 pre-commit 的 hook 执行的 lint 检查耗时过长。首先先介绍下我们工程的技术选型:yarn + learn + ts + react ,在正式排查前,猜测主要导致 lint 执行慢的因素大概有两个 monorepo(工程多、代码量大)、ts(ts 类型检查耗时)。
在开始排查问题之前,先做了个小测试:只改动了一个 tsx 文件,并尝试提交,计时发现,从开始 commit 到 commit 完成,发现竟然耗时了 1min+,晕~。这里就猜想会不会是某个 lint 规则 或 某个 lint 插件导致运行很慢的?接下来就沿着这个思路进行排查。
搞清楚 eslint 的 plugins 和 extends
最近在鼓捣 eslint 规则配置的时候,有两个配置一直傻傻分不清,这两个配置就是 extends
和 plugins
。相信大家在实践过程中也会遇到这样的困扰,今天就来一起看一看,彻底搞清楚。
首先,我们知道 eslint 是一个代码检查工具,它会根据我们在工程里配置的规则,来进行校验。我们常常在以下场景中使用到 eslint。
- vscode、webstorm 等编辑器、IDE安装插件
- 工程运行时,通过 eslint-loader 检查及时发现问题
- commit 时进行代码检查校验拦截(通常会配合 husky + lint-staged 使用)
所以一个团队如果想要保持统一的代码风格、良好的编码习惯,那约定和制定自己的 lint 规则就显得很重要。
rules
在简单的场景中,我们可以不需要了解 plugins 和 extends 的概念,比如只是约定「封号」、「引号」的使用:
1 | { |
通过这样的配置,就约定了工程里统一强制使用封号结尾和双引号。
然而渐渐的,eslint 默认的一些规则不再满足我们的需要,这时我们就需要引入更多的规则集,这就是 plugins 的概念。
styled-components 使用 loadable 懒加载时样式优先级问题
最近在 React 项目中引入 @loadable/component
进行懒加载优化时,发现了一个样式优先级问题。
我们工程里使用的是公司内部组件库,在想要覆盖组件库组件的样式时,基于 styled-components
的写法如下:
1 | import styled from 'styled-components'; |
正常情况下,上述代码应该会生效,即最终展现在页面上的按钮样式宽度应该是 80 px,高度为 32 px,覆盖原 Button 组件的宽高样式。
但是在实际使用过程中,我们发现了一些异常:覆盖的样式会偶现失效的情况。有些时候自定义宽高会生效,有些时候自定义宽高不会生效。经过排查,发现如果是在CustomButton
所在页面刷新,则按钮展示的宽高是符合预期的,如果是从其他页面进入的,则自定义宽高不会生效。没有生效的原因也很简单,CustomButton
的样式优先级排在了 Button
后面。
Yarn resolutions
Yarn 支持在工程的 package.json 文件中的 resolutions
字段里指定包的特定版本或者版本范围。
使用场景
- 可能工程里的某个依赖的包A不是经常更新,但是这个包所依赖的包B有一个重要更新。这这种情况下,如果这个包A指定的依赖包B的版本范围没有覆盖到包B的最新版本的话,即重新安装依赖时,也不会安装到最新的包B,这时我们可能就要一直等待包A的作者更新了。
- 当工程里的子依赖有一个重要的安全方面的更新,并且你不想等你直接依赖的包更新时
- 当工程中某个依赖包正常运行,但是作者不再维护了。如果这个包某个依赖包有更新时,而且我们需要这个更新时。
- 当工程中某个依赖包定义了一个很大范围的版本时,如果子依赖此时更新了一个最新版本存在bug,我们想退回之前的版本时,
总的来说就是,我们希望指定工程直接依赖里的某个子依赖包的版本时,可以使用
resolutions
BFC
CSS 包含块
Varnish 入门
eggjs启动从回车到ready
JavaScript代码是单线程运行的,因而一旦有未捕获的异常抛出线程就会挂掉,业务也就不可访问了,所以一般我们在使用koa,express,thinkjs等其他node框架时一般会使用pm2去管理node进程,保证业务的高可用性。而阿里开源的egg框架本身自带的egg-cluster模板已经帮我们做了这个事情,egg的多进程模型和进程间通信官方文档上写的已经很清楚了,今天学习一下源码,希望有所收获。
egg-bin dev
运行一个egg项目,npm run dev
在package.json文件里我们发现默认其实执行的是egg-bin dev
。egg-bin原来是egg提供的一个开发时使用的命令行工具,翻开egg-bin的代码,我们可以看到egg-bin其实是基于common-bin开发的,这里不赘述common-bin的用法,感兴趣的童鞋自行去查阅。在lib/cmd/dev.js
里我们可以看到egg-bin dev
执行的逻辑(去掉debug日志):