1.一次「看似很小,其实很烦」的问题
事情是这样的,一天我在帮同事 rebase 分支,刚解决完一个冲突,又来一个冲突;
再一看冲突内容,我直接愣住了:
- import axios from 'axios';
- import { getUserInfo } from '@/api/user';
- import Header from '@/components/Header.vue';
+ import Header from '@/components/Header.vue';
+ import axios from 'axios';
+ import { getUserInfo } from '@/api/user';
逻辑没变,代码没变,只是 import 顺序不一样。
我当场沉默了 3 秒,然后心里冒出一句话:
“这不是代码问题,这是人类问题。”
在我们团队里:
- 有人喜欢 先写业务,再慢慢补 import
- 有人喜欢 外部库放最上面
- 有人把
@/components放最前 - 有人一股脑全丢进去,IDE 自动排序,爱咋咋地
结果就是—— 代码能跑,但 Git 天天冲突。
2.问题本质:import 顺序,真的是“个人习惯”吗?
刚开始大家的态度是:“不就是 import 顺序吗?有必要搞这么复杂?”
但当你换个角度看:
- import 本身 没有逻辑依赖
- 却直接影响:
- Git diff
- merge 冲突
- code review 体验
- 新人阅读成本
它本质上是一个团队规范问题,而不是个人喜好问题。
所以我的目标很明确: 让 import 顺序“不可争论”,而不是“约定俗成”。
3. 解决方案:eslint-plugin-import
我选择的第一个方案是: 用 ESLint 强制约束 import 顺序。
按照 require() / import 语句的顺序执行一个惯例将groups选项设置为以下分组时,顺序如下所示:
(1)常见分组说明👇 配置文档
| 分组名 | 含义 | 示例 |
|---|---|---|
builtin | Node 内置模块 | fs、path |
external | 外部依赖 | vue、axios |
internal | 项目内部别名 | @/utils |
parent | 父级目录 | ../utils |
sibling | 同级文件 | ./bar.vue |
index | 当前目录 index | ./ |
object | import log = console.log | |
type | TS 类型 | import type { User } |
(2)安装插件
npm install eslint-plugin-import -D
(3)引入插件
// .eslintrc.js
module.exports = {
plugins: ['import'],
rules: {
'import/order': [
'error',
{
groups: [
'builtin', // Node 内置模块
'external', // 第三方库
'internal', // 项目内部(@/)
'parent', // 父级目录
'sibling', // 同级文件
'index', // 当前目录index文件
'object',
'type'
],
pathGroups: [
{
pattern: 'vue',
group: 'external',
position: 'before',
},
{
pattern: '@/api/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/assets/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/components/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/composables/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/constant',
group: 'internal',
position: 'before',
},
{
pattern: '@/router/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/stores/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/utils/**',
group: 'internal',
position: 'before',
},
{
pattern: '@/views/**',
group: 'internal',
position: 'before',
},
],
pathGroupsExcludedImportTypes: ['type'],
newlines-between: 'always',
alphabetize: {
order: 'asc',
caseInsensitive: true,
}
}
],
}
}
import/order 这个规则,核心作用就一句话:不同“来源”的 import,必须按固定分组和顺序书写
(4)这套规则会强制你写成这样
import { ref } from 'vue';
import debounce from 'lodash/debounce';
import { getUserInfo } from '@/api/user';
import Header from '@/components/Header.vue';
import useUser from '@/composables/useUser';
import { YES_NO } './constant';
import BaseInfoForm from './BaseInfoForm.vue';
好处立刻显现:
- 所有人 import 顺序完全一致
- Git 冲突明显减少
- Code Review 不再盯着 import 找茬
4. 我又发现了 eslint-plugin-simple-import-sort
用了一段时间后,我又发现了另一个插件:eslint-plugin-simple-import-sort
我第一反应是:“这玩意和 import/order 有啥区别?”
一句话总结:
它不讲“分组语义”,只讲“排序规则”,而且可以自动修复
特点非常鲜明:
- ✅ 自动排序
- ✅ 规则更简单
- ❌ 语义不如 import/order 强
(1) 安装 & 使用
npm install eslint-plugin-simple-import-sort -D
plugins: ['simple-import-sort'],
rules: {
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
}
(2)自定义分组示例(实战)
// .eslintrc.js
module.exports = {
rules:{
'simple-import-sort/imports': [
'error',
{
groups: [
// 1. Node 内置
['^node:'],
// 2. 第三方库
['^vue', '^@?\w'],
// 3. 内部模块
['^@/components'],
['^@/composables'],
['^@/utils'],
['^@/api'],
['^@/store'],
['^@/router'],
['^@/views'],
// 4. 相对路径
['^\.'],
],
}
]
}
}
它会直接帮你 自动修复成统一顺序。
5.后来发生了什么?
这套规则上线后,有同事在群里说了一句:
“我终于不用再因为 import 冲突 rebase 半小时了。”
那一刻我意识到:真正的价值,不是炫技,而是让所有人更轻松。