Serverless引入自定义JS脚本报错Cannot read property 'log' of undefined
报错原因
你在变量解析阶段通过${file(./scripts/myScript.js)}引入导出的JS函数时,Serverless Framework不会向这个函数传入完整的serverless实例对象,因此代码里拿到的第一个入参是undefined,调用serverless.cli.log自然会触发属性读取失败的报错。
只有编写Serverless自定义插件时,框架才会向构造函数传入完整的serverless实例,变量解析场景下的JS函数不支持获取该实例。
另外你当前的serverless.yaml本身存在配置错误:provider下定义了两个重复的name字段,第二个字段应该是stackName,重复key会导致配置解析异常,需要先修正。
修复方案
根据你的使用场景可以二选一:
方案1:仅需动态获取凭证、不需要调用Serverless内置方法
直接把需要用到的参数(比如stage)传入JS函数,不需要依赖serverless实例:
- 修改
myScript.js逻辑:
// 入参改为你需要用到的部署参数,不需要访问serverless实例 module.exports = async (stage) => { console.log('当前部署stage:', stage); // 这里写你的凭证生成逻辑,直接返回凭证内容即可 return { // 你的凭证字段 }; }
- 修改
serverless.yaml配置:
service: BATCH-lambda-f provider: name: aws # 修正重复的name字段,改为stackName stackName: serverless-fac-${opt:stage,self:provider.stage} runtime: nodejs12.x stage: develop custom: # 将stage作为参数传入JS函数 credentials: ${file(./scripts/myScript.js):${opt:stage,self:provider.stage}}
方案2:确实需要调用Serverless内置方法(比如打cli日志、获取provider配置)
改用自定义插件的形式实现你的逻辑:
- 修改
myScript.js为插件结构:
class CustomCredentialsPlugin { constructor(serverless, options) { this.serverless = serverless; this.options = options; // 绑定生命周期钩子,在打包前执行凭证生成逻辑 this.hooks = { 'before:package:initialize': this.injectCredentials.bind(this), }; } async injectCredentials() { this.serverless.cli.log('example'); const stage = this.serverless.getProvider('aws').getStage(); console.log(stage); // 生成凭证后直接写入provider配置中 this.serverless.service.provider.credentials = { // 你的凭证字段 }; } } module.exports = CustomCredentialsPlugin;
- 修改
serverless.yaml配置,移除custom.credentials配置,新增插件引用:
service: BATCH-lambda-f provider: name: aws stackName: serverless-fac-${opt:stage,self:provider.stage} runtime: nodejs12.x stage: develop # 引入自定义插件 plugins: - ./scripts/myScript.js
内容的提问来源于stack exchange,提问作者Uthred
相关产品推荐
相关产品推荐

