Skip to main content

vue项目集成husky,lint-staged,commitlint

· 3 min read

需求场景

Git在多人合作时,应该尽量保持代码格式规范,以及commit信息清晰。这一点可以通过git的钩子实现。

解决方案

步骤一:安装husky添加pre-commit,commit-msg钩子

文档地址:https://typicode.github.io/husky/#/?id=automatic-recommended

hooks不生效原因: https://typicode.github.io/husky/#/?id=hooks-not-running

//安装husky,会在根目录生成.husky目录,以及pre-commit钩子
npx husky-init
npm install
//添加commit-msg钩子,unix环境
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
//添加commit-msg钩子,windows环境下
//node_modules/.bin/husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

步骤二:安装commitlint并配置规则

文档地址:https://commitlint.js.org/#/guides-local-setup?id=install-commitlint

config-conventional默认配置:https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/index.js

npm i @commitlint/cli @commitlint/config-conventional -D

新建.commitlintrc.js文件配填写以下配置

module.exports = {
/* type(scope?): subject 例子:feat(server): test */
// 使用预设的配置 https://github.com/conventional-changelog/commitlint/blob/master/@commitlint/config-conventional/index.js
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "chore", "revert"],
], // 改变预设中的提交类型
"type-case": [2, "always", "lower-case"], // 提交类型必须使用小写
"type-empty": [2, "never"], // type不能为空
// 'header-max-length': [2, 'always', 5], // header内容的最大长度为5
// 'subject-min-length': [2, 'always', 1], // subject内容的最小长度为1
// 'body-max-length': [2, 'always', 10], // body内容的最大长度为10
// 'footer-max-length': [2, 'always', 5], // footer内容的最大长度为5
},
};

确保husky的commit-msg钩子内容如下

#!/bin/sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install commitlint --edit $1

步骤三:安装lint-staged并配置规则

文档地址:https://github.com/okonet/lint-staged#readme

npm i lint-staged -D

在package.json中填写以下配置

{
"lint-staged": {
"src/**/*.{js,json,vue,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write"
]
}
}

确保husky的pre-commit钩子内容如下

#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

npx --no-install lint-staged

h5唤醒应用市场下载app

· 3 min read

需求场景

常规的h5引导下载app,一般ios是直接跳转appstore即可,安卓由于复杂的多,一般采用下载apk的方式,或者使用应用宝下载的方式。对于知名度不是很高的app,其实更希望安卓用户像ios一样去应用市场下载app,一方面可以减轻服务器的下载压力,一方面方便用户后续下载更新,让用户知道我们app各大应用市场均可下载,没必要一定要打开官网找下载地址。

方案分析

IOS端

微信环境下,如果是扫码打开h5可以直接跳转appstore,如果是直接打开h5链接,则无法跳转。

Android端

目前h5唤醒app主要有3种方式。通用的Url Schema,(Ios 的Universal Link)以及Android的App Link。

Url Schema的缺点:

1. 比较明显的缺点在于微信等浏览器屏蔽这种方式,需要引导用户去其他浏览器打开。

2. 部分浏览器会在跳转时有提示弹窗,需要二次确认。

3. 无法监听唤醒是否成功,一种通用的方案是去监听浏览器的pagehide事件,设置一个时间点比如2s没有触发则判定没有唤醒成功。

4. 由于国内各大应用市场没有一个统一的规范,没有一个汇总的url schema地址,而且后续各个平台如果修改了链接,开发者需要及时跟进,这个问题就很复杂了,不过正常情况下这种不会轻易修改。

开源类库:https://github.com/suanmei/callapp-lib

相关文档:https://juejin.cn/post/6844903664155525127

国内应用市场链接汇总:国内厂商应用商店跳转链接 (linchangyu.com)

移动端常用meta标签

· One min read
    <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0,user-scalable=0" />

vite esm 跨域问题

· 2 min read

需求场景

因为vue3以及vite的发布,目前一些新的项目已经切换到vue3以及vite打包工具上。由于之前的项目会把打包后的静态资源上传到阿里云oss,然而使用vite打包上传后却出现了问题。竟然提示cors跨域问题,简直是不可思议!!因为这个demo项目中并没有涉及到ajax交互,而且之前也使用vite完成过一些项目,怎么就突然有问题了,是哪里的使用姿势不对?只听过ajax的跨域问题,还没听过js加载的跨域问题,嗯,现在你听说了。

问题原因

因为vite使用了esm模块化加载,也正是因为esm可以让js打包体积更小的优点,算是vite的一个亮点。不过esm加载其他域名下的js就是有跨域的问题的。所有跨域的 ESM 资源加载都需要在资源响应头上添加 Access-Control-Allow-Origin 的响应头。

sequlize设置timezone

· 2 min read

需求场景

使用sequlize读写mysql/mariadb数据时,默认会给每个表添加createdAt,updatedAt字段。由于一般情况下,项目timezone会使用东八区“+8:00”。如果在数据库中存储“+0:00”时区,就会经常遇到时间转换的问题。网上的答案大多数都是添加timezone字段即可。实际情况是添加timezone字段只会在存入数据库时使用“+8:00”区,而从数据库读取还是“+0:00”时区,还是需要进行时间转换的,如果一个个转就崩溃了,肯定不可取。

解决方案

后来终于在sequlize的issue中找到了解决方案,这个issue居然从2013年就存在了。。。至今未关闭。。。看到一些issue提到关于时区转换这块,文档还不够详细,确实啊,很容易坑人。核心代码如下

 useFactory: (configService: ConfigService) => ({
dialect: 'mariadb',
//for writing to database
timezone: '+08:00',
dialectOptions: {
// for reading from database
dateStrings: true,
typeCast: true,
},
...
})

相关issue:https://github.com/sequelize/sequelize/issues/854

js数组转对象reduce

· 2 min read

需求场景

最近在写一个小程序端类似于github calendar的功能。参考了一些源码发现都是svg形式或者react的,并且第一格都代表周日,不符合中国周一是第一天的习惯。小程序没法直接用,没办法只能自己造轮子了。写的过程中有一个需要将数组转为对象,然后新的对象再和另一个数组合并的功能。其中数组转对象,我就使用了最简单的for循环。然而后面却发现使用reduce方式也可以实现数组转对象,这是什么操作,花里胡哨啊。

Reduce实现的优点

for循环实际是命令式编程,reduce是函数式编程。函数式编程的一个优点就是看起来比较清晰,性能当然没那么好。不过这年头还是代码清晰易维护重要啊,性能等出现了再去优化也不迟。

const dataTmp = data.reduce((target, v) => {
let day = getDayOfYear(new Date(v.date))
target[day] = v;
return target;
}, {});
const dataTmp={};
for(let i=0;i<data.length;i++){
let day = getDayOfYear(new Date(data[i].date))
dataTmp[day]=data[i]
}

贴一下自己实现的github calendar,后续抽空继续优化。https://github.com/zenonux/calendar-graph

z-index不生效?

· 2 min read

需求场景

考虑以下场景,A 元素包含 B,C 元素,B 元素包含 B1 元素,C 元素包含 C1 元素。为什么 C1 元素的 z-index 明明很高,却始终在 B1 元素下面?

  <div id="A" style="position: relative;">
<div id="B">
<div id="B1" style="position: absolute;z-index:1000;">B1</div>
</div>
<div id="C" style="position: relative;z-index: 0;">
<div id="C1" style="position: absolute;z-index:9000;">C1</div>
</div>
</div>

然后我把代码稍作改动,为什么 C1 又在 B1 上面了呢?

   <div id="A" style="position: relative;">
<div id="B">
<div id="B1" style="position: absolute;z-index:1000;">B1</div>
</div>
<div id="C" style="position: relative;z-index:auto;">
<div id="C1" style="position: absolute;z-index:9000;">C1</div>
</div>
</div>

解决方案

z-index 的使用涉及到一个层叠上下文的概念。首先只有 position 元素的值为非 static 时,z-index 才会生效,才是有意义的。每一个值为非 static 的 position 元素都会创建一个层叠上下文环境。在我们的示例中就是 A 层叠环境里包含 B1 层叠环境和 C 层叠环境,C 层叠环境包含 C1 层叠环境。这里就可以发现 A 到 C1 有 2 层而 A 到 B1 只有 1 层,所以 C1 的 z-index 无论多大都不会盖住 B1。

那么问题来了,为什么第二种情况把 z-index=0 改成 auto 就变了呢?因为 auto 不会创建层叠上下文环境!!!是个特殊值

进阶思考

其实能创建层叠上下文的不止 z-index,还有 transform 等

详细参考:https://zhuanlan.zhihu.com/p/340371083

ssh免密码登录

· 3 min read

需求场景

每次登录服务器都使用密码登录是很烦人的,很容易忘记密码,还有个出于安全考虑的原因,一般推荐使用ssh密钥登录。

解决方案

  • 客户端生成密钥对

在客户端`~./.ssh/`目录下执行命令,生成密钥对

ssh-keygen -t rsa
  • 服务端写入客户端生成的公钥

在服务端`~./.ssh/`目录下新建 authorized_keys 文件,并把客户端生成的pub公钥的内容写入。

进阶思考

很多文章都是采用上面的方式在本地执行`ssh-keygen -t rsa`生成密钥对,然后将本地生成的pub公钥写入服务器端的authorized_keys的文件中。这样做并没有什么问题,并且一直以来博主也是这么做的,直到有次用到了腾讯云自带的密钥登录功能,发现一个很有意思的事情,他是在服务端执行` ssh-keygen -t rsa`生成密钥,然后将服务端的pub密钥写入自己的 authorized_keys 文件中,然后将私钥提供给用户下载,用户每次登录需要携带服务端的私钥。然后就发现新世界了,在本地或者服务端生成密钥其实都可以,只需要保持私钥和公钥的匹配即可。

腾讯云这样做的原因是作为服务商他只有服务器的权限,没有用户电脑的权限,当然在服务端生成比较合适。博主之前一直使用本地生成密钥对的方式,在使用过程中发现有一个缺点,就是客户端往往不止一台,就需要生成多个密钥加入服务端,此外客户端生成的密钥不稳定,有时候会被不小心清理掉。然后又需要重新生成。也就会出现密钥对很多且不稳定。而采用服务端生成密钥对的方式就解决了这两个问题。密钥只需要生成一次,客户端使用用一个私钥登录,此外服务端的密钥一般不会轻易改动,稳定性也大。

php nginx File not found

· 2 min read

需求场景

最近在腾讯云重新部署php,nginx环境遇到一个非常坑的问题,两台服务器同样的配置,刚部署的服务器出现File not found.

排查

通过`tail -f /var/log/nginx/error.log`在日志中发现Permission denied,Primary script unknown 等报错,查找资料说是权限问题。一般都是让检查nginx的默认用户www-data和php-fpm的默认用户www-data是不是一致。因为默认都是www-data不去改动的话,肯定都是一样的。或者是项目目录权限改为777等,实测都是无效的。

最终解决方案

以为腾讯云默认用户为ubuntu,一般不推荐root直接登录。所以我是在ubuntu用户下登录部署的,把项目部署在了/home/ubuntu/projects下面。因为默认的/var/www/html是可以访问的,而我部署在/home/ubuntu/projects就是不可访问的,当我把项目移动至/home/projects下面就可以了。。。回想起来,之前的一台腾讯云服务器一直用root登录,项目部署在/home/projects也是没有问题的。

问题思考

所以这个问题的根本原因还是权限问题,只不过这个权限问题相当坑,777也解决不了。