Expo 模块开发基础设施指南:基于 `expo-module-scripts` 的统一工程化实践
Expo 模块开发基础设施指南基于expo-module-scripts的统一工程化实践【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo本指南面向希望在 Expo 开源仓库中贡献或移植通用模块universal module的开发者系统讲解从src源码到build产物的标准开发流程模块脚手架、统一构建/测试工具链、TypeScript 配置、Jest 预设与package.json元数据约定。读完本文你将掌握 Expo 多模块 monorepo 中一份配置、处处复用的工程化心法并能独立创建一个符合官方质量标准的原生模块。本文依据仓库文档 guides/Expo Module Infrastructure.md 展开并结合当前仓库中的实际实现packages/expo-module-scripts、packages/expo-sms 等进行源码级佐证与更新。该文档在仓库中已被标注Warning: This doc is outdated and will be updated soon因此本文在保留其核心骨架的同时会以当前仓库代码为准说明演进后的实际用法。统一模块基础设施为什么要标准化Expo 仓库本仓库即其镜像维护着大量跨平台原生模块Android / iOS / Web例如短信、相机、文件系统等。这些模块如果各自为政会带来三方面问题SDK 一致性不同模块在 API 形态、目录组织、构建产物上差异过大会破坏整体 SDK 的连贯质量知识复用开发者在一个模块上积累的经验难以迁移到其他模块维护负担工具链版本漂移Babel、TypeScript、Jest 各用各的版本会让 monorepo 的整体升级变得极其痛苦。因此该仓库的目标非常明确让所有模块共享同一套标准配置与工具降低模块间差异让在 Expo 上开发模块这件事保持简单。这一目标的技术落点是名为expo-module-scripts的私有包——它被定位为模块配置的唯一事实来源source of truth。在 pnpm workspaces 布局下所有模块都引用仓库内版本workspace:*从结构上保证了各模块使用完全一致的 Babel、TypeScript、Jest 版本。仓库根目录存在 pnpm-workspace.yaml确认了 pnpm workspace 的多包管理方式各模块package.json中形如expo-module-scripts: workspace:*的声明参见 expo-sms/package.json正是这一机制的体现。生成一个新模块从expo-cli到create-expo-module原文档记录的是expo-cli时代的脚手架命令expo generate-module [new module directory]可选参数[new module directory]用于指定模块名例如expo generate-module expo-test-module会创建名为expo-test-module的模块省略时会以交互方式询问模块名可选参数--template template directory用于指定创建模块时使用的模板目录。需要说明的是原文档特别标注为 outdated从当前仓库源码结构看模块脚手架已经演进为独立的包与模板目录packages/create-expo-module负责模块创建的编排逻辑特征探测、平台支持、示例应用生成、模板处理、包管理器选择、遥测等均可从 packages/create-expo-module/src 的源码结构推断出来packages/expo-module-template沉淀了标准模块骨架的模板文件以.ejs模板为主包含src、平台原生代码、Jest 配置、package.json、tsconfig.json等模板源。若你计划基于当前仓库创建模块应以这两个包为准文档中expo-cli的用法描述可作为历史背景理解。expo-module-scripts模块开发的标准件集把它声明为开发依赖每个模块要在package.json中把expo-module-scripts声明为开发依赖{ devDependencies: { expo-module-scripts: ^latest version } }当前仓库中 expo-module-scripts/package.json 表明其最新版本为56.0.3自述定位为 A private package for various tasks for Expo module packages like compiling and testing为 Expo 模块包提供编译与测试等任务的私有包。注意该包是私有private基础设施包一般不被模块对外发布所依赖仅作为开发期工具链存在它暴露两个可执行入口bin字段expo-build与expo-module见 package.json。标准 npm scriptsexpo-module-scripts定义了一系列开发期或 npm 生命周期期应执行的脚本。按原文档约定各模块在package.json中声明如下公共脚本{ scripts: { build: expo-module build, clean: expo-module clean, lint: expo-module lint, test: expo-module test, postinstall: expo-module postinstall, prepare: expo-module prepare, prepublishOnly: expo-module prepublishOnly, expo-module: expo-module } }expo-module程序由expo-module-scripts提供可通过pnpm expo-module --help查看全部命令。这些脚本中相当一部分是交互式的会启动文件监听器面向人类开发者而非 CI。若要以非交互模式运行需设置环境变量EXPO_NONINTERACTIVE1。对照当前仓库 bin/expo-module.js 的源码实际注册的子命令如下分类命令说明常用脚本configure生成公共配置文件如 tsconfig 等常用脚本readme生成 README常用脚本typecheck只做类型检查、不产出 JS并监听文件变化常用脚本build编译 src 中的 JS/TS 并监听文件变化常用脚本depscheck校验源码 import 是否全部声明在 dependencies 中常用脚本format格式化源码常用脚本test以交互式 watcher 运行单元测试常用脚本clean删除编译产物生命周期脚本prepare在 npmprepare阶段执行生命周期脚本prepublishOnly在 npmprepublishOnly阶段执行透传脚本jest以给定参数运行 Jest透传脚本tsc以给定参数运行 tsc原文档所列的postinstall子命令在现版 CLI 中已被configure取代——这一点从 bin/expo-module.js 的命令清单可以确认。各子命令实际委托给bin/下对应的可执行脚本如expo-module-clean、expo-module-configure、expo-module-test等这些文件在 publishConfig.executableFiles 中被逐一登记以保证发布后具有可执行权限。以真实模块为例expo-sms/package.json 中即采用了与上表一致的生命周期接线clean/format/prepublishOnly/depscheck直接调用expo-module子命令build使用expo-build srctypecheck使用tsc -p tsconfig.json。自动生成的配置文件与提交进 Git策略configure原文档描述中为postinstall会在必要时于模块包内自动生成配置文件——例如 Babel 会在包目录内查找自己的配置文件。关键约定是这些自动生成的配置文件要提交进 Git。理由有二可以在版本历史中跟踪这些文件的变更必要的情况下允许开发者手动编辑并提交这些文件。如果你看过真实模块目录例如 expo-sms会发现tsconfig.json、oxlint.config.mjs、expo-module.config.json等生成文件确实被提交在仓库中而非仅存在于本机。目录结构与构建产物约定expo-module-scripts对模块目录有严格约定模块源码必须以 TypeScript 书写放在名为src的目录下编译产物输出到名为build的目录build目录不提交到 Git在.gitignore中。之所以敢把产物排除出版本控制是因为 Turborepo 即承担这一任务编排职责。以 expo-sms/src 为例其源码组织为SMS.ts公开 API 入口SMS.types.ts类型定义ExpoSMS.ts/ExpoSMS.native.ts平台桥接实现__tests__/随附单元测试在package.json中包的主入口要指向build下的编译产物{ main: build/ExampleModule.js }真实示例见 expo-sms/package.jsonmain: build/SMS.js同时types: build/SMS.d.ts。运行pnpm clean会删除整个build目录如 expo-sms/package.json 的clean: expo-module clean。编译 TypeScript 与类型检查运行pnpm build把源码从src编译到build。在模块内该命令通常为expo-build src见 expo-sms/package.json。运行pnpm typecheck用tsc做纯类型检查不产出任何 JS 文件。在 monorepo 中跨包工作时优先从仓库根目录通过 Turborepo 运行pnpm build、pnpm typecheck——这样只有受影响的包会被重建且结果会被缓存复用。模块的tsconfig.json由configure自动生成并extendsexpo-module-scripts内部的主配置。该主配置即 tsconfig.base.json。从其中可以读到模块级 TypeScript 的几组关键默认值模块与解析module: esnext、moduleResolution: bundler、moduleDetection: force、verbatimModuleSyntax: true、isolatedModules: trueReact JSXjsx: react-jsx严格性strict: true外加noImplicitReturns、noUncheckedIndexedAccess、noFallthroughCasesInSwitch、forceConsistentCasingInFileNames等产物declaration: true、declarationMap: true、sourceMap: true、inlineSources: true——这意味着类型声明与源码映射在编译期就一并产出方便 IDE 跳转与调试类型检查加速incremental: true并把增量缓存写入${configDir}/.tsbuildinfo类型来源lib同时包含dom、DOM.Iterable、esnexttypes预置jest且通过customConditions把 monorepo 内包的类型重定向到src。快速且可预期的单元测试expo-module-scripts同时提供一个 Jest 预设。模块只需在package.json中加入{ jest: { preset: expo-module-scripts } }该预设为测试拉起专门的 tsconfig并让测试代码像在真实 App 中那样完成转译。原文档提到该预设基于ts-jest这一点已随仓库演进有所变化从 expo-module-scripts/package.json 的依赖清单可以看到swc/jest、swc/core、swc-contrib/mut-cjs-exports以及同目录下的 jest-swc-transform.cjs说明当前实现走的是 SWC 与 jest-expo 组合的转译路径还预置了testing-library/react-native供组件测试使用。文档中关于ts-jest的描述应按过期处理。阅读预设核心 jest-preset.cjs 还能看到几个值得注意的工程决策passWithNoTests: true——允许尚无测试文件的包不因没有测试而失败通过jest-expo/config/maxWorkers限制并行 worker 数避免在开发机上跑满 CPU采用multi-project runner把 iOS / Android / Web / Node 四个平台的 jest-expo 预设分别包进createJestPreset(...)并作为独立 project 运行——这意味着一个模块的单元测试会同时在这些目标环境中验证接入jest-watch-typeahead与jest-snapshot-prettier对快照做 prettier 排版提升交互式 watch 体验。运行pnpm test会以 watcher 模式启动 Jest默认只跑受改动影响的测试并在文件保存后自动重跑。由于每次文件变化都会触发测试这些单元测试必须保持快速与确定性——这也是上面maxWorkers限制与分层预设设计的初衷。真实模块的接线可参考 expo-sms/package.json 的jest: { preset: expo-module-scripts }。package.json元数据字段约定为了让每个模块在 npm 与 GitHub 上可追溯、可归属原文档要求各模块在package.json中填写统一元数据repository与bugs指向 Expo 仓库homepage指向模块源码位置并声明author与license。原文档给出的示例形态如下{ repository: { type: git, url: Expo 仓库的 git 地址 }, author: Expo, license: MIT, bugs: { url: Expo 仓库的 issue 地址 }, homepage: 该模块的源码或文档地址 }参考当前仓库中真实模块的落地写法见 expo-sms/package.jsonexpo-sms在 monorepo 内的成熟实践还包含repository.directory指向本包子目录packages/expo-smshomepage指向其 SDK 文档页keywords罗列expo、react-native、sms等检索词sideEffects: false帮助打包器做 tree-shaking。此外一个功能完整的模块通常还会声明types指向build下的.d.ts、peerDependencies如对expo的依赖、devDependencies如expo-module-scripts: workspace:*——全部细节都可在 expo-sms/package.json 中对照查看。从零到一模块开发速查清单把上述约定收敛为一份可执行的清单初始化在packages/下放置模块目录命名遵循expo-*如用脚手架参考 create-expo-module 与 expo-module-template原文档中expo-cli generate-module为过期描述。接入expo-module-scripts在devDependencies中声明expo-module-scripts当前版本56.0.3利用 pnpm workspace 统一其来源。声明 npm scripts按上文表格接入build/clean/lint/test/prepare/prepublishOnly/typecheck交互式命令在 CI 中记得设置EXPO_NONINTERACTIVE1。生成并提交配置运行expo-module configure生成tsconfig.json等公共配置并将其提交进 Git。布局源码与产物源码放src/产物输出build/不入库main指向build/Entry.js。配置测试在package.json中声明jest: { preset: expo-module-scripts }保持单测快速、确定性以支撑 watcher 模式的每次保存重跑。填写元数据repository/bugs指向 Expo 仓库并在directory中标注模块子路径homepage指向模块文档或源码位置声明author、license: MIT、types与合适的keywords。编译与发布开发期用pnpm build/pnpm typecheck优先从 monorepo 根通过 Turborepo 执行以复用缓存发布走prepublishOnly阶段校验。遵循这套基础设施模块开发者的日常循环就收敛为写src→ watcher 自动构建与测试 → 提交配置与源码而把工具链的差异与版本漂移彻底隔绝在expo-module-scripts这一个事实来源中——这正是 Expo 能在数十个跨平台模块间长期维持 API 连贯性与工程质量的关键所在。【免费下载链接】expoAn open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.项目地址: https://gitcode.com/GitHub_Trending/ex/expo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →