What I'm trying to achieve is to add Vue 3 app into an existing Rails application. So my app would be a typical Rails app until the route /spa/*
is loaded. In that case Rails' controller would serve a layout that dependes on Webpack served JS...
First of all I added the route /spa/
to my routes.rb
in order to always resolve it into a controller that serves the correct layout that uses javascript_pack_tag
Then, I've managed to install and setup Webpacker in my Rails 5.2
rails app and it seems it's working correctly since I've built a simple app with a Vue router and a few components that are rendered correctly when the link is clicked. Well, almost...
The problem is in that I'm serving the Vue app under the path /spa/
instead of the root /
. When I load the /spa/
URL my header component (that holds links) is shown, but the initial component (The one in the Vue router) is not rendered until I click on the Vue link. The component gets rendered, but the URL changes from /spa/
to /q1
. Obviously, if we reload the browser that route is not "controlled" by Vue, but by Rails
What I'd like to achieve is to tell the Webpack(er) and Vue to add /spa/
before any Vue router link.
<nav id="nav">
<router-link to="/">Question 1</router-link>
<router-link to="/q2">Question 2</router-link>
</nav>
I know I could hard code the /spa
to every link I'm using, but that feels so dirty :D
My Vue Router:
import { createWebHistory, createRouter } from "vue-router";
import Question1 from "@/vue/views/Question1.vue";
import Question2 from "@/vue/views/Question2.vue";
// import About from "@/views/About.vue";
const routes = [
{
path: "q1",
name: "Question1",
component: Question1,
},
{
path: "q3",
name: "Question2",
component: Question2,
},
{
path: "",
redirect: { name: 'Question1' }
}
];
const router = createRouter({
history: createWebHistory(),
// publicPath: '/spa',
base: '/spa/',
routes,
});
export default router;
According to the Vue 3 docs this should be solved quite easily by adding the base
parameter to the Router config, but it's not working :/ and neither is the publicPath
I also found somewhere that with Webpack and Vue this could be solved by adding the path to the vue.config.js
, but using the Webpacker gem I'm not sure how to do it.
The question is:
How do I make my Vue app that gets served when the route /spa/
is called behave as if /spa/
didn't exist?
FINAL EDIT
Jump to @Excalibaard's answer :)
In my case the problem was that I was using Vue router v4 that has a different syntax from the one that you normally see when searching for the Router docs.
In the router v3 the base:
is an attribute of an object that is passed to the createRouter()
function
In v4 base
is a parameter that is given to a createWebHistory("the-base-value")
So, the solution in my case would be
const router = createRouter({
mode:history,
history: createWebHistory( '/spa/' ),
routes,
});
You're using the ~3.0 syntax.
new Router
. You provide a base option to the new Router instance.createRouter
function. The routerOptions no longer accept a base
key; base
is now an optional argument for the createHistory function.Try this:
const router = createRouter({
history: createWebHistory('/spa/'),
routes,
});
In regards to editing your webpack config:
vue.config.js
is a file for configuring Vue-CLI. This conflicts with the webpacker gem, as they both have their own way to manage webpack and the deployment chain. For webpacker, you're supposed to edit the webpack configuration from importing custom rules in your config/webpack
folder and merging into the default config.
EDIT: Original (incorrect) answer
You have to remove the slash at the start of your path. A slash at the beginning tells vue-router to handle as an absolute path.
https://router.vuejs.org/api/#route-object-properties
https://router.vuejs.org/guide/essentials/nested-routes.html
I would also advise as you scale up to refer to path names using :to="{ name:'Foo' }"
instead of to paths directly in case you change the path of your routes.