Dynamic SPA routes for statically generated Nuxt app - javascript

I have a Nuxt project that is fully statically generated. But one part of this is pretty dynamic. Let's say it is items page and items/:id pages. Where on the items page we render the list of items as links to each items/:id page.
I would like to opt-out of a static generation for those 2 pages. For now, I used the following changes to the nuxt.config.js:
export default {
target: 'static',
router: {
extendRoutes (routes, resolve) {
routes.push({
name: 'items',
path: '/items/*',
component: resolve(__dirname, 'pages/items/_slug.vue')
})
}
},
generate: { exclude: [/^\/items/], fallback: '404.html' }
This works nicely when I do nuxt generate & nuxt start but only for navigation within the website. When I go directly to let's say /items/42 I get 404 rendered.
How should I adjust configuration or deployment to make it work?

Related

A single payload.js for all nuxt static generate'd routes when data is the same

I have a NuxtJS site with only one page /pages/matrix/index.vue but quite a lot of dynamic routes pointing to this page, each route using the same set of data. When generating a static build for deployment on Netlify, the dist folder currently reaches ~1.2 GB, consisting of
3125 .html files in dist/matrix (occupying ~39% of the space)
3125 folders for payload.js files in dist/_nuxt/static/[random]/matrix/ in subfolders for routes (occupying ~61% of the space)
Those 61% are 3125 copies of a 220kB payload.js with exactly the same set of data: [{}], while only the route changes:
__NUXT_JSONP__("/matrix/place2/time3,time14,time29", (function(a, b, ...) {
return {
data: [{ /* data does not change */ }],
fetch: {},
mutations: void 0
}
}("nor", "does", "this")));
I wonder if there is a way to reduce this redundancy by somehow extracting the data part? Reducing ~665 MB to just 220kB sounds alluring.
Some more background:
Routes are /matrix, /matrix/place1 or /matrix/place8/time1,time7,time18. When generating, I pull all data from a headless CMS and feed it to my page component via the payload option. First, I used File System Routing and imported the pages/matrix/index.vue like this:
// pages/matrix/_places/index.vue
<script>
import Index from '../index'
export default Index
</script>
which felt wrong but worked. I blamed this approach to the "duplication" of those payload files (frankly without completely understanding the mechanics of static generation). I now switched to extendRoutes with this nuxt.config.js setting:
router: {
extendRoutes (routes, resolve) {
routes.push(
{
name: 'matrix-place-times',
path: '/matrix/:place/:times',
component: resolve(__dirname, 'pages/matrix/index.vue')
},
{
name: 'matrix-place',
path: '/matrix/:place',
component: resolve(__dirname, 'pages/matrix/index.vue')
}
)
}
}
The amount of payload files spread across route subfolders stays the same.
Any advice on this? Using Nuxt v2.15.7.
Few things I can think about:
using SSR would solve some of those issues (you told that you wish to stay on Netlify tho)
using some aliased routes may be a good idea, especially if you have the exact same data at 2 differently named endpoints
this video also gives some leads regarding ISG or other ways to have more flexibility towards big page amounts
Nuxt3 is able to run on Cloudflare workers, this is not SSR nor exactly ISG but a middle ground, a different approach but it could render pages for not so expensive while being quick

In Angular, how can one component to have multiple HTML templates?

I am developing an ecommerce application, and one major feature is that this app should have multiple themes. The total number of themes could be 100 or even more. However, these themes all have the same data (For example: all home page have same banner images, new product, feature product data.) .
I know I can use ng-template or TemplateRef to determine which piece of HTML should display. But since I have over 100 themes, both ng-template or TemplateRef methods will load a lot of extra files. So I think I need some sort of lazy load, when a component loads the data then lazy loads the correct HTML template. So how can I have this work?
Looks like it is possible, all our routes are handled by lazy loaded modules. This is our out-of-the-box route config:
const routes: Routes = [
{ path: '', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
];
While module lazy has this route config:
const routes: Routes = [
{ path: 'home', component: HomeComponent },
]
While HomeComponent is taken from the declarations of module lazy.
Then define another module, called for example lazy-two with the same route config, and its own HomeComponent.
Finally, you can switch between the modules by using this code:
lazyLoad() {
const routes: Routes = [
{
path: '',
loadChildren: () => import('./lazy-two/lazy-two.module')
.then(m => m.LazyTwoModule)
}
];
this.router.resetConfig(routes);
this.router.navigateByUrl('/home');
}
This will lazy load module lazy-two and refresh the route to /home - you will see the component of the new module displayed.
I couldn't create a stackblitz, some errors occurred probably because of lazy loading. So I ran it locally on my machine and pushed the code to GitHub
EDIT I managed to make a StackBlitz
I recommend used ComponentFactoryResolver to create the components that you need to render.
this.templates = [
{
id: "template-1",
component: Template1,
},
{
id: "template-2",
component: Template2,
},
];
ngOnInit() {
this.templates.forEach((element) => {
this.containerReference.createComponent(
this.factoryResolver.resolveComponentFactory(element.component)
);
});
}
in the .html you should have
<ng-container #containerReference><ng-container>
what about using the same component and styling it different when you select the template?

How to transfer state between pages in multipage vue app?

I want to transfer data between pages in multipage vue app. I tried vuex with store but it's not working.
I used vue.config.js file to make multipage app. each page has App.vue and main.js to itself. When I import store.js to main.js, Initiate it there and it works only for it's own App.vue. But I need to transfer data from one page to another page. from one App.vue to another App.vue.
(Eg:- when I click on a person's name on one page, it should load that person's profile with his details. (It is an another page)). My plan was when someone click on the profile picture, details about that person goes to the store and I wanted to retrieve them in profile page. It didn't work. I'm a newbie to Vue. Am I doing it wrong way? Is there a better way doing this? Could someone help me to make this success? Thank you!
ps- Database is also attached. If there is a way to pass the reference between pages that will work too.
part of vue.config.js
module.exports = {
pages: {
'index': {
entry: './src/pages/home/main.js',
template: 'public/index.html',
title: 'Home',
chunks: [ 'chunk-vendors', 'chunk-common', 'index' ]
},
'register': {
entry: './src/pages/register/main.js',
template: 'public/index.html',
title: 'Register',
chunks: [ 'chunk-vendors', 'chunk-common', 'register' ]
},
'login': {
entry: './src/pages/login/main.js',
template: 'public/index.html',
title: 'Login',
chunks: [ 'chunk-vendors', 'chunk-common', 'login' ]
},
store.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export const store = new Vuex.Store({
state:{
//this is not real data
i:0
},
Part of my code editor's file stack to get a better idea
I followed the method in below thread to make a multipage app
https://stackoverflow.com/questions/51692018/multiple-pages-in-vue-js-cli
If you want to have the same Vuex store using your app in different tabs try to use vuex persisted state plugin. Plugin would save your store in localStorage and that would give you possibility to share the same store between different tabs (or different instances of your app if you wish).

VueJS 3 Router behaves differently in Dev and Production

I'm pretty new to VueJS and have a problem I can't grasp right now.
I coded a little App which works absolutely fine under vue serve, but when I build it and upload the dist folder to my webserver I'm experiencing a weird problem.
I have the following Routes:
/home
/overview
/listing
/detail
I start at home, click on a button go to overview, from there to listing and from there to detail. Every template has a a "Go Back" Link which works with
#click="$router.back()"
When testing locally with Vue Serve it behaves as expected.
When I built it and upload the dist folder I get the weird error that when I'm on "Detail" and go back, it goes to "Overview" instead of "listing". I notice that the address in the browser is always one level "off". For example if I go back from overview to home, it shows the home-template but the addressbar shows /listing.
Does anyone have an idea what I'm doing wrong? Thanks a lot!
I already tried $router.go(-1), which results in the same error..
My router file looks pretty standard I'd say:
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/overview',
name: 'Overview',
component: Overview
},
{
path: '/listing',
name: 'Listing',
component: Listing
},
{
path: '/detail',
name: 'Detail',
component: Detail
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
It works great in vue serve mode, but just not when using the dist folder online..

Vue.js moduler build

We have project of around 100 pages. We are migrating our front end to some emerging technology. We almost have finalized Vue.js(with vue cli). Vue CLI is building project in one build.js. We have a problem with that. We have frequent requirement changes. So after every small change, we will have to upload whole build js and that will need regression testing of the whole project. Is there any way that build will be module wise? So that only changed module need to be uploaded on live after changes.
Using the Vue router:
The following approach will tell the compiler (Webpack) to "return" the component vs "including" it. Resulting in the given component being "chunked" into its own file for lazy loading.
e.g.
export default new Router({
routes: [
// Home component to be included in bundle.js
{
path: '/',
name: 'home',
component: Home
},
// code splitting - generate a separate unique chuck for about component.
{
path: '/about',
name: 'about',
component: () => import(/* webpackMode: "lazy" */ '#/views/About.vue')
}
]
})
Output = bundle.js and about.js or... 100 other files, given you have a component per page.
more on component lazy loading: https://router.vuejs.org/guide/advanced/lazy-loading.html
Using webpack:
You can extend and/or modify the default compiler (webpack) configuration by adding a vue.config.js file to the project root.
e.g.
// vue.config.js
module.exports = {
configureWebpack: config => {
if (process.env.NODE_ENV === 'production') {
// mutate config for production...
} else {
// mutate for development...
}
}
}
Be sure to read all the documentation at https://cli.vuejs.org/guide/webpack.html as some settings should not be mutated directly.
more on webpack code splitting: https://webpack.js.org/guides/code-splitting

Categories

Resources