一、前言:普遍的 CLI 报错痛点
在 uni-app 新版 Vite+TS 技术栈项目中,绝大多数开发者都会遇到一个极其迷惑的 CLI 报错。执行 App 打包命令进行编译:
npm run build:app
终端直接抛出文件不存在错误,关键报错信息如下:
Error: ENOENT: no such file or directory
open '/src/manifest.json'
这个报错让人十分费解,因为当前项目满足以下全部条件:项目使用 HBuilderX 可以正常编译、运行、调试;项目内已经完整编写 manifest.config.ts;vite.config.ts 也正常注册了 manifest 转换插件。明明已经使用 TS 可编程配置,CLI 却依旧强制读取 /src/manifest.json,缺失该文件就直接编译失败。
绝大多数开发者的第一直觉判断都是:manifest.config.ts 可以完全替代 manifest.json,直接删除静态 JSON 文件即可。笔者最初也持有相同认知,直到翻阅插件与 uni-app 编译源码后才理清核心逻辑:manifest.config.ts 本质只是配置生成器,而非官方配置替代品。这也是 CLI 编译报错、HBuilderX 运行正常的核心原因。本文将深度拆解 manifest.config.ts 的底层工作原理、插件运行逻辑、HBuilderX 与 CLI 的文件读取差异,同时说明生成 manifest.json 的标准流程,彻底解决 CLI 编译报错问题。
二、核心认知纠正:manifest.config.ts 不会自动替代 manifest.json
2.1 两类配置文件的本质定位
首先需要明确一个核心结论:manifest.config.ts 并不是 uni-app 官方原生识别的配置文件,无法直接替代 manifest.json。二者定位有着本质区别:
• manifest.json:uni-app 框架原生标准配置文件,属于编译底层依赖的静态资源。框架所有编译内核、多端打包逻辑、原生能力适配均强制依赖该文件,不可缺失,是编译流程的硬性基础文件。 • manifest.config.ts:人工拓展的可编程配置文件,依托第三方插件实现功能。它支持 TS 类型校验、逻辑分支编写、环境变量判断、配置复用,仅作为配置编写源文件,本身不被 uni-app 原生编译内核识别。
2.2 基础运行流程
manifest.config.ts 的完整工作逻辑为:开发者编写 TS 格式配置 → 第三方插件解析编译 → 自动生成静态的 manifest.json → 框架读取生成后的 JSON 文件完成编译。如果缺失插件编译环节,manifest.config.ts 只是一个无效的文本文件,框架无法识别解析。
三、关键插件:@uni-helper/vite-plugin-uni-manifest 工作原理
3.1 插件核心作用
@uni-helper/vite-plugin-uni-manifest 是支撑 manifest.config.ts 生效的唯一核心插件,也是目前 uni-app 社区通用的 manifest 配置增强插件。该插件的核心作用并非修改框架底层逻辑,而是做配置转换与文件生成,具体能力如下:
1. 解析根目录下的 manifest.config.ts文件,支持 TS 语法、类型约束、注释编写;2. 根据当前运行环境、打包平台,执行配置内部逻辑分支,合并环境变量配置; 3. 将可编程的 TS 配置,实时编译输出为标准、无语法错误的 manifest.json;4. 监听 ts 配置文件改动,热更新同步刷新生成的 json 文件,无需手动编译。
3.2 插件基础使用规范
该插件仅适配 Vite 构建模式的 uni-app 项目,不支持旧版 Webpack 项目。标准使用流程为:
# 安装依赖
pnpm i -D @uni-helper/vite-plugin-uni-manifest
在 vite.config.ts 中引入注册插件,同时在根目录新建 manifest.config.ts,通过官方提供的 defineManifestConfig 函数编写配置,保证类型校验完整性。插件在开发、打包阶段会自动触发编译,输出目标 json 文件。
四、核心差异:HBuilderX 与 CLI 的 manifest 读取逻辑
HBuilderX 能正常运行、CLI 频繁报错,根本原因是二者的编译运行内核、插件加载机制、文件读取优先级完全不同,并非代码配置错误。
4.1 HBuilderX 运行机制
1. HBuilderX 内置定制化 Vite 内核,默认预装 uni-helper 系列生态插件,无需开发者手动配置插件依赖; 2. 编辑器内置编译流程会优先自动加载 manifest 转换插件,后台静默解析 manifest.config.ts;3. 在内存中临时生成虚拟的 manifest.json,无需在项目物理目录生成实体文件;4. 编译内核直接读取内存虚拟文件,开发者无感知,因此不会出现文件缺失报错。
4.2 CLI 命令行运行机制
1. CLI 采用纯净官方编译内核,无内置预装插件,仅加载开发者手动配置的依赖插件; 2. CLI 编译流程严格遵循原生规范,强制读取物理磁盘中的 manifest.json 实体文件,不识别内存虚拟文件; 3. 若插件未正常生效、未生成物理 json 文件,CLI 直接判定文件缺失,抛出 manifest.json not found错误;4. 原生 CLI 不会主动解析 ts 配置文件,无插件转换逻辑,原生仅兼容 json 静态格式。
五、问题解答:为什么 uni build -p app 仍读取 /src/manifest.json
5.1 目录规范硬性要求
根据 uni-app 官方目录规范:HBuilderX 可视化创建的空白项目,manifest.json 默认放置在项目根目录;而 CLI 脚手架创建的标准项目,原生强制要求 manifest.json 存放于 /src 目录下。
执行 uni build -p app 进行 App 端打包时,CLI 会严格按照脚手架规范,固定读取 /src/manifest.json,不会识别根目录的配置文件,也不会主动识别 ts 配置文件。
5.2 App 端打包的特殊编译逻辑
相较于小程序、H5 端,App 端打包流程更为特殊,涉及原生资源打包、基座配置、权限注入、图标启动图编译等底层操作。CLI 在 App 打包阶段会优先校验 src 目录下的原生配置文件,用于同步生成 Android、iOS 原生工程配置,此时插件的转换优先级低于原生校验优先级,即便配置插件,未完成物理生成的 json 文件依旧会判定缺失。
六、标准流程:如何正确生成 manifest.json
想要兼顾 HBuilderX 调试、CLI 命令打包,必须遵循标准生成流程,保证项目存在物理实体 manifest.json,具体操作步骤如下:
6.1 前置准备
1. 确认项目为 Vite 架构,安装依赖 @uni-helper/vite-plugin-uni-manifest;2. 在 vite.config.ts中正确注册插件,无重复配置、无注释屏蔽;3. 根目录编写完整的 manifest.config.ts,使用官方函数定义配置,规避语法错误。
6.2 手动触发生成指令
方式一:执行开发启动指令,插件自动编译生成文件
pnpm dev:h5
启动成功后,插件会自动在指定目录生成标准 manifest.json,默认生成路径适配当前项目架构,CLI 脚手架项目会直接生成至 src 目录。
方式二:强制刷新生成,清除缓存
1. 删除项目 node_modules/.cache 缓存文件夹; 2. 重启命令行执行启动指令,插件重新解析 ts 配置,纯净生成 json 文件。
6.3 生成文件注意事项
• 禁止手动修改生成的 manifest.json,所有配置统一在 ts 文件中编写,避免改动被插件覆盖;• 配置环境变量时,需在插件中配置环境判断逻辑,保证不同打包平台生成对应差异化 json; • 不要删除原始空白 json 文件,初次使用可保留空文件,由插件自动覆盖写入。
七、终极总结:HBuilderX 能跑、CLI 不能跑的完整原因
结合全文逻辑,直白总结二者运行差异及报错根源:
1. 文件本质区别: manifest.config.ts是可编程源码,manifest.json是编译产物,前者永远无法直接替代后者;2. 插件依赖区别:TS 配置生效必须依赖 @uni-helper/vite-plugin-uni-manifest,无插件则 TS 文件无效;3. 运行内核区别:HBuilderX 内置插件,内存生成虚拟 json;CLI 纯净内核,必须读取物理 json 文件; 4. 目录规范区别:CLI 脚手架 App 打包指令固定读取 /src/manifest.json,路径不可自定义修改;5. 报错根源:CLI 打包时,未通过插件生成物理 json 文件,框架检测不到原生配置文件,抛出缺失错误。
八、通用避坑解决方案
1. 所有 Vite+TS 项目必须安装 manifest 转换插件,不可省略依赖; 2. CLI 打包前,优先执行一次本地开发指令,确保生成物理 json 产物; 3. 严禁删除 src 目录下的原始 manifest.json 空白文件,防止路径校验失败; 4. 统一编码习惯,所有配置仅修改 ts 文件,不手动编辑生成的 json 文件; 5. 出现缓存报错时,清除 node_modules 缓存、重启命令行,避免旧配置残留干扰编译。

夜雨聆风