〇. 概述
随着微信开发者工具逐渐完善构建npm包的能力以及对VSCode扩展的支持, 越来越多的工程化工具来到了微信小程序生态, 其中就包括我们熟悉的代码格式化工具ESLint, 以及对.wxml进行格式化的eslint-plugin-wxml插件
本文档是根据插件的官方文档进行的翻译和解释, 并添加自己在实际项目中的踩坑和推荐配置
此文档更新时间: 2023/3/10
对应版本: V 0.7.5
一. 如何使用
支持
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内使用let和const:
- 配置说明:
"wxml/no-const-and-let-in-wxs": "error"
wxml/no-dot-this-in-wx-key: 禁止使用*this做为wx:key:
wx:key可以使用保留关键字*this,代表在for循环中的item本身,这种表示需要 item 本身是一个唯一的字符串或者数字
- 配置说明:
"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类型后代表真值。
- 配置说明:
"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:for和wx:if|wx:elseif|wx:else在同一个标签使用
官方禁止
wx:for和wx:if|wx:elseif|wx:else使用在同一个标签上, 就像v-for和v-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:for和wx: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来指定列表中项目的唯一的标识符
- 配置说明:
"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
},