Asp.net 4.8 MVC + Vite + Svelte + HMR? - asp.net-mvc

I have a legacy application built in ASP.NET 4.8 MVC.
I would like to start building some client side features in Svelte - having svelte components rendering inside razor views. This I have working. I can render a svelte component anywhere in the razor page.
However vite has some problem (im guessing with HMR?), and it keeps refreshing the razor page (https://localhost:44300/somefeature) every few seconds.
Environment
asp.net 4.8 mvc loads to https://localhost:44300/
vite is loading on http://localhost:3000/
Here is what i have so far. I ran npm init vite#latest -> selected svelte + svelte TS
vite.config.js
import { defineConfig } from 'vite'
import { svelte } from '#sveltejs/vite-plugin-svelte'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
svelte({
compilerOptions: {
customElement: true,
}
})
],
build:{
// generate manifest.json in outDir
manifest: true,
rollupOptions: {
// overwrite default .html entry
input: '/src/main.ts'
}
}
})
Then i followed the instructions here https://vitejs.dev/guide/backend-integration.html and added this to the razor page:
#Html.Raw("<script type='module' src='http://localhost:3000/#vite/client'></script>")
<script type="module" src="http://localhost:3000/src/main.ts"></script>
(Note - had to use Html.Raw because it wouldnt let me escape the # correctly - even with ##)
At this point it is rendering my Svelte component perfectly.
The issue however is that vite is now reloading my page every 2 seconds or so - im guessing because HMR is no longer working correctly as the console just says: [vite] connecting...
Can anyone point me in a direction either to get HMR working whilst using another Backend server? For some reason it works in asp.net core, but not so in ASP.NET 4.8. Any observations to help?
Thanks in advance!

Ok i got it working. Here is my vite.config.js. Pay special attention to the
input, outDir and server nodes, and adjust them to your scenario. The proxy is important, you can either set it to your https or http mvc endpoint and port that asp.net spins up for you.
Here is the config:
export default defineConfig({
plugins: [
svelte()
],
build:{
// generate manifest.json in outDir
manifest: true,
rollupOptions: {
// overwrite default .html entry
input: 'Scripts/svelte/app.js',
},
outDir: 'Scripts/svelte/dist'
},
server: {
proxy:{
'*' : {
target: 'http://localhost:26688',
changeOrigin: true
}
},
hmr: {
protocol: 'ws'
}
}
})
Its pretty cool - you get instant HMR of any svelte component inside a razor page without losing any razor state.

THANK YOU!!!! This is exactly what I was looking for to include my react code in my old Asp.Net 4.8 site with hot module reload!
For other's the thing I had to include in my cshtml to make the react stuff load properly was:
<script type="module">
import RefreshRuntime from "http://localhost:9999/##react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>
If you don't include this you get an error saying '#vitejs/plugin-react can't detect preamble'.
I am hosting the development site in IIS locally so to serve up the local files, I just created a /src folder off of the root or my application pointing to the src in my react directory and it worked beautifullly!!

Related

How access environment variables from a Framework Components in Astro?

I'm working in a project using Astro and I am using a component with VUE. For this project I need to access some env vars.
I am able to access from the Astro templates, but I can't find a way to get in the VUE component. Is this possible?
There is no way to do this without exposing the environment variables.
To do this, we have to move the function to an endpoint of our API that runs on the server side and make a request to execute it safely.
You can expose the env var as data to the Vue component like so...
Vue 2
<script>
const { PUBLIC_ENV_HERE } = import.meta.env;
export default {
data() {
return {
PUBLIC_ENV_HERE,
};
},
};
</script>
Vue 3 with script setup
<script setup>
const { PUBLIC_ENV_HERE } = import.meta.env;
</script>
Remember to prefix client side variables with PUBLIC - see https://docs.astro.build/en/guides/environment-variables/ for more info.

Swagger UI : Failed to Load API Definition

I've deployed a simple Web API in net5 with swagger enabled (using default settings), which means in Startup.cs:
Configure Services method:
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyCompany.WebApi", Version = "v1" });
});
Configure method:
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyCompany.WebApi v1"));
And i deploy the same application to 2 Local IIS websites, the first as an application of the Default WebSite running on default port 80, as shown below:
And the second as a Separate WebSite node running on port 8085, as shown below:
Then for the second (hosted as a separate WebSite node), all works fine, so i can see my API definition:
But for the first, hosted as an application under the Default Web Site the API documentation can not be loaded:
Even though the swagger.json file is accessible:
So it look's like swagger is searching for the index.html to display the Swagger-UI in the "root" of the WebSite, and in the case of the first option where the application is hosted under the Default WebSite folder it can not find a way to display the swagger UI. Do we need to add something specific in the swagger definition in this case ?
Thx for any responses !
Emmanuel.
Did you tried this:
app.UseSwaggerUI(c => c.SwaggerEndpoint("swagger/v1/swagger.json", "MyCompany.WebApi v1"));
i removed beginning '/' from swagger json path.

Using VueJS in a ASP project

Currently developing a ASP MVC site.
Some sections of the site will use VueJS for displaying some list, forms etc.
The project setup is Bower, Grunt, standard C# ASP project using TypeScript.
This is my first time using Vue, and the simple stuff is pretty stragt forward. Seting up a page with a form, getting data from a WebService etc.
My problem/question is, what, and how, do i get the best setup, for using Single File Components (Vue) in my cshtml view files.
So, lets say I have a section on my site, where i want to display orders from the user.
Layout, navigation etc is setup by my excisting ASP code. I have a CSHTML viewpage for the current page, pretty vanilla:
#inherits MyViewPage<MyViewModel>
#{
Layout = "~/Views/layout.cshtml";
}
<div id"app">
</div>
Thats it for the excisting view page. In this page, i want to include a Vue Single File Component.
Previously i had the markup directly in the CSHTML page, which works fine. But when i want to user Vue-router, it becomes a problem to maintain the different views. So i should move the markup into a Component.
This is the basic setup;
const page1 = { template: '<div>Page1</div>' }
const page2 = { template: '<div>Page2</div>' }
const routes = [
{ path: '/', component: page1 },
{ path: '/page2', component: page2 }
]
const router = new VueRouter({
routes
})
var vm = new Vue({
router,
el: "#app"
})
Lets say i create a .vue file called page1.vue instead. This contains
<template>
my new page
</template>
<script>
export default {
name: '?',
date: function() {
}
}
</script>
How do i get this file included in my CSHTML file for instance?
You need to develop with webpack to build Single File Components.
See the Vue documentation on this.
Use the Vue Cli and drop a web pack build into your cshtml page.

How to configure create-react-pwa with nested homepage (localhost/app)

I create an app by create-react-pwa(CRP) tool and I deploy the app to a local IIS root path. Then I open Chrome at localhost. Everything works great, even Service worker makes its job, fetches and caches app bundle and other resources. In dev tool, I click on Add to homescreen button in Application tab and a shortcut is added.
There is a problem when I change the root path to a subfolder (localhost/myapp). Of course, I change CRP settings and edit homepage in the package.json and manifest.json
//package.json
"homepage" : "/myapp"
//manifest.json
"start_url": "/myapp/",
Then I build the app and edit a path to service-worker in index.html
<script>
"serviceWorker" in navigator && window.addEventListener("load", function () {
navigator.serviceWorker.register("/myapp/service-worker.js")
})
</script>
I deploy this build to IIS subfolder named "/myapp" and try to inspect result in Chrome. Everything works well, service-worker works. But when I try to Add to homescreen it fails. Chrome display the error bellow:
Site cannot be installed: no matching service worker detected. You may need to reload the page, or check that the service worker for the current page also controls the start URL from the manifest
Please, has someone idea what is wrong?
Build structure:
/wwwroot
/myapp
/static
/index.html
/manifest.json
/service-worker.js
/ etc...
You seem to have done everything correctly except one thing - not defining the scope of the service worker while registering. So there are two things you can try out:
1.Try explicitly adding the scope of the service worker while registration. Before making bigger efforts as described in option 2, check if this works for you. CODE:
<script>
"serviceWorker" in navigator && window.addEventListener("load", function () {
navigator.serviceWorker.register('/myapp/service-worker.js', { scope : '/myapp/' })
})
</script>
2.A full proof way would be this one. Since you are using IIS, you can make changes to your web.config file to add the Service-Worker-Allowed Http header to the response of your service worker file. CODE:
<location path="/myapp/service-worker.js">
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Service-Worker-Allowed" value="/" />
</customHeaders>
</httpProtocol>
</system.webServer>
</location>
and then just define the scope as {scope : '/'} while registering your service worker. This way irrespective of your project structure or placement of your service worker, it should work. Basically what you are doing now is that you are adding "Service-Worker-Allowed" header in HTTP response to the service worker's script resource request. This answer is inspired from the example 10 in the service worker's spec link above.
We were able to get this running on a tomcat server. We had to ensure that
1) The manifest.json, service-worker.js and the index.html reside in WEB-INF directory.
2) Set up a request mapping like to ensure that the manifest and service-worker are returned from the proper location
#RequestMapping(value = "/manifest.json", method = RequestMethod.GET)
public #ResponseBody InternalResourceView manifest() throws IOException {
return new InternalResourceView("/WEB-INF/manifest.json");
}
#RequestMapping(value = "/service-worker.js", method = RequestMethod.GET)
public #ResponseBody InternalResourceView serviceWorker() throws IOException {
return new InternalResourceView("/WEB-INF/service-worker.js");
}
3) We placed the assets from the build script inside resources/static/ directory and made sure that the resources to cache were supplied with proper names, like so, in the service-worker.js
const BASE_STATIC_URLS = [
'.',
'index.html',
'offline.html',
'/myapp/static/js/0.16823424.chunk.js'
];

Angular 2 - How to have different values of a var/const for different environments?

I am developing a Angular 2/Ionic 2 + JEE 7 project and I have a very specific scenario:
I have a httpClient layer that encapsulates every call to backend, there is a const named REST_BASE_PATHthat I would like to point to my localhost when in development environment and to a specific address when in production.
That said I would like to know what is the best and most automatic way of accomplish that..
You could define a custom request options to centralize this:
export class AppRequestOptions extends BaseRequestOptions {
constructor(private #Inject('webApiBaseUrl') webApiBaseUrl:string) {
}
merge(options?:RequestOptionsArgs):RequestOptions {
options.url = this.webApiBaseUrl + options.url;
return super.merge(options);
}
}
The webApiBaseUrl value you inject could be defined when bootstrapping your application:
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide('webApiBaseUrl', { useValue: 'https://bookapi.apispark.net/v1' })
]);
Set base url for angular 2 http requests
You need to update the variable when package your application with the value for the production environment.
Here is a question regarding packaging that could help you at this level:
How do I actually deploy an Angular 2 + Typescript + systemjs app?

Resources