vuejs add route after loading a content file - vuejs2

I developed a CMS and vuejs App to configurate custom terminal in shops. after loading the initial CMS File from the server I want to add the "/" and "*" path to the routes. how can I do this. for some reasons I would like to have the router initialized before I load the content.
I thought I could add a route with:
Vue.router.routes.push({
path: "*",
redirect: this.getStartPageType() // gets the homepage from the store
})
I get always "Cannot read property 'push' of undefined".
How could I do this. is it possible to a a method to the routes.
when adding this to the routes,
{
path: "*",
redirect: () => {
store.getters.getAppStartPageType;
}
}
I got an error: fullpath not definded in
<router-view :key="$route.fullPath" v-if="loaded==true"/>
and when entering a wrong path into the bwoser url string then I got "invalid redirect option: undefined"

Related

Catch-all route for production build of Vue Router/Vite-based SPA

I have a Vue3-based SPA using Vue Router and Vite as dev server. The app has three valid URL paths:
/
/first
/second
For production, it will be deployed on Apache under a prefix, i.e. the production URL paths will be:
/prefix
/prefix/first
/prefix/second
What I want to achieve is that clients should be redirected to a valid URL path (e.g. /prefix) of the application even when they initially request an invalid URL path, such as /prefix/invalid.
For this purpose, I've defined the following router.js:
import { createWebHistory, createRouter } from "vue-router";
const routes = [
{
path: "/first",
component: () => import("./components/First.vue")
},
{
path: "/second",
component: () => import("./components/Second.vue")
},
{
path: "/:anything+",
redirect: "/"
},
];
const router = createRouter({history: createWebHistory(import.meta.env.BASE_URL), routes});
export default router;
The third route entry defines a catch-all route that will match whenever clients request an invalid URL path. This works fine in development on Vite, i.e. when serving the app via npm run dev -- --base='/prefix/'. Even when the browser initially requests /prefix/invalid, the app's /prefix route is loaded and displayed.
When deploying with npm run build -- --base='/prefix/' for production, however, the catch-all route starts working only after clients have initially requested /prefix or /prefix/index.html and the SPA has been loaded. When they initially request /prefix/invalid or even /prefix/first or /prefix/second, Apache responds with 404 Not Found. This is of course because the whole routing is implemented client-side in JavaScript, so my catch-all route and everything else routing-related will only work once the SPA itself has been loaded and its JavaScript is executing in the browser.
My question is: is there a way to make initial requests for invalid URL paths work in production on Apache like in dev on Vite? I tried adding a file public/.htaccess like this:
ErrorDocument 404 import.meta.env.BASE_URL
But the expression import.meta.env.BASE_URL, which Vite statically replaces with the base config option value in router.js, is not replaced in this file - which is consistent with the documentation of the public directory. Hence this approach doesn't work.
Not sure whether I'm following the right path with .htaccess or whether my business problem has any better -possibly simpler- solution?
The problem can be solved by generating .htaccess dynamically using a simple Vite plugin, which I define inline in vite.config.js for simplicity.
// vite.config.js
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
// A private Vite plugin for generating .htaccess dynamically
function generateHtaccess () {
// Resolved Vite configuration, including "base" option
let viteConfig;
return {
name: 'generate-htaccess',
// Rollup Plugin API output generation hook
// See https://rollupjs.org/guide/en/#generatebundle
generateBundle() {
this.emitFile({
type: 'asset',
fileName: '.htaccess',
source: `ErrorDocument 404 ${viteConfig.base}\n`
});
},
// Vite Plugin API specific hook
// See https://vitejs.dev/guide/api-plugin.html#configresolved
configResolved(resolvedConfig) {
viteConfig = resolvedConfig;
},
};
}
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue(), generateHtaccess()],
});
A non-prefixed production build, such as npx vite build, will hence generate dist/.htaccess with the following content:
ErrorDocument 404 /
while specifying a prefix, e.g. npx vite build --base='/~user/' will generate:
ErrorDocument 404 /~user/
With this .htaccess, clients initially requesting any invalid URL path in production on Apache will be properly redirected to the same catch-all route -the app's root directory- as defined in router.js. This behavior will work consistently for any --base value supplied at build time.

how to add # in route in nuxtjs. e.g: example.com/#username

I have been searching to how to add a # in dynamic route in nuxtjs.
I want to achieve example.com/#username
I have tried to create a directory named '#' and inside it i created a file _user.vue but that leads to #/username
I have also tried to extend router in config and create a custom route like
router: {
extendRoutes(routes, resolve) {
routes.push({
name: 'user',
path: '/(#):username',
component: resolve(__dirname, 'pages/userProfile.vue')
})
}
},
but nuxt is preventing it & throwing error:
Expected "0" to match "#", but received "%40"
What i understand with this, is, it is url-encoding the # sign and username.
how do i achieve my desired output, (it is possible in vue router) as discussed in this below issue
https://github.com/vuejs/vue-router/issues/499
Any help will be appreciated.
Thanks!
Nvm.
I have just fixed it myself. posting answer to help others;
Nuxt doesnt support #_username.vue route name in nuxt filesystem routing.
to achieve route as example.com/#username we need to extend it in nuxt.config.js file in router object and define our custom route as
router: {
extendRoutes(routes, resolve) {
routes.push({
name: 'user',
path: '/#:username',
component: resolve(__dirname, 'pages/userProfile.vue')
})
}
},
defination of route is exactly same as vue router, as nuxt implements vue router.
so here,
name property is route name
path property is route path (prv. i was trying it (#):username which was leading to error, & it just got fixed when i removed brackets)
component property is page/component file name and it can exist anywhere, just set the file path where it exists.
Thanks me later!
cheers

Vuejs Router Async Component

I am running a vue app with npm run serve.
I am injecting the components to the routes asynchronously and in my opinion is happening something strange as when I am not even at that path it shows me an error about a component of another path, saying that the file is missing... and it is true it is missing... but isn't that suppose to be injected when I am at that path? Looks like the component is already imported...
const router = new VueRouter({
routes: [
{ path: '/login', component: () => import('./pages/login.vue') },
{ path: '/register', component: () => import('./pages/register.vue') },
]
I see this error in the compiler
./src/main.js
Module not found: Error: Can't resolve './pages/register.vue' in '/home/daniel/work/someapp/frontend/src'
and the path is /login, of course all works properly when I create the register page... just don't understand why it gets imported when the route is not loaded yet.
You are right.
You won't get the error until you navigate to that route that has the erroneous import path.
However, you have specified /login for both login and register.
So if the register component import path is not correct you will get the error.
Here is a trivial implementation which demonstrates the same.
When you navigate to categories, you will see an error. But home, news and lists will work correctly.

Data passing using props in router is not working

I am trying to send data from one vue component to another by using props in router. but it is not working. whenever i try to log the props it outputs undefined. code is given below
From where data is sending
Where receiving
in index.js. router setting
None of the code you've posted matches up.
Firstly, the console logging should be just console.log(this.myprops). The point of using props is that you don't need to reference the router itself, e.g. via $router.
Next problem, you're mixing path and params. That isn't allows. See https://router.vuejs.org/guide/essentials/navigation.html. params are for named routes.
I imagine what you're aiming for is something like this:
self.$router.replace({ name: 'DashboardPatient', params: { myprops: authUser.email } })
with router config:
{
path: '/patient',
component: Dash,
children: [
{
path: ':myprops', // <--- Adding myprops to the URL
name: 'DashboardPatient',
component: DashboardPatient,
props: true,
meta: { requiresAuth: true }
}
]
}
Keep in mind that routing is all about building and parsing the URL. So the value of myprops needs to be in the URL somewhere. In my example it comes at the end, so you'll get /patient/user#example.com as the URL. If it weren't in the URL then there'd be no way for the router to populate the prop if the user hit that page directly (or refreshed the page).
To hit the same route using a path instead of a name it'd be something like this:
self.$router.replace({ path: `patient/${encodeURIComponent(authUser.email)}` })
or even just:
self.$router.replace(`patient/${encodeURIComponent(authUser.email)}`)
Personally I'd go with the named route so that the encoding is handled automatically.
If you don't want to put the data in the URL then routing is not the appropriate way to pass it along. You'd need to use an alternative, such as putting it in the Vuex store.

VueJs 2: Unable to render view when using history mode and route params

I am trying to set up SPA routes using history mode as follows:
{
mode: 'history',
routes: [
{
path: '/',
component: Home
},
{
path: '/articles',
component: ArticleList,
children: [
{
path: ':title',
component: ArticleView
}
]
}
]
}
As I am using the history mode routing on vue and on express application I've set up "express-history-api-fallback" as the last middleware in the pipeline:
const app = express();
const root = path.join(__dirname, '../client/dist');
app.use(express.static(root));
/* other middlewares */
app.use(fallback('index.html', {root: root}));
At the moment of a page reload, everything works fine. I.e. loading a url http://application/articles, opens correctly the view, BUT when I try to access the view that takes in a parameter, no matter what, the view does not get loaded and two requests are made to the express.
I.E. a request to http://application/articles/test will resolve into two requests. One to http://application/articles/test and another one to http://application/articles/app.[calculated-hash].js
As far as I understand, the first request fetches the index.html the other request fetches the bundled js script.
Also, on the express app, all routes to api start with 'api' prefix.
Question:
What is wrong with my setup/code using history mode and route params because no routes with parameters are loaded when trying to access them when entering url manually or hitting refresh?
Update:
Using connect-history-api-fallback produces the same results
The problem was with the script tag the webpack injects into the index.html
<script type="text/javascript" src="app.06503cbc260646a996d9.js"></script>
The src attribute value was missing a '/' prefix thus the resolution of files failed.
So to make it work, I've linked the src file like this:
<script type="text/javascript" src="/app.06503cbc260646a996d9.js"></script>
As I am using the webpack to bundle js files, on the webpack config I've added output.publicPath '/'
More info: connect-history-api-fallback bugtracker