架构
本文档描述 Turf.js 的整体架构,包括其 Monorepo 结构、分层依赖系统、模块化设计原则、构建流水线和外部库集成策略。有关三个基础模块的详细信息,请参阅 基础模块。有关模块的功能分类,请参阅 模块分类。有关完整的依赖层次结构,请参阅 依赖层次。
Monorepo 组织结构
Turf.js 作为一个由 Lerna 管理的 Monorepo 进行组织,包含 100 多个位于 packages/ 目录中的独立包。该仓库使用 PNPM workspaces 进行依赖管理,并在所有包之间维护统一的版本号。
包管理配置
Monorepo 包管理结构
根目录的 package.json2 设置了 "private": true,表示这是一个工作区根目录,本身不发布。lerna.json3-4 文件配置 Lerna 使用 PNPM 作为 npm 客户端,并在所有包中维护版本 7.2.0。@turf/turf 聚合器包 packages/turf/package.json1-211 使用 "workspace:*" 协议声明对所有独立模块的工作区依赖 packages/turf/package.json95-209
分层依赖系统
Turf.js 实现了一个四层依赖架构,防止循环依赖并确保模块化。每一层都构建在前一层的基础上,具有清晰的职责分离。
依赖层结构
四层依赖架构
| 层级 | 目的 | 示例包 | 特性 |
|---|---|---|---|
| 层级 0 | 外部依赖 | @types/geojson, jsts, rbush | 提供专业算法的第三方库 |
| 层级 1 | 基础工具 | @turf/helpers, @turf/meta, @turf/invariant | 被几乎所有其他包使用,无 Turf 依赖 |
| 层级 2 | 原始操作 | @turf/distance, @turf/bearing, @turf/bbox | 基础几何计算,仅依赖层级 1 |
| 层级 3 | 复合操作 | @turf/along, @turf/buffer, @turf/line-slice | 组合层级 2 原语,有限的外部依赖 |
| 层级 4 | 复杂算法 | @turf/union, @turf/concave, @turf/clusters-kmeans | 需要外部库的高级操作 |
@turf/line-slice 包展示了层级 3 的组合。其 package.json68-73 显示了对基础模块(@turf/helpers、@turf/invariant)和一个层级 2 模块(@turf/nearest-point-on-line)的依赖,但避免了外部计算几何库。
模块化设计原则
每个 Turf.js 包都遵循统一的结构,具有单一职责、独立的构建产物和标准化的导出模式。
标准包结构
包构建产物
每个包都在其 package.json 中使用 exports 字段定义双重导出 packages/turf-line-slice/package.json32-44 "type": "module" 字段 packages/turf-line-slice/package.json28 声明 ES Module 为默认格式。main、module 和 types 字段 packages/turf-line-slice/package.json29-31 为旧工具提供向后兼容性。
构建系统架构
构建系统使用 tsup 进行 TypeScript 编译,并生成多种分发格式以支持不同的 JavaScript 环境。
多目标编译流水线
构建流水线和分发格式
独立包使用标准化的构建命令:tsup --config ../../tsup.config.ts packages/turf-line-slice/package.json51 主 @turf/turf 包使用 Rollup 扩展此配置:tsup --config ../../tsup.config.ts && rollup -c rollup.config.js packages/turf/package.json70
Rollup 配置 packages/turf/rollup.config.js1-23 创建一个 UMD 包,具有用于 ES5 兼容性的 Babel 转译、用于浏览器使用的 Node.js polyfills 和 Terser 压缩。输出使用格式 "umd" 和名称 "turf" packages/turf/rollup.config.js14,使库在浏览器中作为 window.turf 可用。
包导出配置
双重格式导出配置支持 ES Module 和 CommonJS 消费者:
| 导出字段 | 目的 | 值 (ESM) | 值 (CJS) |
|---|---|---|---|
type | 声明包类型 | "module" | N/A |
main | CommonJS 入口 | N/A | "dist/cjs/index.cjs" |
module | ES Module 入口 | "dist/esm/index.js" | N/A |
types | TypeScript 类型 | "dist/esm/index.d.ts" | N/A |
exports["."].import | ES Module 消费者 | { types, default } | N/A |
exports["."].require | CommonJS 消费者 | N/A | { types, default } |
exports 字段 packages/turf-line-slice/package.json32-44 为不同的模块系统提供显式入口点,具有单独的 TypeScript 声明文件(ESM 为 .d.ts,CJS 为 .d.cts)。
外部库集成
Turf.js 策略性地集成专门的外部库用于计算密集型操作,将自己的代码集中在 GeoJSON 互操作性和 API 设计上。
关键外部依赖
| 库 | 目的 | 使用方 | 原因 |
|---|---|---|---|
jsts | 计算几何算法 | @turf/buffer, @turf/union, @turf/intersect, @turf/difference | 实现 Java Topology Suite 算法以进行可靠的布尔操作和缓冲 |
polyclip-ts | Martinez-Rueda 布尔操作 | 多边形布尔操作 | 某些多边形操作的 JSTS 替代品 |
rbush | R-tree 空间索引 | @turf/clusters-kmeans, @turf/clusters-dbscan, @turf/nearest-point | 用于聚类和最近邻操作的高效空间查询 |
d3-geo | 地图投影 | @turf/projection, @turf/great-circle | 等距方位和其他制图投影 |
concaveman | 凹包算法 | @turf/concave | 专用的快速凹包实现 |
skmeans | K-means 聚类 | @turf/clusters-kmeans | 统计聚类算法 |
earcut | 多边形三角剖分 | @turf/tesselate | 用于多边形分解的快速三角剖分 |
sweepline-intersections | Bentley-Ottmann 算法 | @turf/line-intersect | 高效的线段相交检测 |
这种架构决策允许 Turf.js 利用经过实战检验的算法,同时保持一个干净的、专注于 GeoJSON 的 API 表面。
开发和质量基础设施
仓库包含全面的工具,用于维护所有包的代码质量和一致性。
Pre-commit 和 CI 流水线
质量保证流水线
根目录的 package.json18-29 配置 lint-staged 在提交时运行,执行 ESLint 修复、Prettier 格式化和 README 重新生成。prepare 脚本 package.json15 在安装时运行 Husky 设置并构建所有包。test 脚本 package.json16 运行 lint,然后通过 Lerna 构建和测试所有包。
.monorepolint.config.mjs 配置(在 package.json12 和 package.json34-37 中引用)在所有包中强制执行一致性规则,例如标准化的 package.json 字段、依赖版本对齐和脚本命名约定。
版本管理
Monorepo 中的所有包共享由 Lerna 管理的统一版本号,目前为版本 7.2.0 lerna.json4 这种同步版本管理简化了依赖管理,并确保整个生态系统保持兼容。Lerna publish 命令 lerna.json5-8 处理同时将所有更改的包发布到 npm 注册表,在整个 @turf/* 命名空间中维护版本一致性。