使Prettier一鍵格式化WXSS(上集)

本文將會結合 ESLint、Prettier、husky、lint-stage、gulp.js 等工具使得項目一鍵化操做,減小在格式化、代碼檢查等操做上浪費時間,由於大前端真的太多東西學了,不學會「偷懶」的話,咱們就要落後更多了。javascript

本系列文章的示例 Demo 在這裏 👉 GitHub: wechat_applet_democss

分爲三篇文章介紹:html

在簡書也有更新 👉 這裏前端

最近在作公司部門前端項目由 SVN 遷移 Git 的事情,因爲歷史代碼在此以前並無引入相似 ESLintPrettier 的代碼檢查或者格式約束等工具。vue

目前部門僅剩我一人維護這十幾個小程序、H5 前端項目。如今只要接觸之前那些沒有經手的項目,就頭疼不想改。雖然思想是這樣,但很無奈,誰讓我只是一個「打工仔」呢!java

吐槽完,入正題。node

1、必備

1. 新建一個微信小程序項目

此處過於簡單省略一萬字...react

# 或者克隆 wechat_applet_demo 項目下來
$ cd your_folder
$ git clone git@github.com:toFrankie/wechat_applet_demo.git
2. 使用 yarn 做爲包管理工具

yarn 相關的安裝不在本系列教程,相信大家都懂。也再也不贅述,自行搜索。jquery

3. 使用 Visual Studio Code 做爲編輯器

雖然從業有一段時間了,很差意思,前端開發我只用 VS Code,未來好長一段時間應該仍是它。至於什麼 WebStorm、Atom、Sublime Text 等,用過但如今已經不會了。git

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
}

2、要開始了

1. yarn 初始化生成 package.json

image.png

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.js
module.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.js
module.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.js
typings
node_modules
# .prettierignore

*.min.js
/node_modules
/dist
# OS
.DS_Store
.idea
.editorconfig
.npmrc
package-lock.json
# Ignored suffix
*.log
*.md
*.svg
*.png
*ignore
## Built-files
.cache
dist
5. 添加 .editorconfig 配置文件

它是用來抹平不一樣編輯器之間的差別的。一樣放置在項目根目錄下。

# .editorconfig
# http://editorconfig.org
# https://github.com/editorconfig/editorconfig/wiki/EditorConfig-Properties


# 根目錄的配置文件,編輯器會由當前目錄向上查找,若是找到 `roor = true` 的文件,則再也不查找
root = true

# 匹配全部的文件
[*]
# 縮進風格:space
indent_style = space
# 縮進大小 2
indent_size = 2
# 換行符 lf
end_of_line = lf
# 字符集 utf-8
charset = 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"
  }
}

3、你覺得完了?

往下看以前,有必要說明一下:

接下來涉及 Gulp.js 內容,是爲了讓 Prettier 處理 Gulp.js 轉換出來的 css,以達到最終 Prettier 格式化處理 wxss 的目的。

可是上述方式我確實走了一些彎路,其實經過 Prettier Configuration Overrides 配置是能夠指定 .wxss 等擴展名文件使用指定的解析器的。換句話說就是,咱們能夠在處理 .wxss 文件時使用 CSS 解析器去處理它就行了。(具體看系列文章之結局篇

但個人建議是將前面兩篇看完,再看結局篇。

不不不,本文我最想分享的是下面這個,前面的內容都比較簡單,不少人都懂了。

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 不太熟悉了,點擊這裏瞭解一下。

4、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 與方法說明,主要參考自官方文檔與無雙的一篇文章

5、開始配置

首先,安裝 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.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
}

經過如下方式調用就行了

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

執行命令,咱們看到以下結果,說明配置成功了。
🎉

6、Git-Hooks

上面已經實現了對 wxssacss 擴展名的文件進行一鍵格式化了。

還能夠「更懶」一些,利用 git-hooks 咱們可實如今 commit 以前,對項目進行 ESLint、Prettier 檢測和格式化,一旦出現錯誤,將中止 commit 操做。

因爲本文篇幅已經很長了,因此咱們放到下一篇繼續寫...

7、插個題外話

因爲本項目的 npm 包僅用於代碼檢查與格式化,並未參與頁面代碼邏輯中。因此我在小程序本地項目配置文件中添加上打包配置選項

packOptions 用以配置項目在打包過程當中的選項。打包是預覽、上傳時對項目進行的必須步驟。

目前能夠指定 packOptions.ignore 字段,用以配置打包時對符合指定規則的文件或文件夾進行忽略,以跳過打包的過程,這些文件或文件夾將不會出如今預覽或上傳的結果內。

*須要注意的是支付寶小程序,在編寫本文時還未支持相似 ignore 選項。

// project.config.js
{
  "packOptions": {
    "ignore": [
      {
        "type": "regexp",
        "test": "\\.md$"
      },
      {
        "type": "folder",
        "test": "node_modules"
      }
    ]
  }
}
相關文章
相關標籤/搜索