使用azure-devops-node-api的Pulumi动态提供者序列化失败问题
解决Pulumi动态资源提供者序列化错误(azure-devops-node-api引用window变量)
问题根源
Pulumi动态资源提供者的代码会被序列化以在Pulumi运行时上下文执行,而azure-devops-node-api模块包含了浏览器环境的代码分支,其中引用了仅存在于浏览器的window变量。当顶层导入该模块时,模块对象会被提供者类的闭包捕获,序列化过程中检测到未定义的window变量,从而抛出错误。
解决方案
通过类型导入+动态运行时导入隔离模块加载,避免闭包捕获包含浏览器环境代码的模块对象,同时确保在Node.js环境下加载模块的Node.js适配版本:
- 顶层仅导入
azure-devops-node-api的类型(编译后会被移除,不影响运行时) - 在需要调用API的函数内部动态导入模块,确保运行时才加载且仅加载Node.js环境的代码
- 修正
updateBuildGeneralSettings的项目参数错误(原代码写死为"project",应传入实际项目名)
修改后的完整代码
import * as pulumi from '@pulumi/pulumi'; // 仅导入类型,编译后不会包含运行时代码 import type * as azdev from 'azure-devops-node-api'; export interface ProjectPipelineSettingsResourceInputs { organization: pulumi.Input<string>; orgServiceUrl: pulumi.Input<string>; project: pulumi.Input<string>; auditEnforceSettableVar: pulumi.Input<boolean>; } interface ProjectPipelineSettingsInputs { organization: string; orgServiceUrl: string; project: string; auditEnforceSettableVar: boolean; } interface ProjectPipelineSettingsOutputs extends ProjectPipelineSettingsInputs { id: string; } class ProjectPipelineSettingsProvider implements pulumi.dynamic.ResourceProvider { private async getWebApiClient(orgServiceUrl: string): Promise<azdev.WebApi> { // 动态导入模块,仅在运行时加载,避免闭包捕获 const { WebApi, getPersonalAccessTokenHandler } = await import('azure-devops-node-api'); const token = process.env.AZDO_PERSONAL_ACCESS_TOKEN; if (!token) { throw new Error('AZDO_PERSONAL_ACCESS_TOKEN is not set'); } const authHandler = getPersonalAccessTokenHandler(token); return new WebApi(orgServiceUrl, authHandler); } async create( inputs: ProjectPipelineSettingsInputs ): Promise<pulumi.dynamic.CreateResult<ProjectPipelineSettingsOutputs>> { const connection = await this.getWebApiClient(inputs.orgServiceUrl); const buildApiClient = await connection.getBuildApi(); // 修正项目参数:传入实际项目名而非字符串"project" const result = await buildApiClient.updateBuildGeneralSettings( { auditEnforceSettableVar: inputs.auditEnforceSettableVar }, inputs.project ); const generatedId = `${inputs.organization}-${inputs.project}`.replace(/\s/g, '-').toLowerCase(); return { id: generatedId, outs: { id: generatedId, ...inputs, ...result } }; } } export class ProjectPipelineSettings extends pulumi.dynamic.Resource { readonly organization!: pulumi.Output<string>; readonly orgServiceUrl!: pulumi.Output<string>; readonly project!: pulumi.Output<string>; readonly auditEnforceSettableVar!: pulumi.Output<boolean>; constructor( name: string, args: ProjectPipelineSettingsResourceInputs, opts?: pulumi.CustomResourceOptions ) { super(new ProjectPipelineSettingsProvider(), name, args, opts); } }
验证修改
修改后执行pulumi up,Pulumi序列化提供者代码时不会再捕获到包含window引用的模块对象,同时动态导入确保模块在Node.js环境下加载正确的适配层,错误会被解决。
内容的提问来源于stack exchange,提问作者arodin
相关产品推荐
相关产品推荐

