Angular Schematics调用ng-new报Invalid Source (undefined)问题求助
解决Angular自定义Schematics调用ng-new后出现"Invalid source: undefined"的问题
问题根源
你碰到的这个错误,本质是后续调用的Angular官方Schematics(比如library)依赖projectName这个上下文变量,但它并没有自动从ng-new的执行流程中传递过来。Angular官方很多Schematics的schema里用了"$default": { "$source": "projectName" }来自动获取当前项目名,但在自定义Schematics的链式调用里,这个变量不会默认继承,所以就抛出了"Invalid source: undefined"的错误。
具体解决步骤
1. 从ng-new的执行结果中提取projectName
ng-new执行完之后,会生成angular.json文件,我们可以从这个文件里读取项目名称,这样比直接用传入的options.name更稳妥(毕竟用户可能在ng-new里改了名称参数):
import { chain, externalSchematic, Rule, Tree } from '@angular-devkit/schematics'; export function myFullSchematic(options: any): Rule { return chain([ // 先执行ng-new,创建基础工作区 externalSchematic('@schematics/angular', 'ng-new', { name: options.name, createApplication: false, // 如果只做库项目,建议关闭应用创建 skipGit: false, // 根据你的需求调整 // 其他ng-new需要的参数 }), // 这里用一个中间Rule来获取projectName,再执行后续操作 (tree: Tree) => { // 读取angular.json解析出项目名 const workspaceContent = tree.read('angular.json')!.toString(); const workspaceConfig = JSON.parse(workspaceContent); // 取第一个项目名,或者直接用options.name(如果确定不会变的话) const projectName = Object.keys(workspaceConfig.projects)[0]; // 链式执行后续的Schematics,显式传递projectName return chain([ externalSchematic('@schematics/angular', 'library', { name: `${options.name}-core`, // 你的库名称 projectName: projectName, // 关键:显式传入projectName // 其他library参数,比如prefix、skipTests等 }), // 你的自定义配置规则:替换Jest、添加CI配置等 setupJestConfig(projectName), addCIConfiguration(), ]); }, ]); }
2. 给所有依赖projectName的官方Schematics显式传参
不管是调用library、component还是其他官方Schematics,只要它的schema里用到了$source: projectName,就必须在externalSchematic的参数里明确传入projectName,不能依赖自动获取。
3. 自定义Schematics里统一从angular.json取项目名
如果你自己写的自定义规则也需要用到项目名,建议直接从angular.json读取,而不是依赖上下文变量,这样更稳定,避免上下文传递的问题。
你的方案可行性分析
完全可行!而且这是非常聪明的做法:
- 复用官方
@schematics/angular的逻辑,既能享受Angular官方的更新(比如新的配置项、修复的bug),又不用自己从零实现所有创建逻辑,只需要在官方基础上做自定义扩展。 - 后续用CI自动化测试也非常适配:你可以在CI流程里自动运行你的自定义Schematics生成项目,然后执行lint、测试、构建等步骤,确保每次依赖升级后功能都正常。
可选的替代思路
如果你觉得链式传递变量有点繁琐,也可以考虑两种替代方式,但都不如你当前的方案高效:
- 预定义模板文件:直接创建一个配置好Jest、CI的工作区模板,然后用Schematics复制模板并替换变量。但缺点是官方Schematics更新时,你得手动同步模板,维护成本高。
- 利用Schematics上下文传递变量:通过
context对象把projectName传递给后续规则,但这种方式需要对Angular Devkit的上下文机制有更深的理解,出错概率更高。
总的来说,你现在的思路是最优的,只需要补充提取并传递projectName的逻辑,就能解决这个错误。
内容的提问来源于stack exchange,提问作者Matt
相关产品推荐
相关产品推荐

