文章目录
- 前言
-
-
- 场景设定:维护代码分层,禁止"跨级调用"
- 实现步骤:从零到一,创建你的第一条自定义规则
-
- [**第 1 步:创建规则文件**](#第 1 步:创建规则文件)
- [**第 2 步:在 `eslint.config.mjs` 中注册并启用你的规则**](#第 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
中:javascript/** * @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
字段,并启用我们的规则。
javascript
// ... 其他 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>
标签里尝试写下:
typescript
import { someFunction } from '@/services/api';
你会立刻看到,这行代码被画上了红色波浪线,当你把鼠标悬停在上面时,会显示我们自定义的错误信息:"页面组件不允许直接导入 service,请通过状态管理层调用。"
而在 src/utils
或其他非 pages
目录的文件中进行同样的导入,则不会有任何报错。
就这样成功地创建并应用了一条非常有价值的、用于维护项目架构的自定义 ESLint 规则!