前言
现在前端工程化一般都会加上 eslint + prettier (从零搭建前端工程(下))做格式化,为了团队风格,美观,还有为了减少不必要的冲突,比如 import 文件的顺序。合并代码的时候,冲突无可避免,但是能尽量减少最好。能够统一排序,添加的文件的改动也比较一目了然。相应的工具其实也不少,大同小异,选择适合自己的而用之。
一、eslint 自带的 sort-imports
《sort-imports》。不看了,自定义差,还几乎不能 auto fix。
二、eslint 插件 eslint-plugin-import
《eslint-plugin-import》。支持自定义配置,支持 auto fix,后面说的都是,不然没啥意义了。示例代码:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 'latest',
},
plugins: ['import'],
rules: {
'import/order': [
'error',
{
groups: [
'index',
'builtin',
'external',
'internal',
'object',
'type',
'unknown',
['parent', 'sibling'],
],
pathGroups: [
{
pattern: 'react*',
group: 'builtin',
position: 'after',
},
{
pattern: '@/*',
group: 'internal',
position: 'after',
},
{
pattern: '@*/**',
group: 'internal',
position: 'before',
},
],
pathGroupsExcludedImportTypes: [],
distinctGroup: false,
'newlines-between': 'always',
alphabetize: {
order: 'asc',
orderImportKind: 'asc',
caseInsensitive: true,
},
warnOnUnassignedImports: false,
},
],
},
};
大部分配置都很好理解,就是这个 pathGroupsExcludedImportTypes
实在不明所以。
Issue#2156 有个老哥给出答案:
想要 pathGroups
的配置生效,那么它原本所属的类型就不要出现在 pathGroupsExcludedImportTypes
react* 属于 external
,而这个属性的默认值是 [‘buildin’, ‘external’],所以配置了 react* 的话,就要重定义这个值。 所以示例代码是空数组。
老哥又提到:But now, it has been applied exactly the opposite way.
囧,确实我理解反了,我以为是要使其生效才要写在里面。而且理解成是 pattern 定义的分类是属于下面 group 的,也就是一开始以为是指定 react* 属于 builtin。而其实不是,而是说 react* 在 builtin 类型的相对位置。= =!
三、eslint 插件 eslint-plugin-simple-import-sort
《eslint-plugin-simple-import-sort》。如其名,为 simple 而生,配置确实比上面的 eslint-plugin-import 好懂,作者也简单列举了对比:《How is this rule different from import/order》。
其实对我最大的吸引的还是对于 type 类型的处理,这里有多个例子:examples
,可以配置 type 导入是在全部最上(下)面,或者在每个分组的最上(下)面。当然注意引入的时候,type 关键字要在外面,比如:import type { Kind } from ‘foo’; 而不是 import { type Kind } from ‘foo’;
示例代码,拿 groups.type-imports-last-in-each-group.ts
改的:
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module',
ecmaVersion: 'latest',
},
plugins: ['simple-import-sort', 'import'],
rules: {
'simple-import-sort/imports': [
'error',
{
groups: [
// 副作用,就是单纯 import 没 from
['^\\u0000'],
// react 全家桶
['^react'],
// react 内置,web 项目应该没有
['^node:', '^node:.*\\u0000$'],
// mono 包,@foo
['^@?\\w', '^@?\\w.*\\u0000$'],
// 自定义别名的包,@/bar
['(?<!\\u0000)$', '(?<=\\u0000)$'],
// 相对路径
['^\\..*\\u0000$', '^\\.'],
// 样式引入
['^.+\\.(s?css|less)$'],
],
},
],
},
};
不过,有些匹配不是很明白。。。不深究了。
四、prettier 插件 @trivago/prettier-plugin-sort-imports
《@trivago/prettier-plugin-sort-imports》。这个也很简单好用,基本满足需求,官网示例也简单。
五、prettier 插件 @ianvs/prettier-plugin-sort-imports
《@ianvs/prettier-plugin-sort-imports》。一开始搜的时候,搜到这两个名字相像的,看了一下挑了个多使用的,而且这个自己也说了是基于上面那个扩展的。所以没细看就选了原本版本的也就是上面的。结果后面细看还增强了功能,而且是看起来确实还挺实用的。我觉得最吸引我的是对于 type 关键字的排序。
示例代码:
/** @type {import("prettier").Config} */
module.exports = {
singleQuote: true,
semi: true,
plugins: ['@ianvs/prettier-plugin-sort-imports'],
importOrder: [
'^react',
'',
'<TYPES>',
'<TYPES>^[.]',
'',
'<THIRD_PARTY_MODULES>',
'^@(.*)',
'^@/(.*)',
'',
'',
'^[.]((?!.s?css$|.less$).)*$',
'',
'(.s?css|.less)$',
],
importOrderParserPlugins: ['typescript', 'jsx', 'decorators-legacy'],
importOrderTypeScriptVersion: '5.0.0',
};
有趣的是,直接用空字符串
作为换行标志,也算是这几个里面最灵活的。不过它这里是把所有 type 关键字统一处理,就是全部放在一个地方,我会比较倾向于放在每个 group 的最后面。当然这样也没问题,个人习惯。
还有,这里也说了,对于副作用的导入,不做处理,因为认为副作用的顺序是会影响加载功能的。我也觉得不处理问题不大,毕竟副作用的引入一般比较少,自己注意就行。
总结
个人觉得 eslint-plugin-simple-import-sort 满足使用,我会倾向于用这个。然后 @ianvs/prettier-plugin-sort-imports 这个也很不错,也可以。
另外
发现 prettier 有针对 tailwindcss 的排序插件《prettier-plugin-tailwindcss》。如果项目有用上 tailwindcss 的话,也可以考虑一用。