文章目录
- 前言
- 场景设定:维护代码分层,禁止“跨级调用”
- 实现步骤:从零到一,创建你的第一条自定义规则
- **第 1 步:创建规则文件**
- **第 2 步:在 `eslint.config.mjs` 中注册并启用你的规则**
- 验证成果
前言
设计一个非常真实、非常有价值的自定义规则场景,这个场景在开发中都可能遇到的:架构约束规则。
场景设定:维护代码分层,禁止“跨级调用”
背景:
在一个良好分层的项目中,我们通常会把代码分成不同的层次。假设你的 uni-app
项目遵循以下结构:
src/services/
:存放所有与后端 API 交互的逻辑(比如userService.ts
,productService.ts
)。这些是“数据服务层”。src/pages/
:存放所有的页面(.vue
文件)。这些是“视图层”。src/utils/
:存放通用的工具函数。
团队规定(我们的架构约束):
为了保持代码的清晰和可维护性,团队规定 “视图层 (pages
)” 不允许直接调用 “数据服务层 (services
)”。
- 错误的做法:在
src/pages/my/index.vue
中直接import { getUserInfo } from '@/services/userService';
- 正确的做法:页面应该通过一个统一的、更高层的逻辑单元(比如 Vuex/Pinia 的 actions,或者一个专门的
controller
层)来获取数据,而不是直接触碰底层的 service。
目标:
我们要创建一个自定义 ESLint 规则,叫做 no-service-import-in-pages
。当有开发者试图在 src/pages/
目录下的任何文件中导入 src/services/
里的模块时,ESLint 应该立刻用红色下划线报错,并给出清晰的提示:“页面组件不允许直接导入 service,请通过状态管理层调用。”
实现步骤:从零到一,创建你的第一条自定义规则
这个过程分为两步:1. 编写规则,2. 注册规则。
第 1 步:创建规则文件
-
在你的项目根目录(和
package.json
同级)创建一个新文件夹,命名为eslint-rules
。 -
在这个文件夹里,创建一个新文件,命名为
no-service-import-in-pages.js
。 -
将以下代码粘贴到
no-service-import-in-pages.js
中:/*** @fileoverview Rule to prevent importing from the services layer directly into page components.* @author Your Name*/ "use strict";//------------------------------------------------------------------------------ // Rule Definition //------------------------------------------------------------------------------module.exports = {// meta: 包含了规则的元数据meta: {type: "problem", // 这表示规则将发现一个代码问题docs: {description: "Disallow direct imports from the services layer in page components",category: "Best Practices",recommended: true,},fixable: null, // 这个规则不可自动修复schema: [], // 这个规则没有额外的配置选项messages: {noServiceImport: "页面组件不允许直接导入 service,请通过状态管理层调用。",}},// create: 返回一个对象,这个对象包含了遍历 AST 时要访问的节点create(context) {// 获取当前正在被检查的文件的绝对路径const filename = context.getFilename();// 如果文件路径不包含 /pages/,那么这个规则直接跳过,不进行任何检查if (!filename.includes("/src/pages/")) {return {};}// 如果文件在 pages 目录下,我们返回一个访问者对象return {// 'ImportDeclaration' 是 AST 中代表 'import ... from ...' 语句的节点类型ImportDeclaration(node) {// node.source.value 获取的是 from 后面的字符串,比如 '@/services/userService'const importSource = node.source.value;// 检查这个导入路径是否包含了 'services'if (importSource && importSource.includes("services")) {// 如果包含了,就报告一个错误context.report({node: node, // 在这个 import 语句节点上报告错误messageId: "noServiceImport", // 使用 meta.messages 中定义好的错误信息});}},};}, };
第 2 步:在 eslint.config.mjs
中注册并启用你的规则
现在我们需要告诉 ESLint:“嘿,我写了一个新规则,给你用!”
打开 eslint.config.mjs
,我们需要修改 “3. A main configuration object” 这个部分,添加一个新的 plugins
字段,并启用我们的规则。
// ... 其他 import 语句 ...
// 导入我们自己的规则
import noServiceImportInPages from './eslint-rules/no-service-import-in-pages.js';export default [// ... 其他配置 ...// 3. A main configuration object for our custom settings{languageOptions: {// ... globals ...},plugins: {// Make plugins available for all files'@typescript-eslint': tseslint.plugin,vue: vuePlugin,// 在这里注册我们的自定义规则插件'custom-rules': {rules: {'no-service-import-in-pages': noServiceImportInPages,},},},rules: {// ... 其他规则 ...// 在这里启用我们的自定义规则,并设置为 error 级别'custom-rules/no-service-import-in-pages': 'error',},},// ... 其他配置 ...
];
验证成果
做完以上修改后,请重启 VSCode!
现在,去任何一个位于 src/pages/
目录下的 .vue
文件,在 <script>
标签里尝试写下:
import { someFunction } from '@/services/api';
你会立刻看到,这行代码被画上了红色波浪线,当你把鼠标悬停在上面时,会显示我们自定义的错误信息:“页面组件不允许直接导入 service,请通过状态管理层调用。”
而在 src/utils
或其他非 pages
目录的文件中进行同样的导入,则不会有任何报错。
就这样成功地创建并应用了一条非常有价值的、用于维护项目架构的自定义 ESLint 规则!