NuxtJS 2 Routing and Template / Components challenge - vuejs2

Hei guys,
I'm having some trouble with my current project. I wish to achieve the following project that must answer this needs :
Have a config JSON with information about the project/projects, static pages, and other general information about the client
Have a main landing page. This page is optional. If this is not set/wanted and if in the config there is only 1 project, then on the base domain the page should be the project
Each static page is built using sections that are found in the config file
Some examples:
Case 1:
In the config, we have a client with 2 projects and no landing page. The routing should be:
domain.ex/project1 -> project template with dynamic sections
domain.ex/project2 -> project template with dynamic sections
Case 2:
We have a client with 1 project and no landing page in the config. The routing should be:
domain.ex -> project template with dynamic sections
Case 3:
We have a client with 1 project and a landing page in the config. The routing should be:
domain.ex -> static page with dynamic sections
domain.ex/project1 -> project template with dynamic sections
What is the best way of doing this in NujtJS? I was thinking either by using a router middleware and changing the page base component based on the config, or by creating manual routes in the nuxt config and redirecting in the route middleware from one to another (but losing Case 2)
Also, I would like to have a decent code splitting

Related

Only Map existing Blazor Pages(Razor Components) in the pipeline?

The usual pattern for Blazor (server) apps, is that at the end pf program.cs there is app.MapFallbackToPage("/_Host");
That will result in ALL request paths, that match no earlier endpoint, executing the Blazor App. Sure the Blazor App has a <NotFound> Renderfragment, but that will still result in establishing the SignalR and so on. What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
NavigationManager.NavigateTo cannot be used directly inside the BuildRenderTree markup of the <NotFound> ... I could maybe put a component inside there that redirects OnInitialized ... but that would still first require the SignalR.
How can I completely avoid Blazor/SignalR for URLs that don't exist in the Blazor App ?
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
app.MapFallbackToPage("~/Admin/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomeRoute/More/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("~/SomePage/{*clientroutes:nonfile}", "/_Host");
app.MapFallbackToPage("/NotValidRoute");
Edit:
#Reason:
I wanted to have a single fallback page (razor page or static) for all routes/urls that don't match any target in the app. But sadly as it seems, that conflicts with blazor'S client side routing. since the server-side routing does not know, which routes should be handled by blazor, it also cannot know, which routes would not map to anything (razor pages and blazor combined). Other please correct me here.
There's server-side routing and client-side routing. On the server side, the middleware pipeline runs first, handling static files and server defined routes, including the fallback route. Fallback routes are routes that don't match static file requests and have the lowest priority, so they are not preferred over other matching routes.
Server-side routing has no idea what routes are going to match on the client-side. That data model is separate. What's happening is, when no server route matches, the host page is rendered, which bootstraps the client. Now you've transitioned to client-side routing and cannot re-enter (without a change to refresh the browser)
What if I want to display a static file (.html) from wwwroot or a specfic RAZOR PAGE (.cshtml), which doesnt establlish a websocket for all those cases where the route does NOT EXIST IN ANY BLAZOR PAGE ???
That requires knowing what routes exists on the client.
Idea: I could try to add ALL POSSIBLE Blazor-routes as fallbacks and the most general fallback to some static file or Razor Page... but that seems LIKE A LOT OF DOUBLE WORK and very error prone... is there no way?
Possible using the <NotFound> component to run some JavaScript and redirect the browser to a fixed route on the server.
Edit:
Another would be to build that found all routable razor components and map them all as fallback routes to "_Host".
Something like this (untested):
// This should match wherever components are declared.
var types = typeof(Program).Assembly.GetTypes();
foreach (var type in types)
{
if (typeof(ComponentBase).IsAssignableFrom(type) && type.GetCustomAttribute<RouteAttribute>() is { } routeAttribute)
{
var route = routeAttribute.Template;
endpointRouteBuilder.MapFallbackToPage(route, "/_Host");
}
}
It partly depends on how your app is hosted. In IIS, you can add applications to any website, which are basically websites of any type you want with a "/path" added.
Currently, my company's main app is "ABCsite.com," and my Blazor app is "ABCsite.com/Blazor"

Why doesn't my nuxt static site serve the static html files found in the Dist folder?

I've created a blog with Nuxt that has dynamic routes for each of my articles (articles/_slug.vue). Inside the _slug.vue file I grab markup content from a strapi CMS using asyncData.
aricles/_slug.vue
After running nuxt generate followed by nuxt start and navigating to an article page in my browser, when I open the page source I find that there are numerous Js files being imported /_nuxt/{randomNumbers}.js and a single div with an id __nuxt , most likely resembling an SPA format.
page source of an article
This does not occur with my index.vue page as when I view the page source for index.vue all my content is in the HTML.
Its important that the google crawler is able to index the content on my article pages, so the page source not containing the blog content is not ideal.
What I don't understand is that when I open the dist folder generated by nuxt I find all my articles in subfolders containing HTML files hard coded with my blog content. So I am wondering why isn't nuxt serving these HTML files , and is there a way to do so ?
distFolder
As far as I know all pages and components go in one component called Nuxt and I think the "__nuxt" element is that. By the way using asyncData and 'nuxt generate' won't make your app server-side dynamic because 'nuxt generate' generates a static site and while using 'nuxt generate' all asyncData hooks will be called once. For the hard coded blog posts I think you should disable Nuxt Crawler in your nuxt.config.js.
Nuxt Docs: The Generate Property #Crawler
export default {
generate: {
crawler: false
}
}
It seems as though after hosting the project on Vercel the static behavior works accordingly. When testing the website locally (nuxt start) the content isn't pre loaded into the page source it continues to act as a SPA on dynamic routes. However after deploying to Vercel the blog content can be found in page source.

How to host Blazon in Razor Pages application

The "standard" Blazor WASM application is hosted inside a static HTML page; e.g., index.html. Due to certain requirements, I want to host Blazor inside a Razor pages application.
What I did is starting from a "standard" Blazor WASM application, removed the static files, because I do not need them, moved the content of index.html to the Wasm.cshtml, and change endpoints.MapFallbackToFile("index.html"); to endpoints.MapFallbackToPage("/Wasm");.
Everything seemed to be working as expected; I can run the application and navigate to the different pages I have in Blazor.
However, things fall apart when I try to access a page using its URL; e.g., http://mysite/counter, where /counter is a page in Blazor, and I get the following error:
An unhandled exception occurred while processing the request.
AmbiguousMatchException: The request matched multiple endpoints. Matches:
/Wasm
/Wasm
Can someone help me identify what I am doing wrong?
P.S.:
I looked at some answer here, but all that I found is people talking about Blazor Server.
I am using .NET 3.1 and Blazor 3.2.
I want to use my Razor Pages application to host/serve Blazor WASM not mixing them in a single project. They as still 2 different projects.
I am totally aware that Blazor WASM and Razor Pages are unrelated technologies. I am not trying to integrate them. I am only trying to server Blazor WASM files from a dynamic page. If it makes you think better about what I am trying to achieve, think about Razor Pages as any server-side technology; PHP, Node, or whatever, then apply this to the routing issue that I am trying to resolve.
OK, based on what you've written so far take a look at ShaunCurtis/Blazor-Experimental on Github. It's a temporary Repo for some experimental code. Ignore BlazorTest. The startup project is Blazor-Experimental.
The default page is a normal razor page. It's a mixed Razor, Blazor Server and Blazor WASM site. All the WASM routes look like wasm/fetchdata, so we have different URLs for all the Server and WASM "Pages".
Startup differentiates URLs using multiple endpoints, so any URL that is in the "scope" of the Blazor WASM application gets set to _wasm.cshtml. Anything else that can't be mapped directly is in the "scope" of the Blazor Server Application at _host.cshtml. All plan Razor pages on the site get served as is. You don't need the Blazor Server bit at all, just fallback to the default Razor page.
endpoints.MapFallbackToPage("/wasm/{**segment}", "/_wasm");
endpoints.MapFallbackToPage("/_Host");
To summarise the answer:
Create a Blazor WASM project. You can copy the one from Blazor Hosted template.
Reference the project from the Razor Pages project.
Create the page that will host Blazor WASM; e.g., Wasm.cshtml, and make sure the page route is not set; i.e., only #page at the top of the page, so that it takes the default route /wasm.
Copy the code from index.html in the Blazor WASM project into Wasm.cshtml.
Important: If you are using your own layout, it is important to have <base href="/" /> on the page or the layout <head> section.
Remove all the static files from form the Blazor WASM project; e.g., index.html.
Remove all *.razor pages from the Blazor WASM project.
Add Wasm.razor to the Blazor WASM project and set its route to /wasm; i.e., #page "/wasm".
In Startup.cs in the Razor Pages project, add app.UseBlazorFrameworkFiles(); after app.UseStaticFiles();.
Also in the same Startup.cs, add endpoints.MapFallbackToPage("/wasm/{**segment}", "/wasm"); inside app.UseEndpoints() lambda.
Now run the application and navigate to /wasm. You should see the content of your Wasm.razor in addition to whatever layout you have set. You will get the same result when you paste the URL http://whateveryoursiteis/wasm.
You give very little information, so I'll have to make a number of guesses.
I guess you based your WASM integration on the Blazor WASM ASP.NET hosted template. That template consists of three projects: The .Client project, the .Server project and some extra project with shared models (they're probably doing clean architecture). The server project is a Razor pages project and the client a WASM project.
What you must understand is that a Blazor WASM project is not comparable with a Razor pages application. A Blazor WASM, or actually any WASM file is a different kind of binary and is fully run at the client! It is a client-side application. I.e. the output binary is totally different. You cannot have one project that generates both a server (x86/arm) binary and a client (WASM) binary. You need two separate projects.
What actually happens while compiling the WASM project, is that all page routing is also converted to WASM. Just inspect your network traffic when you change a page. Even though you browser url changes, that's fake... there is no network traffic! In fact, you stay on the same page.
Now think what happens when you enter "[..]/counter" manually in the browser. The host will actually again download the same .wasm file from the root ("/" = "/Index") and then parse the routing client-side.
Going back to your problem. For some reason you copied all the contents from the Blazer WASM project wwwroot/index.html to a Razor Page project Pages/Index.cshtml. Now you're confusing the whole routing system. When you type "[...]/counter", the WASM router will tell you that the .wasm file needs to be downloaded from "/Index". At the same time the Razor Pages router will tell you the compiled Index.cshtml is available at "/Index". That will give your "AmbiguousMatchException: The request matched multiple endpoints. Matches: /Index /Index".
Just look at the Summary of UseBlazorFrameworkFiles:
Configures the application to serve Blazor WebAssembly framework files from the root path "/".
Solution is just to keep the index.html in the WASM project as is. Just look at the default Blazor WASM ASP.Net app: it hosts Blazor WASM, Razor Pages and MVC at the same time and routing is just fine.
A different solution would be to use the overload of UseBlazorFrameworkFiles, where you can give a path prefix. E.g.
app.UseBlazorFrameworkFiles("/wasm");
You will need to fix other routing.
edit:
So let's give a case. you have:
A Blazor WASM project that serves pages /, /counter, etc.
A Razor pages project that serves pages /weatherforecast, etc.
Now:
you start the app on /. This loads the WASM from the server.
Next you click on the counter icon. this doesn't change the page!: it shows the counter page and updates the navigation url, but doensn't load a new page.
Now to go to weatherforecast. This is not found in the WASM, so a new page is actually loaded from the server. (either a razor page or controller/view)
If you would go back to counter, this is not found on the server, so the server 'falls-back' to the root (/Index) and loads the WASM again. Next is look if counter is found in the WASM.
Having a dynamic /Index will disrupt this system, so you'll have to manually solve all the routing.

Vue: How to enable multi page in an existing SPA project?

I have a single page (SPA) application written in Vue.
Now I need a separate page that should be available without being signed in.
To me it seems like a need to enable multi page app (MPA). I see in the documentation (https://cli.vuejs.org/config/#pages) that I need to set this up in vue.config.js. But I the documentation is unclear to me. Do I need to edit/rerun the Vue CLI setup? Or do some webpack changes. Just adding a new page entry with corresponding files does not work (webpack does not insert anything in html-file).
From SPA View, i would likely go like this
Inside /views folder
- HomePage.vue (no auth)
- Login.vue
- /users/ subfolder (auth needed)
- DashBoard.vue
- About.vue
etc
Then define the routes (paths,components,etc.) with requiresAuth as auth-check, redirects back to the route with HomePage.vuecomponent then.
and SPA mostly comes with MPA Challenges such as SEO, SSR concerns. The routing roughly the same to Vue/Nuxt.

NuxtJs generate for dynamic websites?

I'm creating a simple demo app with NuxtJs. The homepage shows static content that is not changed very often. There is another route for showing a list of users: /users. And one for showing user's details: /user/id.
Now my question is what's the difference between nuxt generate and nuxt build? which one should I use?
I think nuxt generate page will not render dynamic routes like users and user/id, Am I right? If I am right, then generate command will generate a pre-rendered HTML for homepage only. So using generate is always better than using build right ?
In universal mode, nuxt generate is for static site generation. nuxt build is for SSR site.
In 2.13.0, Nuxt introduced a target: static feature, make sure to
check it.
A static site has the best performance, and it is easy to deploy on nginx or other services, like Netlify.
By default, nuxt generate only render your static home page and /users page, not the dynamic /user/:id route.
But you can config nuxt to help you generate the dynamic routes.
If you have a fixed set of users, you can use functions to generate the routes.
If the users data is constantly in change, you can config nuxt to fallback to SPA on the dynamic routes. But you can't get any benefit for SEO on the dynamic routes.
For SPA fallback, in the generate config, define a custom page for SPA fallback:
export default {
generate: {
fallback: "custom_sap_fallbackpage.html"
}
}
Config the fallback page for unknow route in your deployment, for example, in Nginx:
location / {
try_files $uri /custom_sap_fallbackpage.html;
}
nuxt build will build you a SSR site. The html is rendered on the server and sent to the client. It add some work load on the server and maybe is not that easy to deploy, but the main gain is the SEO. And to some users with low end devices or slow internet connection, maybe your site will perform better than depolying in SPA mode.
Basically, you need to consider:
The website's content is static or constantly changing?
nuxt generate for static. nuxt generate or nuxt build or spa mode for sites with dynamic routes.
Do you need SEO?
SPA wouldn't get any SEO.
How you deploy the site?
For static hosting service, only nuxt generate or spa mode will work.
your website is heavy with js code, and you want best performance for user with slow internet and slow devices. Or SEO is important for your site with a lot of dynamic content.
SSR is for you, use nuxt build.
There are three different deployment and generation options in Nuxt.
Universal Mode
In this mode you build your project and then you ship it to a node.js server, the first view is always rendered dynamically on the server and then turns into SPA, and works in the client. That's great for SEO, and for consuming API's but you cannot upload it to any hosting, for example on a shared VPS.
So - Node.js Host is required here.
SPA
Well basically how Vue.js works by default, virtually no SEO at all, you can upload it on a shared VPS hosting, because it's just an index.html and build.js file and it's working entirely on the client-side (in the browser).
We can go for a static hosting here.
Static App
This is where Nuxt.js shines, because this mode will generate an index.html file and the corresponding js/css assets for each route you have in the dist folder, and you can then just take those numerous files, and upload them to any hosting, you don't need a server here, because your first views are already pre-rendered, unlike Universal where the node server should pre-render the first view. So you get SSR here, and your main concert as far as I understand is if you get SPA too, and that's the best part as in Universal mode, after the first request the app continues in SPA mode, how great is that eh?
Anyways there are some things you should take into consideration, that if you want to generate index.html for dynamic content you need to make something that's kinda a mood killer. You need to add this to nuxt-config.js
generate: {
routes: () => {
return [
'/posts/1'
]
}
}
You can also use axios to make http request and return array here. Or even export default array from a file and include it here, where you combine all your dynamic routes. It's a one time job, but if you add new crud in your backend, that would add up 1 more request to run on executing nuxt generate that should be described in nuxt-config.
So that's the reason I would prefer to pay more for a server, but to host a Universal App, instead static generated, because that's the part that doesn't make it really great for consuming API's in my personal opinion, but it is a great future anyways.
when you website update data often you don't need to use build by using npm generate your website static, load fast and SEO friendly for search engine and more secure and if your project has data NuxtJS download all data from database and change data to .json file statically.
if your website load data from the database you must use npm build to load data dynamically from database. use mode "spa" for a single page without client-side rendering or "universal" in nuxt.config.js for client-side rendering.
for dynamic routing use npm build for change route parameters from the database.