reactjs.netazure-pipelinesvite

Vite - Azure pipelines | React .NET - There was an error exporting the HTTPS developer certificate to a file


When trying to push my react .net project my npx vite build fails

The error message in question:

There was an error exporting the HTTPS developer certificate to a file.
error during build:
Error: Could not create certificate.
    at file:///D:/a/1/s/name.client/vite.config.ts.timestamp-1730192939030-060bc963903a.mjs:24:11
    at ModuleJob.run (node:internal/modules/esm/module_job:234:25)
    at async ModuleLoader.import (node:internal/modules/esm/loader:473:24)
    at async loadConfigFromBundledFile (file:///D:/a/1/s/name.client/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:66634:15)
    at async loadConfigFromFile (file:///D:/a/1/s/name.client/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:66475:24)
    at async resolveConfig (file:///D:/a/1/s/name.client/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:66083:24)
    at async build (file:///D:/a/1/s/name.client/node_modules/vite/dist/node/chunks/dep-CDnG8rE7.js:65180:18)
    at async CAC.<anonymous> (file:///D:/a/1/s/name.client/node_modules/vite/dist/node/cli.js:828:5)

Pipeline:

pr:
  - Development
  - master

pool:
  vmImage: "windows-latest"

variables:
  buildConfiguration: "Release"
  buildPlatform: "any cpu"

steps:
  - checkout: self
    fetchDepth: 0
  - task: NuGetToolInstaller@1

  - task: UseDotNet@2
    inputs:
      packageType: 'sdk'
      version: '8.x' # Ensure this matches your project's .NET version
      installationPath: $(Agent.ToolsDirectory)/dotnet
    displayName: 'Install .NET SDK'

  - task: NuGetCommand@2
    displayName: "NuGet restore"
    inputs:
      restoreSolution: "name.sln"

  - task: SonarCloudPrepare@1
    inputs:
      SonarCloud: "namename"
      organization: "name-test1"
      scannerMode: "MSBuild"
      projectKey: "namenamepass"
      projectName: "name"


  - task: VSBuild@1
    displayName: 'Build solution **\*.sln'
    inputs:
      solution: "name.sln"
      platform: "$(BuildPlatform)"
      configuration: "$(BuildConfiguration)"

  - task: VSTest@2
    displayName: "VsTest - testAssemblies"
    inputs:
      testAssemblyVer2: |
        **\$(BuildConfiguration)\*Test*.dll
        !**\obj\**
      codeCoverageEnabled: true
      platform: "$(BuildPlatform)"
      configuration: "$(BuildConfiguration)"

  - task: SonarCloudAnalyze@1
    displayName: "Run SonarCloud analysis"

  - task: SonarCloudPublish@1
    displayName: "Publish results on build summary"

vite config:

import { fileURLToPath, URL } from "node:url";

import { defineConfig, UserConfig } from "vite";
import plugin from "@vitejs/plugin-react";
import fs from "fs";
import path from "path";
import child_process from "child_process";
import mkcert from "vite-plugin-mkcert";
const isCI = process.env.CI === 'true' || process.env.AZURE_PIPELINE === 'true';
const baseFolder =
    process.env.APPDATA !== undefined && process.env.APPDATA !== "" ? `${process.env.APPDATA}/ASP.NET/https` : `${process.env.HOME}/.aspnet/https`;

//@ts-ignore
const certificateArg = process.argv.map((arg) => arg.match(/--name=(?<value>.+)/i)).filter(Boolean)[0];
const certificateName = certificateArg ? certificateArg.groups.value : "name.client";

if (!certificateName) {
    console.error("Invalid certificate name. Run this script in the context of an npm/yarn script or pass --name=<<app>> explicitly.");
    process.exit(-1);
}

const certFilePath = path.join(baseFolder, `${certificateName}.pem`);
const keyFilePath = path.join(baseFolder, `${certificateName}.key`);

if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
    if (
        0 !==
        child_process.spawnSync("dotnet", ["dev-certs", "https", "--export-path", certFilePath, "--format", "Pem", "--no-password"], {
            stdio: "inherit",
        }).status
    ) {
        throw new Error("Could not create certificate.");
    }
}

const configLocal : UserConfig  = {
    plugins: [plugin(), mkcert()],
    resolve: {
        alias: {
            "@": fileURLToPath(new URL("./src", import.meta.url)),
        },
    },
    server: {
        proxy: {
            "^/weatherforecast": {
                target: "https://localhost:7293/",
                secure: false,
            },
        },
        port: 5173,
        https: {
            key: fs.readFileSync(keyFilePath),
            cert: fs.readFileSync(certFilePath),
        },
    },
}
const configServer : UserConfig  = {
    plugins: [plugin(), mkcert()],
    resolve: {
        alias: {
            "@": fileURLToPath(new URL("./src", import.meta.url)),
        },
    },
    server: {
        proxy: {
            "^/weatherforecast": {
                target: "https://localhost:7293/",
                secure: false,
            },
        },
        port: 5173,
    },
}

export default defineConfig(isCI ? configServer : configLocal);


Solution

  • I can reproduce the same issue when using vite + asp.net project.

    enter image description here

    The issue can be related to the .NET8 version used in the Pipeline.

    In your Pipeline definition, it will use the .net8 version: 8.0.403 (Set version via UseDotNet task). When creating the certificate, if the .aspnet/https folder does not exist, it will not be automatically created.

    To solve this issue, you can downgrade the .Net version to 8.0.402.

    For example:

    steps:
      - checkout: self
        fetchDepth: 0
      - task: NuGetToolInstaller@1
    
      - task: UseDotNet@2
        inputs:
          packageType: 'sdk'
          version: '8.0.402' # Ensure this matches your project's .NET version
          installationPath: $(Agent.ToolsDirectory)/dotnet
        displayName: 'Install .NET SDK'
    

    Result:

    enter image description here

    For more detailed info, you can refer to this ticket: Pipeline Error on SPA Project There was an error exporting the HTTPS developer certificate to a file