aspnetcore-vueclimiddleware
aspnetcore-vueclimiddleware copied to clipboard
example of setup with vite istead of vuecli?
I think it would be great if there was an example of how to setup with vite instead of vue-cli. it seems that the middleware is general enough that this should be possible.
I think the only change would be to the regex for whatever the export of Vite shows on the console when the web app is ready. Also, be sure to replace the contents of ClientApp
with a Vite app instead of vue-cli.
https://github.com/EEParker/aspnetcore-vueclimiddleware/blob/master/samples/Vue3/Startup.cs#L67
endpoints.MapToVueCliProxy(
"{*path}",
new SpaOptions { SourcePath = "ClientApp" },
npmScript: (System.Diagnostics.Debugger.IsAttached) ? "serve" : null, // make sure `serve` is the correct command
regex: "Compiled successfully", // change this to vite output
forceKill: true
);
At the moment without these two tickets I'm not sure how far you can get with this.
- https://github.com/vitejs/vite/pull/3115
- https://github.com/vitejs/vite/issues/3093
The HMR requires websockets to be proxied. You can use something like AspNetCore.Proxy to forward the websockets but there is no way to tell Vite the port to actually run the HMR (runtimePort) and what to use in the HTML (hmr port - need to be the proxy server port).
An alterative approach however is to use Vite's proxy feature and skip this plugin and continue to use AddSpaStaticFiles/UseSpaStaticFiles for production builds. You would need to start the SPA project separately and use those endpoints instead. This approach does require the proxy url to be different than the vite project.
Run this command or use alternative methods for generating a SSL certificate. I used the following msbuild target.
<Target Name="GetHttpsForLocal" BeforeTargets="Build">
<Exec WorkingDirectory="$(SpaRoot)" Command="dotnet dev-certs https -ep ./localhost-key.pfx -p dev-passphrase" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Failed to get localhost key" />
</Target>
vite.config.ts
import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import { readFileSync } from 'fs'
const key = readFileSync('localhost-key.pfx');
export default defineConfig({
plugins: [vue()],
server: {
https: {
pfx: key,
passphrase: 'dev-passphrase' // required for some reason -- maybe easier way?
},
proxy: {
'^/api/.*': {
target: 'https://localhost:5001',
rewrite: (path) => path.replace(/^\/api/, ''),
changeOrigin: true,
secure: false
},
'^/swagger': {
target: 'https://localhost:5001',
changeOrigin: true,
secure: false
}
}
}
})
So does this mean that all traffic goes through vite first, which forwards specific routes to dotnet while serving the vue routes directly? Are swagger supposed to go to dotnet?
What about vite for production build?
This tool is meant for development only and to facility HMR and other features. Production should serve the static files directly using standard AspNet static file methods.
I gave it a try and eventually hit a wall.
- Windows 10
- Node v14.16.0
- .net core 3.1
When using MapToVueCliProxy
I got the error message related to the port parameter as it tries to append port
to the npmScript
command:
info: VueCliMiddleware[0]
> echo Starting the development server && vite build --mode development "--port" "8080"
info: VueCliMiddleware[0]
Starting the development server
fail: VueCliMiddleware[0]
E:\vite-setup\vueapp\node_modules\vite\dist\node\cli.js:426
fail: VueCliMiddleware[0]
throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
fail: VueCliMiddleware[0]
^
fail: VueCliMiddleware[0]
CACError: Unknown option `--port`
To accommodate regex
changes for Vite (mentioned by @EEParker) I modified my npm script:
"build-dev": "echo Starting the development server && vite build --mode development"
.
I guess one of two things need to happen:
- VueCliMiddleware needs to stop appending --port param and assume that whatever is default will be used (port in VueCli and Vite configs and be changed), or
- ViteJS does add --port param to the command
I've got this mostly working now (albeit with Vue 2) due to the following 2 fixes in Vite:
- vitejs/vite#3578
- vitejs/vite#4332
In vite.config.js:
defineConfig({
///....
server: {
hmr: {
clientPort: 44308,
}
}
})
package.json:
"scripts": {
"dev": "vite",
"serve": "vite preview",
"build": "vite build"
}
Program.cs (or Startup.cs):
endpoints.MapToVueCliProxy(
"{*path}",
new SpaOptions { SourcePath = "ClientApp" },
npmScript: isDevelopement ? "dev" : null,
regex: "ready in .+ ms", //vite 3 doesn't show "running at" text anymore. "\d+ ms" doesn't work because of color formatting
port: 8080,
forceKill: true
);
However, quite often on the first run, a few of the requests from vite for certain components are failing. The requests make it to the vite proxy, but are failing with:
System.Net.Http.HttpRequestException: Failed to proxy the request to http://127.0.0.1:8080/src/XXXXXX.vue?vue&type=style&index=0&scoped=477d7e3e&lang.css, because the request to the proxy target failed. Check that the proxy target server is running and accepting requests to http://127.0.0.1:8080/.
The underlying exception message was 'An error occurred while sending the request.'.Check the InnerException for more details.
---> System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
---> System.Net.Sockets.SocketException (10054): An existing connection was forcibly closed by the remote host.
--- End of inner exception stack trace ---
etc etc
A refresh of the page and all works fine. I can't work out what the issue is.
I have it working just fine and I'm using vite3 with vuejs3 in my .NET 6 project. What I have:
vite.config.ts - I had to set server.host to true because of some VueCliMiddelware was pushing for 127.0.0.1 while vite was expecting localhost and I needed to set server.hmr.protocol to 'ws' for websocket:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server: {
host: true,
hmr: {
protocol: 'ws',
port: 52896
}
},
})
Program.cs (or Startup.cs) - like @yitzolsberg said, vite3 prints out ready in [x]ms so you gotta make VueCliMiddleware look for that:
spa.UseVueCli(npmScript: "dev", port: 3000, false, ScriptRunnerType.Npm, "ready in", true);
Hope this helps!