美文网首页规范指南
使Prettier一键格式化WXSS(上集)

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

作者: 越前君 | 来源:发表于2020-09-10 01:05 被阅读0次

    本文将会结合 ESLint、Prettier、husky、lint-stage 等工具使得项目一键化操作,减少在格式化、代码检查等操作上浪费时间,因为大前端真的太多东西学了,不学会“偷懒”的话,我们就要落后更多了。

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

    分为三篇文章介绍:

    扩展篇

    最近在做公司部门前端项目由 SVN 迁移 Git 的事情,由于历史代码在此之前并没有引入类似 ESLintPrettier 的代码检查或者格式约束等工具。

    目前部门仅剩我一人维护这十几个小程序、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
    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"
      }
    }
    

    三、你以为完了?

    往下看之前,有必要说明一下:

    接下来涉及 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 不太熟悉了,点击这里了解一下。

    四、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.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"
      }
    }
    

    执行命令,我们看到如下结果,说明配置成功了。


    六、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"
          }
        ]
      }
    }
    

    相关文章

      网友评论

        本文标题:使Prettier一键格式化WXSS(上集)

        本文链接:https://www.haomeiwen.com/subject/lktuektx.html