Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

webpack - Serve Vue.js app from a subpath in Rails 5 with Webpacker

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,
});
question from:https://stackoverflow.com/questions/65892560/serve-vue-js-app-from-a-subpath-in-rails-5-with-webpacker

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...