js 几种导入依赖排序 import sort

前言

现在前端工程化一般都会加上 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 的话,也可以考虑一用。