【问题标题】:Relative vs. non-relative module import for custom modules自定义模块的相对与非相对模块导入
【发布时间】:2017-09-11 20:54:27
【问题描述】:

更新[09/12/2017 16:58 EST]

在此问题的底部添加了为什么我不愿将本机支持的非相对导入与我自己的模块一起使用的原因。

更新[09/12/2017 12:58 EST]:

根据要求,我使下面的文件结构反映了我的实际用例。这是一个嵌套视图模块,请求目录树上某处的实用程序模块。


每个请求

在 TypeScript 和 ES6 中,可以通过以下方式导入自定义模块

// Relative
import { numberUtil } from './number_util';
// OR
// Non-relative
import { numberUtil } from 'number_util';

根据 TypeScript 文档 (link),应该:

... 使用 保证维护您自己的模块的相对导入 它们在运行时的相对位置。

... 导入任何文件时使用非相对路径 您的外部依赖项。

我的问题是我的项目结构是这样的:

project/
  |--utils
  |    |--number_util.ts
  |--views
  |    |--article_page
  |         |-- editor_view
  |                |--editor_text_area.ts

当我在 editor_text_area 模块中包含 utils/number_util 时,导入语句如下所示:

import { numberUtil } from './../../../utils/number_util';

这很长且不可读,最糟糕的是,难以维护:每当我需要移动 editor_text_area 时,我将不得不更新这些相对路径,同时我只能使用非相对路径方式

import { numberUtil } from 'utils/number_util';

对于如何最好地进行模块导入以实现最高的可读性和可维护性,是否有人有任何建议?


但是使用非相对方式会带来一个问题(除了官方文档不推荐):如果我安装了一个与我正在导入的模块同名的npm 模块怎么办?在这一点上,它不像上面提到的更丑陋的替代方案那样安全

【问题讨论】:

  • 通常嵌套层次结构太深是架构问题的标志。是什么让它这么深?
  • @loganfsmyth 请查看我更新的代码 sn-p,我包含了一个与我的非常相似的真实用例
  • 之前在应用程序中拥有顶级“views”文件夹,我个人觉得正是这个原因令人沮丧。我选择将editor_view 和其他类似的东西移到顶部。它的名称中已经包含view。将它们全部放在名为view 的文件夹和特定于页面的文件夹中不会提供任何有意义的逻辑。如果您需要特定于页面的逻辑,例如“article_view 上加载了什么”,导入/导出依赖图已经告诉您。
  • 我必须说,我不会完全扁平化您的源层次结构。实际上,我发现在非平凡的项目中进行这种结构化非常有用。只是不要让它变得太深。因此,如果 editor_view 实际上对其他视图也有用,但只是 article_page 需要,您应该将其提升一个级别。

标签: javascript typescript ecmascript-6


【解决方案1】:

根据您的项目工具和结构,您有一些选择。

A) 您可以将部分依赖项发布为独立模块,或许在私有注册表中。然后,您可以使用 npm 安装它们,并像任何其他外部依赖项一样需要它们。

B) 许多模块系统支持某种路径映射。 vue-js webpack template 使用webpackalias feature@ 设置为源代码根。 TypeScript 也支持path mapping。引入该映射后,您可以使用

import { numberUtil } from '@/utils/number_util';

这种方法基本上为您的模块引入了一个私有命名空间。 这是安全的,因为您只能使用名称为 @ 的 npm 模块隐藏 npm 模块,这是一个无效名称,因此不能存在。

对于您的示例,您必须在 compilerOptions 中包含这些条目:

"baseUrl": ".",
"paths": {
    "@/*": ["*"]
}

或者如果您只想从utils 导入模块,您可以将映射更改为"@/*": ["utils/*"] 并使用'@/number_util' 导入。

C) 要考虑的另一件事是改进您的项目结构。根据您的实际项目,在某处应用facade pattern 可能是有意义的。也许inject 依赖于editor_text_area 而不是让它自己导入。

【讨论】:

  • 谢谢!除非我遗漏了一些明显的东西,否则“别名”方法很像我在问题中提到的“非相对”导入。那有什么不同?
  • @benjaminz 根据使用的模块系统的实际解析算法,别名方法可能会影响已安装的 npm 模块。当您使用@ 来引用存储库根目录时,应该不会造成任何问题。但是,我的建议是使用 root-relative 导入,如我的更新中所述。
  • 我尝试了 '/utils/number_util' 方法,但它不起作用,它抱怨找不到模块,但是当我删除前导斜杠时,它工作得很好。您使用了什么compilerOptions 使它起作用?我检查了文档,似乎只有当您执行 import '/utils/number_util 时才支持前导斜杠
  • @benjaminz 我自己试过了,/ 总是解析为实际的文件系统根目录,无论编译器配置如何。抱歉,我不应该依赖另一个 SO 帖子的二手信息。鉴于这些新信息,我建议您使用选项 B。有关详细信息,请参阅我的更新答案。
【解决方案2】:

你可以加"baseUrl": "./src",给你tsconfig.json

那么你可以import * as utils from 'utils'导入./src/utils/index.ts

【讨论】:

    猜你喜欢
    • 2021-08-16
    • 2021-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-01-09
    • 2010-09-21
    • 1970-01-01
    相关资源
    最近更新 更多