Eptagone / Vite.AspNetCore

Small library to integrate Vite into ASP.NET projects
MIT License
264 stars 35 forks source link

Could not copy the file "<full path js file>" because it was not found #89

Open luysantana opened 10 months ago

luysantana commented 10 months ago

When I try to publish my app to a folder (trying to execute localhost to sure that It will works on production), I have the error in title for every entry file.

It's strange, because when I comment csproj, publish, uncomment csproj and publish, the publish occurs for once, but fail for next ones:

 <!--Build the final assets--> 
<Target Name="PublishBuildAssets" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Release' ">
     <!--Build the final assets--> 
    <Exec Command="npm run prd" />
</Target>

Analyzing the build log, I see that npm run prd occurs 2 times, one before build and one before publish, I think the files are recreated with another name and msbuild loses the references.

I have try like this:

<Target Name="NpmInstall" Inputs="package.json">
    <Exec Command="npm install" />
</Target>

<Target Name="NpmRunBuild" DependsOnTargets="NpmInstall" BeforeTargets="BeforeBuild" >
    <Exec Command="npm run prd" />
</Target>

But like the first one, It fails after the first time. Another thing is for the first publish, It's doesn't load js and css files. The console shows that the manifest file doesn't exists, but exists in the folder.

I have this configuration:


/**
 * Name: vite.config.ts
 * Description: Vite configuration file
 */

import { defineConfig } from "vite";
import { spawn } from "child_process";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import { glob }from "glob";

// Get base folder for certificates.
const baseFolder =
    process.env.APPDATA !== undefined && process.env.APPDATA !== ""
        ? `${process.env.APPDATA}/ASP.NET/https`
        : `${process.env.HOME}/.aspnet/https`;

// Generate the certificate name using the NPM package name
const certificateName = process.env.npm_package_name;

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

// Export Vite configuration
export default defineConfig(async () => {
    // Ensure the certificate and key exist
    if (!fs.existsSync(certFilePath) || !fs.existsSync(keyFilePath)) {
        // Wait for the certificate to be generated
        await new Promise((resolve) => {
            spawn("dotnet", [
                "dev-certs",
                "https",
                "--export-path",
                certFilePath,
                "--format",
                "Pem",
                "--no-password",
            ], { stdio: "inherit", })
                .on("exit", (code) => {
                    resolve();
                    if (code) {
                        process.exit(code);
                    }
                });
        });
    };

    // Define Vite configuration
    const config = {
        appType: "custom",
        root: "wwwroot/src",
        build: {
            emptyOutDir: true,
            manifest: true, 
            outDir: "../dist",
            assetsDir: "",
            rollupOptions: {
                input: Object.fromEntries(
                    glob
                        .sync("./wwwroot/src/**/js/[^_]*.js")
                        .map(file => [file.split("\\")[file.split("\\").length - 1], fileURLToPath(new URL(file, import.meta.url))]),
                ),
            },
        },
        server: {
            strictPort: true,
            https: {
                cert: certFilePath,
                key: keyFilePath
            }
        },
        optimizeDeps: {
            include: []
        }
    }

    return config;
});

Program.cs

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddViteServices(opt =>
{
    opt.Server.AutoRun = true;
    opt.Server.Https = true;
    opt.Manifest = "wwwroot/dist/.vite/manifest.json";
});

//...

var app = builder.Build();

if (app.Environment.IsEnvironment("production"))
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

//...

if (app.Environment.IsEnvironment("DEBUG"))
{
    app.UseViteDevelopmentServer(true);
    app.UseDeveloperExceptionPage();
}

app.Run();

cshtml files (this is layout.cshtml, but the others follow the same)

<link rel="stylesheet" vite-href="~/layout/js/layout.js" asp-append-version="true" />
<script type="module" vite-src="~/layout/js/layout.js" asp-append-version="true"></script>

I try to do what the Wiki says, but I think that doesn't affect the publish process This is after vite build image

I'm using VS2022 17.8.5 dotnet 8.0.101 the app uses version 7 of sdk

Deepfreezed commented 10 months ago

Yes, I experienced this as well. I am not sure if it's related the VS publishing process with npm build or Vite.AspNetCore. It does work if I update the project file like mentioned but fails subsequent tries.

Eptagone commented 9 months ago

It runs two times because you have the tasks PublishBuildAssets and NpmRunBuild to run the same command, the first one runs before Build and the second runs before BeforeBuild. So, the order is:

And also, I can see you are using a base directory. Your base directory should be configured to /dist/ in your vite.config.ts and also in your program.cs file. You can see an example in the Wiki.

I see you have "wwwroot/dist/.vite/manifest.json" as your manifest name. The manifest name is relative to your wwwroot folder and base directory which is dist. Your manifest name is .vite/manifest.json which is the default value, so you can omit it. You should have something like this:

builder.Services.AddViteServices(opt =>
{
    opt.Server.AutoRun = true;
    opt.Base = "/dist/";
    opt.Server.Https = true;
});

I also suggest you move your assets in wwwroot/src to another folder like Client, Assets, etc. Otherwise, those files will also copied on publish. You don't want that, do you?

Deepfreezed commented 8 months ago

I was still running into this issue on publish. You need to run npm run build command on 'Publish'. If you run it on 'Build' it will build twice and mess-up the wwwroot file copy references.

Or if it still does not work, just build npm before publish so the manifest is there and ignore npm commands in Visual Studio.

<!-- Ensure Node.js is installed -->
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build;Publish;PublishBuildAssets" Condition=" !Exists('node_modules') ">
  <Exec Command="node --version" ContinueOnError="true">
    <Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
  </Exec>
  <Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
  <Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
  <Exec Command="npm install" />    
</Target>  

<Target Name="PublishBuildAssets" BeforeTargets="Publish" Condition=" '$(Configuration)' == 'Release' ">
  <Exec Command="npm run build" />
</Target>