Flutter 导入:相对路径还是包?

Flutter imports : relative path or package?

在 Flutter 中,为了在我们自己的包的 lib 目录中导入库,我们应该使用相对导入

import 'foo.dart'

还是包导入?

import 'package:my_app/lib/src/foo.dart'

Dart guidelines提倡使用相对导入:

PREFER relative paths when importing libraries within your own package’s lib directory.

Provider package says to always use packages imports :

  • Always use package imports. Ex: import 'package:my_app/my_code.dart';

除了简洁还有什么区别吗?为什么包导入会减少相对导入的错误?

提供商不再需要导入包。

这是一个旧的 Dart 错误的解决方法:

TL;DR,通过混合相对和绝对导入,有时 Dart 创建了 class 定义的副本。

这导致了荒谬的行:

import 'package:myApp/test.dart' as absolute;
import './test.dart' as relative;

void main() {
  print(relative.Test().runtimeType == absolute.Test().runtimeType); // false
}

由于 provider 依赖 runtimeType 来解析对象,因此此错误导致 provider 在某些情况下无法获取对象。

从相同的Dart guidelines,进一步向下他们给出了相对进口的原因:

There is no profound reason to prefer the former—it’s just shorter, and we want to be consistent.

就个人而言,我更喜欢绝对方法,尽管它更冗长,因为这意味着当我从不同的 dart 文件(在其他文件夹中)导入时,我不必弄清楚文件的位置导入的是,相对于当前文件。虚构的例子:

我有两个 dart 文件,在不同的文件夹级别,需要导入 themes/style.dart:

一个是widgets/animation/box_anim.dart,相对路径导入是:

import '../../themes/style.dart';

另一种是screens/home_screen.dart相对导入:

import '../themes/style.dart';

这可能会让人感到困惑,所以我发现最好在两个文件中都使用绝对值,并保持一致:

import 'package:myapp/themes/style.dart';

并且始终坚持这条规则。所以,基本上,无论您使用什么方法 - 一致性是关键!

Linter for Dart package, also has something to say about this,但更多的是不要混合在'/lib'文件夹中:

DO avoid relative imports for files in lib/.

When mixing relative and absolute imports it's possible to create confusion where the same member gets imported in two different ways. An easy way to avoid that is to ensure you have no relative imports that include lib/ in their paths.

TLDR;选择你喜欢的,注意prefer_relative_imports is recommended in official Effective Dart guide

首先,如所述,Provider不再推荐包导入。

Dart linter 提供了一个规则列表,包括一些预定义的规则集:

导入规则

关于导入实际上有两个以上的相反规则:

  • avoid_relative_lib_imports,在 pedanticlints 规则集中启用,基本上建议避免导入 'lib'在他们的道路上。

以下两个是你提到的那个:

我应该选择哪一个?

选择你想要的规则!它不会导致任何性能问题,并且没有规则可以减少其他规则的错误。只需选择一个,让你的导入在你的所有项目中保持一致,感谢 Dart linter。

我个人更喜欢使用 prefer_relative_imports, as it is recommended by Dart team, with this VSCode extension 自动修复和排序我的导入。

这个问题已经有了很好的答案,但我想提一下我在 单元测试 [=51] 中遇到的一个 非常烦人和 hard-to-find 的问题 =] 由相对导入引起。

exception-catching expect 块的 expect 失败指示器

expect(
  () => myFunction,
  throwsA(isA<InvalidUserDataException>())
);

显示 actual 结果与 expected 结果完全相同,并且失败原因的指示为零。

在大规模 trial-and-error 之后,问题是因为预期的 InvalidUserDataException(custom-made class)正在以相对格式与包格式导入测试文件.

为了找到这个,我必须比较 side-by-side、line-by-line、call-by-call 这个测试文件和另一个使用完全相同的异常预期的测试文件(幸运的是,我们有这个), 只是偶然, 我碰巧滚动到这个文件的导入顶部, 看到蓝色下划线说 prefer relative imports to /lib directory.

不,他们不是首选;它们是必要的,因为当我将其更改为 PACKAGE(绝对)导入时,一切突然开始工作。

我从中学到的是:对测试文件(lib 目录之外的文件)使用绝对导入

  • 例如src/test/main_test.dart 里面
    • 不要:使用import '../lib/main.dart'
    • DO: 使用package:my_flutter_app/main.dart

也许其他人已经知道这一点,但我不知道,而且我在网上找不到任何关于这个问题的搜索,所以我想我会分享我的经验,可能会帮助那些被困在这个问题上的人。

有人知道为什么会这样吗?

编辑:就上下文而言,这发生在将 Flutter 2.1.4(稳定版)与 Sound Null Safety

一起使用时