使用Prettier、Husky 和 lint-staged 进行 Commit 前处理

在编写代码时,如果你的代码中配置了 ESLint, 而你自己没有运行 ESLint ,可能会导致你的 CI build 失败。因此,在 Commit 前加入格式的修正是很有必要的。

在这篇文章中,我将向你分享,如何使用 Prettier、Husky、Lint-staged 对项目进行 commit 前的格式修复,以及如何配合 Sublime Text 使用。

1. 全局安装 Prettier

想要使用 Prettier 进行格式修复,首先,你需要安装 Prettier ,在命令行中执行如下命令:

npm install --global prettier

2. 在 Sublime Text 中安装 JSPrettier

然后,在 Sublime Text 中使用 Package Control 来安装拓展 JSPrettier

在 Sublime Text 中唤起 Package Control ,执行 Install Pacakge ,并安装其中的 JsPrettier

3. 在项目根目录中添加 Prettier 的配置文件

你可以在项目的根目录下创建一个 .prettierrc 的文件,然后在其中加入配置项目,具体的配置项目可以参考官方的 Options 页面

比如,如下是我的配置文件

{
  "singleQuote": true,
  "semi": false,
  "tabWidth": 2
}

Options 页面地址:https://prettier.io/docs/en/options.html

4. 使用 Sublime 进行格式修正

当你配置好了配置文件以后,打开 Sublime Text,找到一个 JS 文件,并打开,这时,在代码中点击右键,可以看到一个 JSPrettier Format Code ,点击这一项,就可以自动根据你所创建的配置文件,进行界面的修正了。

5. 安装 Husky 和 Lint-staged 配置 Pre-commit 检查

接下来,我们来配置 Precommit 的检查

首先,你需要安装 Husky

cnpm install lint-staged husky --dev --save

安装完成后,修改你的 packages.json 文件,在其中添加如下代码

  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,json,wpy}": ["prettier --write", "git add"]
  }

然后保存。这样,就完成了 precommit 的格式检查了。

6. 测试 commit

接下来,你可以随便修改一个文件,然后执行 git commit操作,你可以看到其会输出如下的内容

可以看到进入 husky 执行 precommit 的修复

参考链接:https://prettier.io/docs/en/precommit.html

WePy 整合云开发

由于工作上的原因,有需求要使用 WePy,刚好,有了云开发的契机,就决定研究一下。

初试 WePY

想要做云开发和 WePY,首先要先熟悉 WePY。 WePY 其实之前就听说过,不过自己一直没有使用,更多还是习惯用小程序原生写法来进行开发。

后续,也用过一些其他的框架,比如 MinUI 。

和 MinUI 相比,WePY 给我来说最大的感受是提供了 promise 的支持和 async/await 的支持,这个支持可以极大的改善 JavaScript 编程时遇到的 Callback Hell 的问题,可以让我们更加愉悦的开发。

此外,我比较看重的特性是支持外部的 NPM 包,支持 NPM 包意味着可以更好的使用 JavaScript 原本的工程化的产品,也是大大提升生产力的特性。不过,相比于 Promise 的支持和 async/await 的支持,这个如今已经被微信小程序官方团队所支持的 npm 也显得不那么重要了。

做一个 WePY 的 tempalte 吧!

在看文档时注意到,WePY 是使用 wepy init 来进行初始化的,而且可以使用 wepy list 来查看项目的模板。发现了其中有一个基于 ZanUI 的模板。

由于 ZanUI 及更名后的 VantUI 我都比较熟悉,所以从他下手,去研究一下如何制作 WePY 的模板。

复制 repo名/模板名,并在前面加上 github 的域名,就找到了对应的 repo 。

简单的看了一下项目的文件,发现其中并没有什么特殊的,需要指明初始化内容的文件,所以猜测大概率是不需要进行单独的配置的。

这方面 WePY 的文档做的不是很好,我在文档中并没有找到相关的说明。如果可以的话,希望开发者可以加一个功能,比如加上一个 .wepy-template ,可以在里面加入一些交互式的问题,从而来让用户设置一些内容。

在确定了模板其实并不困难以后,我就开始做自己的云开发模板了。

如何做一个模板

做一个模板只需要三步

  1. 下载官方的 empty 模板
  2. 加入你自己的代码
  3. 上传到 Github

说起来简单,不过,在实际制作时,还是应当注意一些问题:

  1. 初始化 Empty 模板后,尽快使用 git init 来初始化版本控制。这是因为云开发是与小程序的 AppID 进行绑定的,如果前期没有做好控制,容易出现后续将 AppID 加入了版本追踪。所以在一开始,我就将项目进行了初始化,方便后续的回溯。
  2. 上传到 Github 时,应当注意配置 Readme,在我之前的文章中,曾经提到过我们应当尽可能的交付一些产品给世界,好让世界根绝我们所交付的产品进行估值。特别是对于模板类型的 repo ,更是需要一个非常好的 Readme ,来引导别人去使用自己的模板
  3. 制作完成模板后,记得自己使用 wepy init 命令将整个过程完整的走一遍。确保你的模板是可用的。

在使用 WePY 过程中遇到的一些问题

CloudFunctionRoot 的设定问题

在做第一个版本的时候,我是将云函数的目录放在 src 目录下,后续,在运行时发现, WePY 会自动编译云函数的目录,导致出错。不得已,我将云函数的目录放置在了项目的根目录。

当时在研究这部分时,我试图去寻找 wepy.config.js文件的配置说明,希望找到一个 exclude 配置项目,来忽略一部分目录,可惜,我并没有找到。

WePY 下的一些定义问题

在使用原生写法的时候,我常常会在 Page({}) 函数外部放上一些引用。比如这样

const database = wx.cloud.database()
const storeCollection = database.collection('store')
Page({
    onReady():function(){
        // some code
    }
})

在 WePY 中我试图将代码放在 Page 实例的内部,不过会导致报错,因此,我不得不废弃这样的写法,改用 constructor 来实现。

 export default class Index extends wepy.page {
    constructor () {
      super()
      this.db = wx.cloud.database()
    }
    onLoad() {
      console.log('onLoad')
      console.log(this.db)
    }
}

对 getApp 报错

在 WePY 中,由于传承了 Vue 的思想,并没有提供对 getApp的 hack ,不过在实际的测试过程中,发现 getApp() 依然可用。

如果不引入 Redux 之类的状态管理工具的情况下,getApp() 的单例模式作为一个全局的 Bus 来进行数据的传递还是非常方便的。

关于 WePY 的其他

总的来说, WePY 是一个值得尝试的框架,单纯 Async/Await 的引入,可以让你的代码变得更加简洁易懂。特别是如果你的项目需要长期运转的情况下,整洁的代码会帮助你的项目成功。

此外,如果你很习惯于 Vue 的写法,那么 WePY 不容错过,computed 属性还是非常实用的。

小程序的 marker 无法触发 bindmarkertap 事件应该如何处理

TL;DR

如果想要 marker 可以响应 bindmarkertap 事件,需要设定 markerID,这一点文档中并没有标注。

具体情况

在开发美食地图时,出现了一个问题,marker 的点击总是不会触发 bindmarkertap 事件。

我的代码是这样写的

    store.get().then(res => {
      this.setData({
        stores: res.data,
        windowHeight: app.globalData.windowHeight,
      }, () => {
        wx.hideLoading();
        wx.showToast({
          title: '双指缩放可以调整地图可视区域,查看更多美食',
          icon: 'none'
        })
      })
    })

在地图中去调用 stores. marker

在地图上的确可以出现图标,但是无法点击 maker 并触发事件。

通过复制官方的 marker 的数据进行调试后发现,当 maker 有 id 时,marker 就可以触发事件,因此,怀疑是 ID 的问题。

在美食地图小程序中,我使用的是腾讯云提供的小程序·云开发,其使用的是 MongoDB 作为后台的 Database ,默认的主键为 _id,所以,我自己写了代码来转换 _id

      data.map(item => {
        item.id = item._id
      });

对应的 commit :https://github.com/CloudKits/miniprogram-foodmap/commit/5abcad1f756e03a388bb33dd1c699d3cae9ea0c4#diff-f5ea41cdd371d7b65bfdf8d32188e37d