微信小程序ESLint插件eslint-plugin-wxml使用指南

1,942 阅读7分钟

〇. 概述

随着微信开发者工具逐渐完善构建npm包的能力以及对VSCode扩展的支持, 越来越多的工程化工具来到了微信小程序生态, 其中就包括我们熟悉的代码格式化工具ESLint, 以及对.wxml进行格式化的eslint-plugin-wxml插件

本文档是根据插件的官方文档进行的翻译和解释, 并添加自己在实际项目中的踩坑和推荐配置

此文档更新时间: 2023/3/10

对应版本: V 0.7.5

插件官网: eslint-plugin-wxml.js.org/

一. 如何使用

支持VSCode微信开发者工具, 配置方法相同

1. 在编辑器中安装最新版本ESLint扩展

2. 安装相关依赖:

npm install --save-dev eslint eslint-plugin-wxml @babel/core @babel/eslint-parser @wxml/parser

# OR

pnpm add -D eslint eslint-plugin-wxml @babel/core @babel/eslint-parser @wxml/parser

3. 在项目根目录新建.vscode目录以及该目录下的settings.json文件

4. 在settings.json文件的eslint.validate配置项内添加wxml:

{
  "eslint.validate": [...其他语言, "wxml"],
}

当然, 你也可以配置到全局的settings.json里, 不过为了团队成员的统一, 建议将这些配置到项目的settings.json里~

还有, 记得注释掉项目.gitignore里的.vscode/*

5. 因为ESLint中对wxml的配置和原始的配置需要分隔开, 所以需要我们对之前的.eslintrc.js文件进行一点改造:

module.exports = {
  root: true,
  overrides: [{
    files: ['*.wxml'],
    rules: {
      // 针对wxml的校验规则
      'wxml/no-dot-this-in-wx-key': 'error',
      ...
    },
    plugins: ['wxml'],
    processor: 'wxml/wxml',
    parser: '@wxml/parser'
  },
  // 原来的配置移到这里
  {
    files: ['*.js', '*.ts', '*.tsx', '*.jsx'],
    parser: '@babel/eslint-parser',
    rules: {
      'array-bracket-spacing': [2, 'never'],
      ...
    },
    ...
  }
 ]
}

6. 如果需要从命令运行ESLint, 需要在项目package.json添加相关命令

"scripts": {
    "lint": "eslint --fix --ext .js,.wxml pages package utils components"
  },

默认情况下ESLint仅针对.js文件, 所以需要--ext选项指定要格式化的文件/目录, 此处需根据项目实际结构配置~

7. 理论上完成上述配置后eslint-plugin-wxml就应该生效了, 如果不生效请检查配置是否正确或重启编辑器试试~

如果还是不生效就点击编辑器底部的ESLint, 查看下插件有没有输出什么错误~

二. 配置说明

wxml/colon-style-event-binding: 强制使用冒号的事件绑定:

已弃用, 请使用wxml/event-binding-style

wxml/empty-tag-self-closing: 强制空标签自闭合:

  • 配置说明: "wxml/empty-tag-self-closing": "error"
<!-- ✓ GOOD -->
<view bind:tap="clickhandler" />
<view />{{interpolation}}</view>
<view />text</view>
<view /><sub /></view>

<!-- ✗ BAD -->
<view bind:tap="clickhandler" ></view>

<view>

</view>

wxml/event-binding-style: 强制事件绑定样式:

  • 配置说明: 须指定第二个参数为"colon""no-colon"
  • 比如: "wxml/event-binding-style": ["error", "no-colon"]
<!-- colon -->
<view bind:tap="clickhandler" />
<view mut-bind:tap="clickhandler" />

<!-- no-colon -->
<view bindtap="clickhandler" />
<view mut-bindtap="clickhandler" />

wxml/forbid-attributes: 配置禁止使用的wxml属性:

  • 配置说明:"wxml/forbid-attributes": [<enabled>, { "forbid": [<string|{ attr: string, message: string }>] }]
{
  "wxml/forbid-attributes": [
    "error",
    {
      "forbid":
      [
        {
          "attr": "className",
          "message": "wxml use class not jsx className"
        }
      ]
    }
  ]
}
<!-- ✓ GOOD -->
<text class="text-center" >{{name}}</div>

<!-- ✗ BAD -->
<text className="text-center" >{{name}}</div>

wxml/forbid-tags: 配置禁止使用的wxml标签:

  • 配置说明:"wxml/forbid-tags": [<enabled>, { "forbid": [<string|{ tag: string, message?: string, disableAttrs?: string[], skipAttrs?: string[] }>] }]
{
  "wxml/forbid-tags": [
    "error",
    {
      "forbid":
      [
        "div",
        "span",
        {
          "tag": "p",
          "message": "please use <text />"
        }
      ]
    }
  ]
}
<!-- ✓ GOOD -->
<view />text</view>
<view /><sub /></view>

<!-- ✗ BAD -->
<div>{{name}}</div>
<span>{{title}}</span>
<!-- 报错: please use <text />  -->
<p>{{title}}</p>

wxml/max-depth: 设置wxml组件的最大深度:

  • 配置说明: "wxml/max-depth": [<enabled>, number]

wxml/max-len: 设置单行代码最大宽度:

  • 配置说明: "wxml/max-len": [<enabled>, <number | { code: number, ignoreWhitespace?: boolean }>]

wxml/max-lines: 设置每个文件的最大行数:

  • 配置说明:"wxml/max-lines": [<enabled>, <number | { max: number, skipBlankLines?: boolean }>]

wxml/no-const-and-let-in-wxs: 禁止在wxs内使用letconst:

  • 配置说明: "wxml/no-const-and-let-in-wxs": "error"

wxml/no-dot-this-in-wx-key: 禁止使用*this做为wx:key:

wx:key可以使用保留关键字*this,代表在for循环中的item本身,这种表示需要 item 本身是一个唯一的字符串或者数字

参考: developers.weixin.qq.com/miniprogram…

  • 配置说明: "wxml/no-dot-this-in-wx-key": "error"

wxml/no-duplicate-attributes: 禁止使用重复的属性:

  • 配置说明: "wxml/no-duplicate-attributes": "error"

wxml/no-dynamic-wx-key: 禁止使用动态wx:key:

  • 配置说明: "wxml/no-dynamic-wx-key": "error"
<!-- ✓ GOOD -->
<view
 wx:for="{{goodsList}}"
 wx:key="goodsId"
>
 {{item.name}}
</view>

<!-- ✗ BAD -->
<view
 wx:for="{{goodsList}}"
 wx:key="id-{{goodsId}}"
>
 {{item.name}}
</view>

wxml/no-inconsistent-tagname: 禁止不配对的标签名:

  • 配置说明: "wxml/no-inconsistent-tagname": "error"
<!-- ✓ GOOD -->
<view
 wx:for="{{goodsList}}"
 wx:key="goodsId"
>
 {{item.name}}
</view>
<same-tag-name>
    {{"tag name must be equal"}}
</same-tag-name>

<!-- ✗ BAD -->
<view
 wx:for="{{goodsList}}"
 wx:key="id-{{goodsId}}"
>
 {{item.name}}
</viw>

wxml/no-index-in-wx-key: 禁止使用index做为wx:key:

  • 配置说明: "wxml/no-index-in-wx-key": "error"

wxml/no-inline-wxs: 禁止使用内联wxs:

  • 配置说明: "wxml/no-inline-wxs": "error"
<!-- ✓ GOOD -->
<wxs module="util" src="../../../util.wxs" />

<!-- ✗ BAD -->
<wxs module="util" >
  function util () {
    // balabala
  }
  module.exports = {
    util: util
  }
</wxs>

wxml/no-unexpected-string-bool: 禁止使用布尔字符串:

关键字需要在双引号之内 <checkbox checked="{{false}}"> </checkbox> 不要直接写 checked="false",其计算结果是一个字符串,转成boolean类型后代表真值。

参考: developers.weixin.qq.com/miniprogram…

  • 配置说明: "wxml/no-unexpected-string-bool": "error"
<!-- ✓ GOOD -->
<checkbox checked="{{false}}"> </checkbox>
<popup showMask />

<!-- ✗ BAD -->
<checkbox checked="false"> </checkbox>
<popup showMask="true" />

wxml/no-unnecessary-block: 禁止不合适的block标签使用

  • 配置说明: "wxml/no-unnecessary-block": "error"
<!-- ✓ GOOD -->
<block wx:if="{{show}}"> {{title}}</block>
<block wx:if="{{show}}">
  <multi-children />
  <view>
    <sub-view />
  </view>
</block>
<!-- 官方建议使用 <block /> 来包裹循环列表 -->
<block wx:if="{{showList}}">
  <view wx:for="{{list}}"> {{item.name}}</view>
</block>

<!-- ✗ BAD -->
<block wx:for="{{list}}" wx:key="id">
  <goods name="{{item.name}}" img="{{item.imgUrl}}" />
</block>
<block wx:if="{{show}}"> </block>
<block wx:if="{{show}}">
  <view>
    <sub-view />
  </view>
</block>

wxml/no-vue-directive: 禁止在微信小程序里错误的使用vuejs指令:

醒醒, 这是微信小程序, 不是vue😵

  • 配置说明: "wxml/no-vue-directive": "error"
<!-- ✓ GOOD -->
<view wx:if="{{show}}"> {{title}}</view>

<!-- ✗ BAD -->
<view v-if="{{show}}"> {{title}}</view>
<view v-else-if="{{hide}}"> {{title}}</view>

wxml/no-wx-for-with-wx-if: 禁止wx:forwx:if|wx:elseif|wx:else在同一个标签使用

官方禁止wx:forwx:if|wx:elseif|wx:else使用在同一个标签上, 就像v-forv-if不应该用在同一个标签上一样

  • 配置说明: "wxml/no-wx-for-with-wx-if": "error"
<!-- ✓ GOOD -->
<view wx:for="{{list}}"> {{item.name}}</view>
<!-- 官方建议使用 <block /> 来包裹循环列表 -->
<block wx:if="{{showList}}">
  <view wx:for="{{list}}"> {{item.name}}</view>
</block>

<!-- ✗ BAD -->
<view wx:if="{{showList}}" wx:for="{{list}}"> {{item.name}}</view>
<view wx:elif="{{showOtherList}}" wx:for="{{otherList}}"> {{item.name}}</view>
<view wx:else wx:for="{{lastList}}"> {{item.name}}</view>

wxml/no-wx-for-with-wx-else:禁止wx:forwx:else在同一个标签使用

亲测可以用wxml/no-wx-for-with-wx-if代替此命令

官方文档说wxml/no-wx-for-with-wx-if已弃用, 请使用wxml/no-wx-for-with-wx-else代替, 他可能说反了(也可能我没理解作者的意思🤔)

wxml/no-wx-if-string: 禁止wx:if使用字符串:

因为任何非空字符串在js里用作判断时都会当作true处理

  • 配置说明: "wxml/no-wx-if-string": "error"
<!-- ✓ GOOD -->
<view wx:if="{{user}}"> {{user.name}}</view>
<view wx:elif="{{show}}">show this view</view>


<!-- ✗ BAD -->
<!-- 这里多了个空格, 所以变成了true -->
<view wx:if="{{showList}} "> I will be always show on the page </view>
<view wx:if="string"> I will be always show on the page </view>
<view wx:if="{{showSwitch}}-string"> I will be always show on the page </view>
<!-- wx:elif 同理 -->
<view wx:elif="string"> I will be always show on the page </view>

wxml/omit-bool-attributes: 禁止可省略的布尔属性:

<a attr=true />等价于<a sttr />

  • 配置说明: "wxml/omit-bool-attributes": "error"
<!-- ✓ GOOD -->
<cart showBadge />
<swiper autoplay />
<virtual-list hideSpinner="{{false}}" />


<!-- ✗ BAD -->
<cart showBadge="{{true}}" />
<swiper autoplay="{{true}}" />

wxml/quotes: 设置引号风格:

  • 配置说明: 须指定第二个参数为"single"或"double"
  • 比如: "wxml/quotes": ["error", "single"]

wxml/report-interpolation-error: 允许提示插值错误:

  • 配置说明: "wxml/report-interpolation-error": "error"

wxml/report-wxml-syntax-error: 允许提示wxml语法错误:

  • 配置说明: "wxml/report-wxml-syntax-error": "error"

wxml/report-wxs-syntax-error: 允许提示内联wxs里的js语法错误:

  • 配置说明: "wxml/report-wxs-syntax-error": "error"

wxml/required-attributes: 设置必要属性:

  • 配置说明: "wxml/required-attributes": [<enabled>, <{ tag: string, attrs: <string | { key: string, value: string }>[] }>] }]

wxml/required-root-tag: 设置必要根标签:

  • 配置说明: "wxml/required-root-tag": [<enabled>, string]

wxml/required-tags: 设置wxml必须的标签:

  • 配置说明: "wxml/required-tags": [<enabled>, ...string[]]

wxml/wx-key: wx:for循环时必须声明wx-key:

如果列表中项目的位置会动态改变或者有新的项目添加到列表中,并且希望列表中的项目保持自己的特征和状态(如input中的输入内容,switch的选中状态),需要使用wx:key来指定列表中项目的唯一的标识符

参考: developers.weixin.qq.com/miniprogram…

  • 配置说明: "wxml/wx-key": "error"

wxml/wxs-module-prop: 允许提示wxs标签module属性相关检查:

  • 配置说明: "wxml/wxs-module-prop": "error"

wxml/wxs-must-be-top-level: 强制要求wxs必须为顶层标签:

  • 配置说明: "wxml/wxs-must-be-top-level": "error"

三. 配置建议

这个是我在实际项目中的配置, 供各位参考~

rules: {
      // https://eslint-plugin-wxml.js.org/
      // 'wxml/max-len': ['error', 80], // 单行最大长度
      'wxml/forbid-tags': [ // 禁止使用非小程序标签
        'error',
        {
          'forbid':
          [
            'p',
            {
              'tag': 'div',
              'message': 'please use <view />'
            },
            {
              'tag': 'span',
              'message': 'please use <text />'
            },
            {
              'tag': 'img',
              'message': 'please use <image />'
            }
          ]
        }
      ],
      'wxml/no-dot-this-in-wx-key': 'error', // 禁止使用*this作为wx:key
      'wxml/no-duplicate-attributes': 'error', // 禁止使用重复的属性
      'wxml/no-dynamic-wx-key': 'error', // 禁止使用动态wx:key
      'wxml/no-inconsistent-tagname': 'error', // 禁止不配对的标签名
      'wxml/no-unexpected-string-bool': 'error', // 禁止使用布尔字符串
      'wxml/no-vue-directive': 'error', // 禁止使用vuejs指令
      'wxml/no-wx-for-with-wx-if': 'error', // 禁止wx:for和wx:if等在同标签使用
      'wxml/no-wx-if-string': 'error', // 禁止wx:if使用字符串
      'wxml/omit-bool-attributes': 'error', // 禁止可省略的布尔属性
      'wxml/quotes': ['error', 'double'], // 单引号
      'wxml/report-interpolation-error': 'error', // 允许提示插值错误
      'wxml/report-wxml-syntax-error': 'error', // 允许提示wxml语法错误
      'wxml/wx-key': 'error' // 必须使用wx-key
    },