Skip to content

依赖层次

本文档描述 Turf.js monorepo 中使用的四层依赖架构。它解释了 100 多个包如何组织成分层结构,从通用的基础模块到依赖外部库的复杂算法。这种层次结构防止循环依赖并支持独立包的模块化消费。

有关三个基础模块本身的信息,请参阅 基础模块。有关模块如何按功能分类的信息,请参阅 模块分类

四层系统概述

Turf.js 将其依赖组织成四个不同的层级。每一层都构建在前一层的基础上,创建一个严格的层次结构,确保在 monorepo 中不会发生循环依赖。

SVG
100%

层级 0:外部依赖

外部依赖提供 Turf.js 本身未实现的专业算法和数据结构。这些库因其稳定性和性能特征而被精心选择。

目的使用方
@types/geojsonGeoJSON 的 TypeScript 类型定义所有 TypeScript 模块
jsts用于计算几何的 Java Topology Suite 移植@turf/buffer, @turf/union, @turf/intersect
polyclip-tsMartinez-Rueda 多边形裁剪算法@turf/mask, @turf/difference
rbushR-tree 空间索引@turf/unkink-polygon, @turf/clusters-kmeans
skmeansK-means 聚类实现@turf/clusters-kmeans
sweepline-intersectionsBentley-Ottmann 线相交@turf/line-intersect
concaveman凹包算法@turf/concave
d3-geo地图投影@turf/projection
earcut多边形三角剖分@turf/tesselate

层级 1:基础模块

三个基础模块构成了整个依赖层次结构的基础。其他所有 Turf.js 模块都至少依赖这些包中的一个。

SVG
100%

@turf/helpers

@turf/helpers 包是最基本的依赖,每个 Turf.js 模块都需要它。它提供:

  • GeoJSON 工厂函数:point()lineString()polygon()featureCollection()
  • 单位转换工具:radiansToLength()lengthToRadians()lengthToDegrees()
  • 常量:用于单位转换的 earthRadiusfactors
  • 选项对象的类型定义

来自 packages/turf-rhumb-destination/package.json77 的依赖声明示例:

"@turf/helpers": "workspace:*"

@turf/meta

@turf/meta 包提供大约 50+ 个模块使用的迭代工具。它能够高效地遍历 GeoJSON 结构:

  • coordEach():遍历所有坐标
  • coordReduce():对坐标进行规约
  • geomEach():遍历几何体
  • flattenEach():遍历展平的特征
  • segmentEach():遍历线段

来自 packages/turf-flatten/package.json72-73 的使用示例:

"@turf/helpers": "workspace:*",
"@turf/meta": "workspace:*"

@turf/invariant

@turf/invariant 包提供输入验证和类型提取,大约 70+ 个模块使用它:

  • getCoord():从各种输入类型提取坐标数组
  • getGeom():从特征或几何体提取几何体
  • 类型守卫:getType()geojsonType()
  • 集合工具:collectionOf()featureOf()

来自 packages/turf-rhumb-bearing/package.json72-73 的示例:

"@turf/helpers": "workspace:*",
"@turf/invariant": "workspace:*"

层级 2:原始操作

层级 2 模块实现仅依赖基础层和外部库的基础几何操作。它们不依赖其他 Turf.js 操作。

SVG
100%

层级 2 模块的特征

层级 2 模块具有共同特征:

  1. 最小依赖:仅依赖基础模块
  2. 单一职责:每个模块执行一个定义明确的计算
  3. 无 Turf.js 内部依赖:不导入其他 Turf.js 操作模块
  4. 高可重用性:被层级 3 和层级 4 模块用作构建块

来自 packages/turf-rhumb-distance/package.json74-79 的示例:

"dependencies": {
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

此包仅依赖 @turf/helpers@turf/invariant,使其成为真正的原始操作。

层级 3:复合操作

层级 3 模块组合来自层级 2 的原始操作以实现更复杂的功能。它们从较低级别的构建块构建更高级的功能。

SVG
100%

示例:@turf/line-slice

@turf/line-slice 模块展示了层级 3 的组合。它依赖 @turf/nearest-point-on-line,其本身也是一个层级 3 模块:

来自 packages/turf-line-slice/package.json68-73

"dependencies": {
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@turf/nearest-point-on-line": "workspace:*",
  "@types/geojson": "^7946.0.10"
}

这表明模块既依赖基础模块,又依赖另一个复合操作。

示例:@turf/line-chunk

@turf/line-chunk 模块展示了多个层级 3 依赖:

来自 packages/turf-line-chunk/package.json73-78

"dependencies": {
  "@turf/helpers": "workspace:*",
  "@turf/length": "workspace:*",
  "@turf/line-slice-along": "workspace:*",
  "@turf/meta": "workspace:*",
  "@types/geojson": "^7946.0.10"
}

它依赖 @turf/length(层级 2)和 @turf/line-slice-along(层级 3),展示了复合操作如何相互构建。

层级 4:复杂算法

层级 4 模块实现复杂的算法,通常需要外部库和跨越层级 1-3 的多个 Turf.js 依赖。

SVG
100%

示例:@turf/unkink-polygon

此模块展示了层级 4 依赖的复杂性:

来自 packages/turf-unkink-polygon/package.json68-76

"dependencies": {
  "@turf/area": "workspace:*",
  "@turf/boolean-point-in-polygon": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/meta": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "rbush": "^3.0.1",
  "tslib": "^2.8.1"
}

此模块需要:

  • 基础模块:@turf/helpers@turf/meta
  • 层级 2 原语:@turf/area
  • 层级 3 操作:@turf/boolean-point-in-polygon
  • 外部库:用于空间索引的 rbush

示例:@turf/mask

来自 packages/turf-mask/package.json66-72

"dependencies": {
  "@turf/clone": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "polyclip-ts": "^0.16.8",
  "tslib": "^2.8.1"
}

此模块使用 polyclip-ts 库进行 Martinez-Rueda 多边形裁剪算法,展示了外部计算几何库的集成。

示例:@turf/line-intersect

来自 packages/turf-line-intersect/package.json71-76

"dependencies": {
  "@turf/helpers": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "sweepline-intersections": "^1.5.0",
  "tslib": "^2.8.1"
}

使用 sweepline-intersections 库实现 Bentley-Ottmann 算法以进行高效的线段相交检测。

依赖链

复杂操作通常通过多个层级创建长依赖链。理解这些链有助于识别任何给定模块的传递依赖。

SVG
100%

来自 packages/turf-point-to-line-distance/package.json69-81

"dependencies": {
  "@turf/bearing": "workspace:*",
  "@turf/distance": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@turf/meta": "workspace:*",
  "@turf/nearest-point-on-line": "workspace:*",
  "@turf/projection": "workspace:*",
  "@turf/rhumb-bearing": "workspace:*",
  "@turf/rhumb-distance": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

这展示了层级 4 模块如何聚合来自较低层级的多个依赖,每个依赖都带来其自己的传递依赖。

其他依赖模式

跨层级布尔操作

布尔操作通常依赖多个 Turf.js 模块来实现其功能:

来自 packages/turf-boolean-parallel/package.json68-75

"dependencies": {
  "@turf/clean-coords": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/line-segment": "workspace:*",
  "@turf/rhumb-bearing": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

@turf/boolean-parallel 模块依赖:

  • @turf/clean-coords(层级 3):移除重复坐标
  • @turf/line-segment(层级 3):将线分割为段
  • @turf/rhumb-bearing(层级 2):计算方位角

工具模块组合

某些模块组合多个工具以提供增强的功能:

来自 packages/turf-rewind/package.json72-80

"dependencies": {
  "@turf/boolean-clockwise": "workspace:*",
  "@turf/clone": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@turf/meta": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

@turf/rewind 模块使用 @turf/boolean-clockwise 在应用 rewind 操作之前确定多边形方向。

几何分析链

复杂的几何分析模块通常具有广泛的依赖链:

来自 packages/turf-polygon-tangents/package.json71-80

"dependencies": {
  "@turf/bbox": "workspace:*",
  "@turf/boolean-within": "workspace:*",
  "@turf/explode": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@turf/nearest-point": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

Workspace 依赖

所有 Turf.js 包对内部依赖使用 "workspace:*" 协议,由 pnpm workspaces 管理。这确保 monorepo 中的所有包在开发期间正确引用彼此,并在发布时解析为适当的版本。

来自 packages/turf-sector/package.json65-72

"dependencies": {
  "@turf/circle": "workspace:*",
  "@turf/helpers": "workspace:*",
  "@turf/invariant": "workspace:*",
  "@turf/line-arc": "workspace:*",
  "@turf/meta": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

workspace:* 协议在发布过程中由 Lerna 转换为具体的版本号,如 lerna.json1-10 中所配置。

主聚合包

@turf/turf 包作为主分发包,依赖所有 100+ 个独立包:

来自 packages/turf/package.json94-210

"dependencies": {
  "@turf/along": "workspace:*",
  "@turf/angle": "workspace:*",
  "@turf/area": "workspace:*",
  // ... 100+ 更多依赖
  "@turf/voronoi": "workspace:*",
  "@types/geojson": "^7946.0.10",
  "tslib": "^2.8.1"
}

此聚合包允许用户通过单个依赖导入整个 Turf.js 库,同时保持模块化结构,支持 tree-shaking 和选择性导入。

防止循环依赖

层级系统通过严格规则防止循环依赖:

  1. 层级 1 模块不能依赖任何其他 Turf.js 模块
  2. 层级 2 模块只能依赖层级 1
  3. 层级 3 模块可以依赖层级 1 和 2
  4. 层级 4 模块可以依赖层级 1、2 和 3
  5. 任何模块如果会创建循环,则不能依赖同一层级的模块

这种层次结构通过以下方式强制执行:

  • Pull Request 评估期间的代码审查
  • 防止本地循环导入的 monorepo 结构
  • 按依赖顺序编译的构建系统

结果是一个有向无环图(DAG)的依赖,确保:

  • 可预测的构建顺序
  • 无循环引用运行时错误
  • 清晰的模块边界
  • 消费应用程序中的高效 tree-shaking