本文将会联合 ESLint、Prettier、husky、lint-stage、gulp.js 等工具使得我的项目一键化操作,缩小在格式化、代码查看等操作上浪费时间,因为大前端真的太多货色学了,不学会“偷懒”的话,咱们就要落后更多了。

本系列文章的示例 Demo 在这里 ???? GitHub: wechat_applet_demo。

分为两篇文章介绍:

  • 使Prettier一键格式化WXSS(上集)
  • 使Prettier一键格式化WXSS(下集)

在简书也有更新 ???? 这里。

最近在做公司部门前端我的项目由 SVN 迁徙 Git 的事件,因为历史代码在此之前并没有引入相似 ESLint、Prettier 的代码查看或者格局束缚等工具。

目前部门仅剩我一人保护这十几个小程序、H5 前端我的项目。当初只有接触以前那些没有经手的我的项目,就头疼不想改。尽管思维是这样,但很无奈,谁让我只是一个“打工仔”呢!

吐槽完,入正题。

一、必备

1. 新建一个微信小程序我的项目

此处过于简略省略一万字...

# 或者克隆 wechat_applet_demo 我的项目下来$ cd your_folder$ git clone git@github.com:toFrankie/wechat_applet_demo.git
2. 应用 yarn 作为包管理工具

yarn 相干的装置不在本系列教程,置信你们都懂。也不再赘述,自行搜寻。

3. 应用 Visual Studio Code 作为编辑器

尽管从业有一段时间了,不好意思,前端开发我只用 VS Code,未来好长一段时间应该还是它。至于什么 WebStorm、Atom、Sublime Text 等,用过但当初曾经不会了。

Anyway,什么开发工具不重要,本人用着难受就好。

上面介绍几个与本我的项目相干的 VS Code 插件

ESLint:自动检测 ESLint Rule,不合乎规定时,在编辑页面会有正告 ️
Prettier - Code formatter:可用于格式化

依照以上两个插件之后,须要对编辑器做增加一些配置。

思考到多人开发的场景,而每个人的开发工具配置不尽相同,所以我把以下配置放到我的项目根目录下中,并将其退出 Git 版本控制中,这样每个人拿到我的项目都有此配置了。

门路是:your_project/.vscode/settings.json

{  "files.associations": {    "*.wxss": "css",    "*.wxs": "javascript",    "*.acss": "css",    "*.axml": "html",    "*.wxml": "html",    "*.swan": "html"  },  "files.trimTrailingWhitespace": true,  "eslint.workingDirectories": [{ "mode": "auto" }],  "eslint.enable": true, // 是否开启 vscode 的 eslint  "eslint.options": {    // 指定 vscode 的 eslint 所解决的文件的后缀    "extensions": [".js", ".ts", ".tsx"]  },  "eslint.validate": ["javascript"],  "editor.codeActionsOnSave": {    "source.fixAll.eslint": true  },  "git.ignoreLimitWarning": true}

二、要开始了

1. yarn 初始化生成 package.json

2. 装置 ESLint、Prettier 相干依赖

若要应用 ESLint,往往须要配置很多繁冗的 rules 规定,如果每个人都要这种做的话,显然会消耗很多精力。于是就有人站了进去,并在 GitHub 上开源了他们的代码标准库,比拟风行的有 airbnb、standard、prettier 等。

在这里我抉择的是国内腾讯 AlloyTeam 团队出品的 eslint-config-alloy 开源标准库。

其实他们团队最开始应用 Airbnb 规定,然而因为它过于严格,局部规定还是须要个性化,导致起初越改越多,最初决定从新保护一套。通过两年多的打磨,当初 eslint-config-alloy 曾经十分成熟了。

我抉择它的几点起因:

  • 实用于 React/Vue/Typescript 我的项目
  • 款式相干规定由 Prettier 治理
  • 有中文文档和网站示例(就我那糟糕的英语水平,这点极吸引我,哈哈)
  • 更新快,且领有官网保护的 vue、typescript、react+typescript 规定
$ yarn add --dev babel-eslint@10.0.3$ yarn add --dev eslint@6.7.1$ yarn add --dev eslint-config-alloy@3.7.1$ yarn add --dev eslint-config-prettier@6.10.0$ yarn add --dev eslint-plugin-prettier@3.1.4$ yarn add --dev prettier@2.0.5$ yarn add --dev prettier-eslint-cli@5.0.0
3. 装置完依赖,那么就要加上 ESLint、Prettier 的配置文件

他们的配置文件能够有多种,这里应用 JavaScript 格局别离是 .eslintrc.js.prettierrc.js,都搁置在我的项目根目录下。

对于配置我就不开展说了,若有纳闷的,能够自行搜寻查找答案或者评论留言给我。

// .eslintrc.jsmodule.exports = {  root: true,  parser: 'babel-eslint',  env: {    browser: true,    es6: true,    node: true,    commonjs: true  },  extends: ['alloy'],  plugins: ['prettier'],  globals: {    Atomics: 'readonly',    SharedArrayBuffer: 'readonly',    __DEV__: true,    __WECHAT__: true,    __ALIPAY__: true,    App: true,    Page: true,    Component: true,    Behavior: true,    wx: true,    my: true,    swan: true,    getApp: true,    getCurrentPages: true  },  parserOptions: {    ecmaVersion: 2018,    sourceType: 'module'  },  rules: {    'no-debugger': 2,    'no-unused-vars': 1,    'no-var': 0,    'no-param-reassign': 0,    'no-irregular-whitespace': 0,    'no-useless-catch': 1,    'max-params': ['error', 3],    'array-callback-return': 1,    eqeqeq: 0,    indent: ['error', 2, { SwitchCase: 1 }]  }}
// .prettierrc.jsmodule.exports = {  printWidth: 120,  tabWidth: 2,  useTabs: false,  semi: false,  singleQuote: true,  // 对象的 key 仅在必要时用引号  quoteProps: 'as-needed',  // jsx 不应用单引号,而应用双引号  jsxSingleQuote: false,  // 开端不须要逗号  trailingComma: 'none',  // 大括号内的首尾须要空格  bracketSpacing: true,  // jsx 标签的反尖括号须要换行  jsxBracketSameLine: false,  // 箭头函数,只有一个参数的时候,无需括号  arrowParens: 'avoid',  // 每个文件格式化的范畴是文件的全部内容  rangeStart: 0,  rangeEnd: Infinity,  // 不须要写文件结尾的 @prettier  requirePragma: false,  // 不须要主动在文件结尾插入 @prettier  insertPragma: false,  // 应用默认的折行规范  proseWrap: 'preserve',  // 依据显示款式决定 html 要不要折行  htmlWhitespaceSensitivity: 'css',  // 换行符应用 lf  endOfLine: 'lf'}
4. 配置 ESLint、Prettier 疏忽规定

对应的文件是 .eslintignore.prettierignore,同样的都放在我的项目根目录下。

这些就依据本人我的项目理论状况做调整了,以下仅供参考:

# .eslintignore*.min.jstypingsnode_modules
# .prettierignore*.min.js/node_modules/dist# OS.DS_Store.idea.editorconfig.npmrcpackage-lock.json# Ignored suffix*.log*.md*.svg*.png*ignore## Built-files.cachedist
5. 增加 .editorconfig 配置文件

它是用来抹平不同编辑器之间的差别的。同样搁置在我的项目根目录下。

# .editorconfig# http://editorconfig.org# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties# 根目录的配置文件,编辑器会由当前目录向上查找,如果找到 `roor = true` 的文件,则不再查找root = true# 匹配所有的文件[*]# 缩进格调:spaceindent_style = space# 缩进大小 2indent_size = 2# 换行符 lfend_of_line = lf# 字符集 utf-8charset = utf-8# 不保留行末的空格trim_trailing_whitespace = true# 文件开端增加一个空行insert_final_newline = true# 运算符两遍都有空格spaces_around_operators = true# 对所有的 js 文件失效[*.js]# 字符串应用单引号quote_type = single[*.md]trim_trailing_whitespace = false
6. 增加 npm scripts

增加三条脚本指令:

  • "eslint": "eslint ./ --ext .js"
  • "eslint:fix": "eslint --fix ./ --ext .js"
  • "prettier:fix": "prettier --config .prettierrc.js --write './**/*.{js,css,less,scss,json}'"

通过 yarn run <command> 即可执行一键格式化和修复了,当然了 ESLint 应用 --fix 只能修复一部分,残余的只能手动解决了。

{  "name": "wechat_applet_demo",  "version": "1.0.0",  "description": "微信小程序 Demo",  "main": "app.js",  "repository": "git@github.com:toFrankie/wechat_applet_demo.git",  "author": "Frankie <1426203851@qq.com>",  "license": "MIT",  "private": true,  "scripts": {    "test": "echo \"Error: no test specified\" && exit 1",    "eslint": "eslint ./ --ext .js",    "eslint:fix": "eslint --fix ./ --ext .js",    "prettier:fix": "prettier --config .prettierrc.js --write './**/*.{js,css,less,scss,json}'"  },  "devDependencies": {    "babel-eslint": "10.0.3",    "eslint": "6.7.1",    "eslint-config-alloy": "3.7.1",    "eslint-config-prettier": "6.10.0",    "eslint-plugin-prettier": "3.1.4",    "prettier": "2.0.5",    "prettier-eslint-cli": "5.0.0"  }}

三、你认为完了?

不不不,本文我最想分享的是上面这个,后面的内容都比较简单,很多人都懂了。

Prettier 反对的 JavaScript、JSX、Angular、Vue、Flow、TypeScript、CSS、Less、Scss、HTML、JSON、GraphQL、Markdown(GFM、MDX)、YAML 的代码格式化。

但其实是不能辨认 wxssacss 等小程序特有的层叠款式,只管它们规定与 CSS 无异,然而 Prettier 并没有解析器去解析它们。

咱们试图去调整脚本命令为(增加 *.wxss 扩展名的文件):

{  "scripts": {    "prettier:fix": "prettier --config .prettierrc.js --write './**/*.wxss'",  }}

而后去执行的时候就会报错,如下:

[error] No parser could be inferred for file: app.wxss

既然这样走不通的话,总不能利用 VS Code 的 Prettier 插件一个一个地去格式化 *.wxss 的文件吧,那样工作量太大了,不合乎咱们“偷懒”的做法。

那么如何解决呢?

我应用的是 Gulp.js 来解决。如果对 Gulp 不太熟悉了,点击这里理解一下。

四、Gulp.js

简略说下 Gulp.js 的工作形式,它应用的是 Node.js 中的 stream(流),首先获取到须要的 stream,而后通过 streampipe() 办法把流导入到你想要的中央。比方 Gulp 插件中,通过插件解决后的流又能够导入到其余插件汇总,当然也能够把流写入文件中,所以 Gulp 是以 stream 为媒介的,它不须要频繁的生成临时文件,这也是 Gulp 的速度比 Grunt 快的一个起因。

我刚开始时的想法是:首先将 wxssacss)转换并导出为 css,接着删除 wxssacss)文件,再者应用 Prettier 对 css 文件进行格式化,转回 wxssacss)之后,再删除掉 css 文件。这个过程会频繁的生成临时文件,思路是有点像 Grunt。

然而理解了 Gulp 的思维后,其实它帮咱们省掉了频繁增删文件的环节,全副放在内存中操作,也会更快一些,所以此前的计划被我否掉了。

上面咱们只用到 Gulp 的其中两个 API, gulp.src()gulp.dest()

1. gulp.src()

这个办法是用来获取流的,但要留神这个流外面的内容不是原始的文件流,而是一个虚构文件对象流(Vinyl files),这个虚构文件对象中存储着原始文件的门路、文件名、内容等信息。(这里不深刻,点到为止,有趣味自行理解)

语法:gulp.src(globs[, options])
  • globs:是文件匹配模式,用来匹配文件门路(包含文件名)
  • options:为可选参数,通常状况咱们不须要用到

*对于参数具体阐明,请看文档。

2. gulp.dest()

该办法是用来写文件的

gulp.dest(path[, options])
  • path:是写入文件的门路
  • options:为可选参数,通常状况咱们不须要用到

要想应用好 gulp.dest() 这个办法,就要了解给它传入的门路参数与最终生成的文件的关系。

Gulp 的应用流程个别是:首先通过 gulp.src() 办法获取到咱们想要解决的文件流,而后把文件流通过 pipe() 办法导入到 Gulp 的插件中,最初把通过插件解决后的流再通过 pipe() 办法导入到 gulp.dest() 中,gulp.dest() 办法则把流中的内容写入到文件中。

这里须要弄清楚的一点是,咱们给 gulp.dest() 传入的门路参数,只能用来指定要生成的文件的目录,而不能指定生成文件的文件名,它生成文件的文件名应用的是导入到它的文件流本身的文件名,所以生成的文件名是由导入到它的文件流决定的,即便咱们给它传入一个带有文件名的门路参数,而后它也会把这个文件名当做是目录名,例如:

const gulp = require('gulp')gulp.src('script/jquery.js').pipe(gulp.dest('dist/foo.js'))// 最终生成的文件门路为 dist/foo.js/jquery.js,而不是 dist/foo.js

若须要批改文件名,须要应用插件 gulp-rename。

  • 对于上述 Gulp 的 API 与办法阐明,次要参考自官网文档与无双的一篇文章。

五、开始配置

首先,装置 Gulp 相干依赖包。

$ yarn add --dev gulp@4.0.2$ yarn add --dev gulp-clean@0.4.0$ yarn add --dev gulp-debug@4.0.0$ yarn add --dev gulp-prettier@3.0.0$ yarn add --dev gulp-rename@2.0.0

接着,咱们在我的项目根目录下创立一个 gulpfile.js 文件。

Gulp.js 官网疾速入门的教程,很简略,这里不在赘述。

思路:应用 gulp.src() 获取流,而后应用 Gulp 插件对流别离作重命名(gulp-rename)、格式化(gulp-prettier)、再重命名回来(gulp-rename)、最初导出(gulp.dest())。过程中有利用 gulp-debug 插件来查看一些信息。

这里我对微信小程序、支付宝小程序的层叠款式都解决了。

// gulpfile.jsconst { 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}

通过以下形式调用就好了

// package.json{  "scripts": {    "prettier:wxss": "gulp wxss",    "prettier:accs": "gulp acss",    "prettier:wxss:acss": "gulp all"  }}

执行命令,咱们看到如下后果,阐明配置胜利了。

六、Git-Hooks

下面曾经实现了对 wxssacss 扩展名的文件进行一键格式化了。

还能够“更懒”一些,利用 git-hooks 咱们可实现在 commit 之前,对我的项目进行 ESLint、Prettier 检测和格式化,一旦呈现谬误,将进行 commit 操作。

因为本文篇幅曾经很长了,所以咱们放到下一篇持续写...

七、插个题外话

因为本我的项目的 npm 包仅用于代码查看与格式化,并未参加页面代码逻辑中。所以我在小程序本地我的项目配置文件中增加上打包配置选项。

packOptions 用以配置我的项目在打包过程中的选项。打包是预览、上传时对我的项目进行的必须步骤。

目前能够指定 packOptions.ignore 字段,用以配置打包时对合乎指定规定的文件或文件夹进行疏忽,以跳过打包的过程,这些文件或文件夹将不会呈现在预览或上传的后果内。

*须要留神的是支付宝小程序,在编写本文时还未反对相似 ignore 选项。

// project.config.js{  "packOptions": {    "ignore": [      {        "type": "regexp",        "test": "\\.md$"      },      {        "type": "folder",        "test": "node_modules"      }    ]  }}