本文将会结合 ESLint、Prettier、husky、lint-stage 展开介绍,旨在在代码格式化、代码检查上减少时间浪费。
完整示例:wechat_applet_demo。
共三篇:
使Prettier一键格式化WXSS(上集)
使Prettier一键格式化WXSS(下集)
使Prettier一键格式化WXSS(结局篇)
微信开放社区用 Markdown 用着不顺手,本文只做一个大概的简述,具体请看这里。
一、前世今生
最近,在处理部门前端项目由 SVN 迁移 Git 的事情。由于历史代码在此之前并没有引入类似 ESLint、Prettier 的代码检查或者格式约束等工具。
目前部门仅剩我一人维护这十几个小程序、H5 前端项目。现在只要接触以前没有经手的项目,就头疼不想改,很无奈,谁让我是一个打工人呢!
二、必备
创建小程序项目,使用 yarn 作为包管理工具、安装 vscode 相关插件。
三、配置 ESLint、Prettier
这些都不难了,很多人都懂了。还是那句话,看我上面的原文。
其实 ESLint、Prettier 在目前的 H5 项目中,几乎所有前端框架或库都兼容得很好了,一系列配套的工具简直用得不要太爽了。Prettier 支持 CSS、LESS、SCSS 等,但是呢,他遇到小程序的 wxss 或者 acss 却不行了,会报错:
[error] No parser could be inferred for file: app.wxss
原因是 Prettier 并没有解析器去解析它们,它不知道怎么处理,所以就抛出错误了。
这就是本文主要要解决的问题。在此之前,我是通过安装 vscode 插件 Prettier - Code formatter 一个一个来格式化的,太傻了。
四、如何让 Prettier 识别小程序的层叠样式呢?
此前我去网上搜索了一番,似乎真没有人去做这件事,也可能是没公开或者没写出来,反正我还没找到,哈哈。
下面我走了一些弯路,Prettier 其实是可以针对某些文件类型指定不同的 Parser 的,此前我并没有发现,所以才走了一些弯路,这样就不需要使用 Gulp 做类型转换了。详细看简书原文,这里不更新了。
我使用的是 Gulp.js 来处理。如果对 Gulp 不太熟悉了,点击这里了解一下。
简单说下 Gulp.js 的工作方式,它使用的是 Node.js 中的 stream
(流),首先获取到需要的 stream
,然后通过 stream
的 pipe()
方法把流导入到你想要的地方。比如 Gulp 插件中,经过插件处理后的流又可以导入到其他插件汇总,当然也可以把流写入文件中,所以 Gulp 是以 stream
为媒介的,它不需要频繁的生成临时文件,这也是 Gulp 的速度比 Grunt 快的一个原因。
下面我们只用到 Gulp 的其中两个 API, gulp.src()
和 gulp.dest()
。
思路:使用gulp.src()
获取流,然后使用 Gulp 插件对流分别作重命名(gulp-rename)、格式化(gulp-prettier
)、再重命名回来(gulp-rename
)、最后导出(gulp.dest()
)。过程中有利用gulp-debug
插件来查看一些信息。
// gulpfile.js
const { series, parallel, src, dest } = require('gulp')
const rename = require('gulp-rename')
const debug = require('gulp-debug')
const clean = require('gulp-clean')
const prettier = require('gulp-prettier')
const config = require('./.prettierrc')
// wxss 一键格式化
const wxssPrettier = () => {
return src('./**/*.wxss')
.pipe(
// 可以利用插件,查看一些 debug 信息
debug()
)
.pipe(
// 重写扩展名为 css,才能被 Prettier 识别解析
rename({
extname: '.css'
})
)
.pipe(
// Prettier 格式化
prettier(config)
)
.pipe(
// 重新将扩展名改为 wxss
rename({
extname: '.wxss'
})
)
.pipe(
// 导出文件
dest(__dirname)
)
}
// acss 一键格式化
const acssPrettier = () => {
return src('./**/*.acss')
.pipe(debug())
.pipe(
rename({
extname: '.css'
})
)
.pipe(prettier(config))
.pipe(
rename({
extname: '.acss'
})
)
.pipe(dest(__dirname))
}
// 这里导出多个 task,通过 gulp xxx 就能来调用了,如 gulp all
// 关于 series、parallel API 分别是按顺序执行(同步)、同时执行(并行)
module.exports = {
all: parallel(wxssPrettier, acssPrettier),
wxss: wxssPrettier,
acss: acssPrettier
}
调用 Gulp 任务:
// package.json
{
"scripts": {
"prettier:wxss": "gulp wxss",
"prettier:accs": "gulp acss",
"prettier:wxss:acss": "gulp all"
}
}
五、Git-Hooks
利用 Git Hooks 钩子实现提交代码自动执行此前的 ESLint、Prettier 命令,以保证我们提交的代码是不丑的。
我们这里使用到的是 pre-commit。
六、husky
husky 是一个为 Git 客户端增加 hook
的工具。当其安装到所在仓库时,它会自动在 .git/hooks
增加相应的钩子实现在 pre-commit
阶段就执行一系列保证每一个 commit
的正确性。
当然,pre-commit
阶段执行的命令,当然要保证其速度不要太慢,每次 commit
都等很久也不是好的体验。
// package.json
{
"husky": {
"hooks": {
"pre-commit": "yarn run format:all"
}
}
}
七、lint-staged
上面的流程,我们只提交了一个文件的变动,但是它对所有文件进行了扫描,这里是存在体验性问题的。
假如我们有 N 多个暂存文件,那么每当我们 git commit
一次就所有检查所有文件一遍,这导致我们的体验非常不好,过程很慢,显然不是我们想要的。
那么如何解决呢?我们需要用到它 👉 lint-staged。
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged --config .lintstagedrc.js"
}
}
}
// .lintstagedrc.js
const path = require('path')
module.exports = {
'*.js': ['prettier --config .prettierrc.js --write', 'eslint --fix --ext .js'],
'*.json': 'prettier --config .prettierrc.js --write',
'*.wxss': absolutePaths => {
// 获取相对路径
// const cwd = process.cwd()
// const relativePaths = absolutePaths.map(file => path.relative(cwd, file))
// return `gulp wxss --path ${relativePaths.join(' ')}`
return 'gulp wxss'
},
'*.acss': 'gulp acss'
}
八、至此
上面介绍的都很粗糙,不完整。有兴趣的请看 👉 原文。
为啥不用prettier的overrids属性直接修改对应文件类型的parser
我用vs-code那个插件格式化小程序很乱啥咋回事.没两个view之间隔了4个tab 乱七八糟
不明觉厉