3

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,
});
2
  • 1
    Are you also exporting/importing the VueRouter in your main vue app? I do not see the export link in your snippet. Commented Jan 26, 2021 at 8:33
  • Yes! Sorry about that... I've updated the snippet Commented Jan 28, 2021 at 19:55

1 Answer 1

3

You're using the ~3.0 syntax.

  • In vue-router 3.0, you instantiate a router via new Router. You provide a base option to the new Router instance.
  • In vue-router 4.0, you do this via the 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.

Sign up to request clarification or add additional context in comments.

5 Comments

Hmmm If I remove the the slash and leave the route as { path: "q1", name: "Question1", component: Question1, } the Vue app doesn't compile at all. The error is: vue-router.esm-bundler.js:1293 Uncaught Error: Route paths should start with a "/": "q1" should be "/q1"
Can't argue with an edit message that clear ;). I've edited my answer.It's been a while since I've worked with vue and rails in the same app, instead of a separate front- and backend. The issue seems to be in vue-router 4.0 though.
Thank you so much! I've noticed that my router initializatio with the base param wasn't doing anything, but there's no way I would have noticed the difference between the Vue Router ~3 and v4... I'll update my question and point to your correct answer for the next lost soul! Thank you again!
I've noticed that the new router is under "next" subdomain... What's with that? How come it's a simple /v3 and /v4 separation?
Vue 3.0 released only very recently, and was available for public testing and review by making it available under the next domain. A lot of established tooling still has to catch up. Once vue 3.0 projects have enough support from external (UI) libraries so new people can work with it comfortably, I'm sure it will become the 'default' version, and the 'next' subdomain will become unused until the next major change.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.