Appearance
XCon Studio Vite Proxy (.NET)
XCon Studio Vite Proxy is a middleware that provides seamless integration with Vite development server in ASP.NET Core applications. It automatically starts, manages and proxies the Vite server during development.
⚠️ Note: This middleware only works in Development environment. A separate build system is used for production.
🚀 Installation
Installation with NuGet
bash
# With .NET CLI
dotnet add package XConViteProxy
# In Package Manager Console
Install-Package XConViteProxyNuGet Package: https://www.nuget.org/packages/XConViteProxy
Package Reference
xml
<PackageReference Include="XConViteProxy" Version="1.0.31" />🎯 Quick Start
Program.cs Configuration (Recommended Usage)
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container
builder.Services.AddControllersWithViews();
// Add Razor runtime compilation for hot reload
if (builder.Environment.IsDevelopment())
{
builder.Services.AddRazorPages()
.AddRazorRuntimeCompilation();
}
// XCon Vite Proxy hosted service
builder.Services.AddXConViteProxy();
var app = builder.Build();
// Configure the HTTP request pipeline
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
else
{
// XCon Vite Proxy Middleware - MUST be before UseStaticFiles
app.UseXConViteProxy(app.Environment);
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();Important Points:
- ✅
AddXConViteProxy()adds the service to DI - ✅
UseXConViteProxy()middleware should be added BEFORE UseStaticFiles() - ✅ Hot reload support with Razor Runtime Compilation
- ✅ Only active in Development environment
That's it! Now when you press F5:
- Vite dev server starts automatically
/scripts/*requests are routed to Vite- HMR (Hot Module Replacement) works
- Razor views also update with hot reload
- Vite closes automatically when the application closes
Usage with Custom Port
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
// Custom Vite server URL
app.UseXConViteProxy(app.Environment, "http://localhost:5173");
app.Run();⚙️ Automatic Configuration
The middleware automatically performs the following steps:
1. Reading Dev Script from package.json
json
{
"scripts": {
"dev": "vite --config vite.config.dev.js"
}
}2. Parsing Vite Config File
javascript
// vite.config.dev.js
export default defineConfig({
root: path.resolve(__dirname, 'scripts'),
server: {
port: 4201
}
});3. Automatic Detection
The middleware automatically detects:
- ✅ Vite config file path (from
--configparameter) - ✅ Root folder (from
root:setting) - ✅ Port number (from
port:setting) - ✅ Development command (
npm run dev)
🔧 Working Principle
Vite Server Management
csharp
// Middleware does the following:
// 1. At Startup
- Reads package.json
- Parses Vite config
- Runs `npm run dev` command
- Waits for Vite to be ready
// 2. At Runtime
- Captures requests to Vite root path
- Proxies to Vite server
- Adds CORS headers
- Routes HMR websocket connections
// 3. At Shutdown
- Cleans up Vite process
- Terminates child processes
- Releases resourcesProcess Safety (Windows)
Process safety is ensured using Job Object on Windows:
csharp
// Windows Job Object features:
- Vite closes automatically if main process crashes
- No orphan processes remain
- No resource leaks
- Clean shutdown guarantee🗂️ Project Structure
A typical ASP.NET Core + Vite project:
MyWebApp/
├── Program.cs # ASP.NET Core entry point
├── appsettings.json
├── MyWebApp.csproj
├── package.json # npm/vite configuration
├── vite.config.dev.js # Vite development config
├── scripts/ # Vite root folder
│ ├── src/
│ │ ├── main.ts
│ │ ├── components/
│ │ │ ├── my-widget/
│ │ │ │ ├── my-widget.ts
│ │ │ │ ├── my-widget.html
│ │ │ │ └── my-widget.css
│ │ └── app.ts
│ ├── index.html
│ └── vite-env.d.ts
└── wwwroot/
└── index.html # ASP.NET static files⚠️ Important: Middleware Ordering
Critical: UseXConViteProxy() middleware MUST be added BEFORE UseStaticFiles()!
✅ Correct Ordering
csharp
if (builder.Environment.IsDevelopment())
{
// 1. FIRST Vite Proxy
app.UseXConViteProxy(app.Environment);
app.UseDeveloperExceptionPage();
}
// 2. THEN Static Files
app.UseStaticFiles();
app.UseRouting();❌ Wrong Ordering
csharp
// WRONG! If static files come first, Vite proxy won't work
app.UseStaticFiles();
app.UseXConViteProxy(app.Environment); // Never called!Why? Middlewares run in order. If UseStaticFiles() finds a file in the /scripts folder, it terminates the request and never reaches the Vite proxy.
📋 Supported Features
Automatic Proxy Paths
The middleware automatically proxies these paths:
csharp
// Vite root path
/scripts/* → Vite server
// Vite special paths
/@vite/* → Vite internal
/@fs/* → File system access
/node_modules/* → Dependencies
/@id/* → Module IDs
// Vite file types
*.ts, *.tsx, *.jsx, *.js → TypeScript/JavaScript
*.css, *.scss, *.less → Styles
*.vue, *.svelte → Framework filesCORS Support
Automatic CORS headers are added:
csharp
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type🚀 Usage Examples
Basic MVC Application
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
// MVC services
builder.Services.AddControllersWithViews();
// Razor runtime compilation (for hot reload)
if (builder.Environment.IsDevelopment())
{
builder.Services.AddRazorPages()
.AddRazorRuntimeCompilation();
}
// XCon Vite Proxy hosted service
builder.Services.AddXConViteProxy();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
}
else
{
// IMPORTANT: Vite proxy must be BEFORE UseStaticFiles
app.UseXConViteProxy(app.Environment);
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();With Razor Pages
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
var app = builder.Build();
// Vite proxy (development only)
app.UseXConViteProxy(app.Environment);
app.MapRazorPages();
app.Run();API + SPA (Vite) Structure
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
// API services
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Development middlewares
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
// Vite dev server proxy
app.UseXConViteProxy(app.Environment);
}
// API endpoints
app.MapControllers();
// SPA fallback
app.MapFallbackToFile("index.html");
app.Run();Adding Custom Vite Service
csharp
using XCons.ViteProxy;
var builder = WebApplication.CreateBuilder(args);
// Manually add Vite proxy service
builder.Services.AddXConViteProxy();
var app = builder.Build();
// Middleware usage
if (app.Environment.IsDevelopment())
{
app.UseXConViteProxy(app.Environment, "http://localhost:4201");
}
app.Run();📝 Console Output and Logging
Vite Output
Vite server outputs appear in console:
bash
XCon Vite Proxy: Starting Vite dev server...
XCon Vite Proxy: Vite dev server started successfully
XCon Vite Proxy: Using Vite root path: /scripts
[Vite] VITE v5.0.0 ready in 500 ms
[Vite] ➜ Local: http://localhost:4201/
[Vite] ➜ Network: use --host to exposeProxy Logging
bash
XCon Vite Proxy: Service constructed, URL: http://localhost:4201
XCon Vite Proxy: Detected port from config: 4201
XCon Vite Proxy: Detected root: /scripts
XCon Vite Proxy: Vite started (PID: 12345)
XCon Vite Proxy: Vite process (PID: 12345) assigned to Job Object ✓
XCon Vite Proxy: Child will be killed automatically when parent dies
XCon Vite Proxy: Vite ready ✓Error Situations
bash
# Config not found
XCon Vite Proxy: package.json not found
XCon Vite Proxy: Using default: /scripts, port: 4201
# Vite could not be started
XCon Vite Proxy: Failed to start Vite process
XCon Vite Proxy: Error: npm not found in PATH
# Proxy error
XCon Vite Proxy: Proxy error: Connection refused
HTTP 502: Vite proxy error: Unable to connect to Vite server🛠 Troubleshooting
Problem: Vite Server Not Starting
Solution:
bash
# Make sure Node.js and npm are installed
node --version
npm --version
# Check that dev script exists in package.json
npm run dev
# Make sure dependencies are installed
npm installProblem: Port Conflict
Solution:
csharp
// Use custom port
app.UseXConViteProxy(app.Environment, "http://localhost:5173");Or change port in vite.config.js:
javascript
export default defineConfig({
server: {
port: 5173 // Different port
}
});Problem: Hot Reload Not Working
Solution:
javascript
// vite.config.js - HMR settings
export default defineConfig({
server: {
port: 4201,
hmr: {
protocol: 'ws',
host: 'localhost',
port: 4201
}
}
});Problem: CORS Errors
Solution:
csharp
// Middleware automatically adds CORS headers
// If problem persists:
app.UseCors(policy =>
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseXConViteProxy(app.Environment);Problem: Process Not Closing (Orphan Process)
Solution: Job Object works automatically on Windows. If you experience issues:
powershell
# Clean orphan Vite processes
Get-Process | Where-Object {$_.ProcessName -like "*node*"} | Stop-Process -Force⚙️ Advanced Configuration
Multiple Vite Instances
csharp
// For main widgets
app.UseXConViteProxy(app.Environment, "http://localhost:4201");
// Another Vite for admin panel
app.UseMiddleware<XConViteMiddleware>("/admin-scripts", "http://localhost:4202");Custom Path Matching
csharp
public class CustomViteMiddleware : XConViteMiddleware
{
public CustomViteMiddleware(RequestDelegate next, string viteRootPath)
: base(next, viteRootPath) { }
protected override bool ShouldProxyToVite(string path)
{
// Custom path logic
return path.StartsWith("/custom-path") ||
base.ShouldProxyToVite(path);
}
}Conditional Vite Startup
csharp
var builder = WebApplication.CreateBuilder(args);
// Add Vite service
builder.Services.AddXConViteProxy();
var app = builder.Build();
// Start only under certain conditions
if (app.Environment.IsDevelopment() &&
builder.Configuration.GetValue<bool>("EnableVite"))
{
app.UseXConViteProxy(app.Environment);
}
app.Run();🔒 Security Notes
Development-Only Usage
csharp
// ✅ Correct - Only in development
if (app.Environment.IsDevelopment())
{
app.UseXConViteProxy(app.Environment);
}
// ❌ Wrong - Don't use in production
app.UseXConViteProxy(app.Environment); // Always runs!Safe Port Management
csharp
// Read from appsettings.Development.json
var viteUrl = builder.Configuration["Vite:Url"] ?? "http://localhost:4201";
if (app.Environment.IsDevelopment())
{
app.UseXConViteProxy(app.Environment, viteUrl);
}Process Safety
csharp
// Process safety with Job Object (Windows)
// - Prevents orphan processes
// - Prevents resource leaks
// - Clean shutdown guarantee
// Process cleanup also works on Linux/macOS
// ViteDevServerService.Dispose() does automatic cleanup💡 Tip: With XCon Vite Proxy, the ASP.NET Core + Vite development experience becomes extremely simple. All you need to do is add the line
app.UseXConViteProxy(app.Environment);- everything else is automatic!