Aspire CLI 的 npm 安装包使用指南:从全局安装到 TypeScript AppHost 实战
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
本篇技术指南围绕 Aspire CLI 的 npm 分发包展开。Aspire 是面向分布式应用的 code-first 应用模型,其 CLI 以npm install -g方式发布,通过一个小巧的 JavaScript launcher 调用平台原生二进制,让你在终端中完成 Aspire AppHost 的创建、运行、发布与部署。读完本文,你将掌握 npm 包的安装与升级方法、launcher 的平台选择与缓存机制、常用命令的完整用法,以及基于 TypeScript AppHost(apphost.mts)从零搭建带支撑服务的分布式应用的实战方案。
Aspire CLI 的 npm 分发架构:pointer 包 + RID 包
与直接发布单一二进制不同,Aspire CLI 采用 npm 生态中成熟的"指针包(pointer package)+ 平台特定包(RID package)"双包结构。顶层包名为@microsoft/aspire-cli,它只包含少量 JavaScript 文件,真正的原生 CLI 二进制则由各个平台专属的 optional dependencies 携带:
@microsoft/aspire-cli # 顶层指针包(launcher) ├── package.json ├── README.md ├── bin/aspire.js # JavaScript launcher └── bin/aspire-package-map.json # RID -> 包名映射表RID(Runtime Identifier)包按操作系统、CPU 架构与 Linux libc 组合命名,共七个:
| RID 包名 | 平台 | CPU | libc |
|---|---|---|---|
@microsoft/aspire-cli-win-x64 | Windows | x64 | — |
@microsoft/aspire-cli-win-arm64 | Windows | arm64 | — |
@microsoft/aspire-cli-linux-x64 | Linux | x64 | glibc |
@microsoft/aspire-cli-linux-arm64 | Linux | arm64 | glibc |
@microsoft/aspire-cli-linux-musl-x64 | Linux | x64 | musl |
@microsoft/aspire-cli-osx-x64 | macOS | x64 | — |
@microsoft/aspire-cli-osx-arm64 | macOS | arm64 | — |
每个 RID 包内是bin/aspire(Windows 上为bin/aspire.exe)原生可执行文件。这种"顶层命令 + 平台负载"的设计在 npm 生态中已有成熟先例,Aspire 的完整设计权衡可参见 npm CLI 包设计规格。顶层包的package.json通过os、cpu、libc元数据让 npm 只安装匹配当前平台的 RID 包,具体映射关系在打包脚本 pack-cli-npm-package.ps1 中定义。
安装 Aspire CLI:平台要求与三步验证
npm 安装包要求Node.js 20 或更高版本(launcher 使用了 Node 16.9+ 的Erroroptions-bag 语法,而libc选择器依赖 npm >= 10.7,该版本随 Node 20.10+ 一同发布,Node 18 已于 2025-04-30 停止维护,因此 Node 20 是受支持的最低 LTS)。
支持的平台包括:Windows x64/Arm64、macOS x64/Arm64、带 glibc 的 Linux x64/Arm64,以及带 musl 的 Linux x64(即 Alpine 环境)。
npm install -g @microsoft/aspire-cli安装完成后立即验证:
aspire --version aspire --help安装过程中有一个容易踩的坑:顶层包通过 npm optional dependencies 安装各平台的原生包,切勿禁用 optional dependencies(不要使用--omit=optional、--no-optional或设置npm_config_optional=false),否则 launcher 找不到原生 CLI 二进制,安装即失败。这一点在 launcher 源码 中也有对应的诊断提示。
launcher 工作原理:RID 检测、musl 识别与安全缓存
npm install -g安装的aspire命令实际执行的是 bin/aspire.js launcher,它的启动流程如下:
- 读取 RID 映射表:加载
bin/aspire-package-map.json,将当前 RID 映射到具体 npm 包名(包名在打包时生成,launcher 不硬编码)。 - 检测当前 RID:基于
process.platform、process.arch判定 Windows/macOS/Linux 分支,Linux 下还需额外区分 glibc 与 musl(见 detectRid)。 - 解析原生包:用
require.resolve("<rid-package>/package.json")定位已安装的 RID 包,并校验 RID 包版本与顶层包版本一致,防止部分安装或版本错配(resolveNativeBinary)。 - 复制到 Aspire 自有缓存:将原生二进制复制到
~/.aspire/npm/<version>/<rid>/bin/(Windows 为%USERPROFILE%\.aspire\npm\<version>\<rid>\bin\aspire.exe)。 - 转发信号并启动子进程:以继承 stdio 的方式 spawn 缓存二进制,透传全部命令行参数。
关于 Linux libc 检测有一个值得注意的细节:glibc 与 musl 混装环境下,二进制与动态链接器不匹配会在 exec 时崩溃(报错如missing ld-linux-aarch64.so.1或GLIBC_X.Y not found)。因此 launcher 采用三层探测策略(isMusl):优先使用 Node 的 runtime report(glibcVersionRuntime字段存在即排除 musl),其次以ldd --version输出为权威依据,最后才回退到检查/lib、/usr/lib下是否存在ld-musl-*.so文件。任何探测失败都会落到友好的 "Unsupported platform" 错误,而不是静默加载错误二进制。
为什么必须复制到缓存目录?因为 Aspire CLI 首次运行时会在进程路径相对位置自解压内嵌 bundle。若直接从node_modules执行,解压目标可能落在 pnpm store、Yarn unplugged 目录、npm 全局缓存等只读的包管理器路径中。复制到 Aspire 自有的可写缓存布局(目录以 0700 权限创建)即可规避这一问题。缓存新鲜度采用"文件大小 + mtime"双重校验,不一致时通过临时文件原子重命名更新缓存,避免并发首次运行时读到残缺二进制(ensureCachedBinary)。
launcher 还会设置三个环境变量透传给 CLI,使 CLI 感知自己运行自 npm 安装:
ASPIRE_NPM_PACKAGE=@microsoft/aspire-cli ASPIRE_NPM_PACKAGE_VERSION=<version> ASPIRE_NPM_PACKAGE_RID=<rid>CLI 端的 NpmInstallDetection 检测到这些变量后,会把aspire update --self与更新提示路由到npm install -g @microsoft/aspire-cli@latest,而不是用 GitHub 二进制下载器去覆盖 npm 拥有的文件。若需要调试或测试,缓存根目录可通过环境变量ASPIRE_NPM_CACHE_DIR覆盖。
快速开始:从空目录到运行中的 AppHost
安装完成后有三种入门路径:
- 全新应用:运行
aspire new从模板创建 Aspire 应用。 - 现有仓库:运行
aspire init为仓库添加 AppHost,然后运行aspire run。 - 仅需仪表板:运行
aspire dashboard run启动独立仪表板。
对于已有一个或多个应用项目的现有仓库:
aspire init aspire runaspire run会启动 AppHost 并自动打开 Aspire 仪表板,其中汇集了日志、链路追踪、指标、资源与健康检查信息。
常用命令一览
| 命令 | 作用 |
|---|---|
aspire new | 从模板创建新的 Aspire 应用 |
aspire init | 为现有仓库添加 AppHost |
aspire add <integration> | 安装集成,例如 PostgreSQL、Redis |
aspire run | 启动 AppHost 并打开仪表板 |
aspire publish | 根据 AppHost 模型准备部署产物 |
aspire deploy | 将 AppHost 部署到支持的部署目标 |
aspire dashboard run | 仅启动仪表板,供已导出 OpenTelemetry 的应用接入 |
aspire --help/aspire <command> --help | 查看当前命令选项 |
独立仪表板:单命令接入 OpenTelemetry
Aspire 仪表板可以独立于 AppHost 运行,任何导出了 OpenTelemetry 数据的应用都可以接入,无需 AppHost 参与。启动方式只需一条命令:
aspire dashboard run启动后,你的应用通过OTEL_EXPORTER_OTLP_ENDPOINT环境变量指向仪表板暴露的 OTLP 端点即可上报数据。更细粒度的控制可通过aspire dashboard run --help查看,常用选项包括--frontend-url、--otlp-grpc-url与--allow-anonymous。
一个简单的 TypeScript AppHost 应用定义
Aspire 是 code-first 模型,应用结构用 TypeScript AppHost(apphost.mts)以代码描述:项目、容器、数据库、缓存以及它们之间的连接关系全部声明在代码中。下面的例子运行一个 Express API 和一个 Vite 前端,将 API 通过 HTTP 对外暴露,并把前端与 API 连接起来:
import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); // Run the Express API and expose its HTTP endpoint externally. const app = await builder .addNodeApp("app", "./api", "src/index.ts") .withHttpEndpoint({ env: "PORT" }) .withExternalHttpEndpoints(); // Run the Vite frontend after the API and inject the API URL for local proxying. const frontend = await builder .addViteApp("frontend", "./frontend") .withReference(app) .waitFor(app); // Bundle the frontend build output into the API container for publish/deploy. await app.publishWithContainerFiles(frontend, "./static"); await builder.build().run();每个 builder 调用都返回 promise,因此在另一个资源引用某资源之前,必须用await先拿到该资源对象。aspire run会构建并启动全部资源,然后打开仪表板。
添加支撑服务:数据库与缓存
数据库、缓存等资源用同样的方式添加,并通过withReference建立连接;waitFor让依赖方等待资源就绪后再启动:
import { createBuilder } from './.aspire/modules/aspire.mjs'; const builder = await createBuilder(); const postgres = await builder.addPostgres("postgres"); const db = await postgres.addDatabase("db"); const cache = await builder.addRedis("cache"); await builder .addNodeApp("api", "./api", "src/index.ts") .withHttpEndpoint({ env: "PORT" }) .withExternalHttpEndpoints() .withReference(db) .withReference(cache) .waitFor(db) .waitFor(cache); await builder.build().run();注意:addPostgres与addRedis只有在先用aspire add postgresql和aspire add redis安装对应集成后才可用。
更新与卸载
更新到最新的 npm 发布版本:
npm install -g @microsoft/aspire-cli@latest如果是从 npm 安装的 CLI 执行aspire update --self,CLI 会引导你回到上面的 npm 更新命令,而不会尝试用二进制下载器覆盖 npm 管理的文件。卸载同样通过 npm 完成:
npm uninstall -g @microsoft/aspire-cli故障排查
optional dependencies 被禁用导致安装失败
如果安装失败,或 launcher 提示原生包未安装,请检查是否使用了--omit=optional、--no-optional或npm_config_optional=false环境变量,然后重新执行:
npm install -g @microsoft/aspire-cli顶层包的postinstall脚本(node bin/aspire.js --npm-postinstall-check)会在支持平台上立即校验原生 RID 包是否存在,从而把"缺原生二进制"的问题提前到安装阶段暴露,而不是拖到首次执行aspire时才报错。不过,若使用--ignore-scripts跳过生命周期脚本,运行时 launcher 仍会保留同样的缺失原生包诊断。
PATH 中找不到aspire
确认 shell 能访问 npm 的全局可执行目录:npm prefix -g可以显示全局前缀;macOS 与 Linux 上aspireshim 通常位于该前缀的bin目录下,Windows 上通常位于用户配置文件下的 npm 目录中。
平台与架构不受支持
当前 npm 包仅提供 Windows x64/Arm64、macOS x64/Arm64、带 glibc 的 Linux x64/Arm64、带 musl 的 Linux x64 原生二进制。其他平台不受该包支持。RID 包与顶层包的平台元数据在打包脚本中一一对应,且 launcher 的 RID 检测与打包脚本的 RID 列表由单元测试交叉验证(见 AspireJsLauncherTests),防止两端失配。
安装损坏或版本错配
如果 launcher 报告包损坏、原生包版本与顶层包版本不匹配,或缺失原生二进制,请重装:
npm uninstall -g @microsoft/aspire-cli npm install -g @microsoft/aspire-clilauncher 在每次启动时都会校验 RID 包版本与指针包版本一致,并在复制到缓存前用lstat(而非stat)拒绝将符号链接视为有效缓存条目,避免缓存被低权限攻击替换为指向外部内容的链接(needsCopy)。此外,launcher 会把 SIGINT、SIGTERM、SIGHUP(POSIX 下还有 SIGQUIT,Windows 下为 SIGBREAK)转发给原生子进程,确保程序化kill <wrapper>不会让长期运行的aspire run会话遗留孤儿进程。
构建、验证与发布:npm 包如何从仓库走向 npmjs
理解使用层面的机制后,可以进一步了解这个 npm 包是如何从本仓库产出并保证质量的:
- 打包:构建流程从已签名的原生 CLI 归档中提取
aspire(或aspire.exe)二进制,由 pack-cli-npm-package.ps1 生成指针包与 RID 包各自的临时目录与package.json,再调用npm pack产出.tgz。你正在阅读的这份 README 正是指针包 README 的模板,其中的__PACKAGE_NAME__与__VERSION__占位符在打包时被替换为实际包名与版本。 - RID 包 README:各平台专属包的 README 来自 pack-cli-npm-package.rid.README.md,同样在打包时填充占位符。
- 验证:verify-cli-npm-package.ps1 会逐个核对 RID 包中的二进制与签名归档二进制逐字节一致,并校验指针包的
bin声明、postinstall脚本、版本戳记的 README、aspire-package-map.json及 optionalDependencies 版本对齐。 - 端到端安装测试:CI 会在 Windows、Linux 与 macOS 上执行真实的
npm install -g冒烟测试,断言aspire --version输出与构建版本一致,并确认运行时缓存落在预期的~/.aspire/npm/<version>/<rid>/bin布局下,最终汇总为validation-summary.json,发布流水线以此作为放行门槛。 - 测试保障:仓库内还包含针对 launcher 的单元测试(AspireJsLauncherTests),覆盖 RID 包版本错配、损坏的 package.json、chmod/复制失败时的临时文件清理、缓存复制与环境变量转发、以及 RID 检测与打包脚本的一致性等场景,保证 launcher 在各种异常与并发条件下行为可靠。
对发布细节、RID 检测的完整设计决策与安全权衡感兴趣的读者,可进一步阅读 npm CLI 包设计规格 与 launcher 源码。
【免费下载链接】aspireAspire is the tool for code-first, extensible, observable dev and deploy.项目地址: https://gitcode.com/GitHub_Trending/as/aspire
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考