chrisvfritz / prerender-spa-plugin

Prerenders static HTML in a single-page application.
MIT License
7.32k stars 633 forks source link

Undesired nesting #402

Open jeffreykthomas opened 4 years ago

jeffreykthomas commented 4 years ago

My vue site is working fine after installing the plugin if it is entered from '/'

But if the site is entered from a subpage, say '/contact', then a router link to '/aboutus' will result in '/contact/aboutus', instead of the desired '/aboutus'. The same link will work correctly if the first page entered is '/'

Couldn't find anyone else that has had that issue, anyone have an idea?

I have just a very basic setup for the plugin:

const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const PuppeteerRenderer = PrerenderSPAPlugin.PuppeteerRenderer

module.exports = {
  pwa: {
    name: 'San Diego Mentors',
    themeColor: '#f96332',
    msTileColor: '#2ca8ff',
    appleMobileWebAppCapable: 'yes',
    appleMobileWebAppStatusBarStyle: '#f96332'
  },
  lintOnSave: false,
  configureWebpack: {
    plugins: process.env.NODE_ENV === 'production' ? [
      new PrerenderSPAPlugin({
        staticDir: path.join(__dirname, 'dist'),
        routes: [
          '/',
          '/contact',
          '/donate',
          '/signup',
          '/aboutus',
          '/faqs',
          '/financials',
          '/history',
          '/impact',
          '/team',
          '/training',
          '/camps',
          '/partner',
          '/personnel',
          '/schools'
        ],
        renderer: new PuppeteerRenderer({
          maxConcurrentRoutes: 1,
          headless: true
        })
      })
    ] : []
  }
};
JoshTheDerf commented 4 years ago

Any chance you could show your vue-router setup? Seems more like an app-specific issue.

jeffreykthomas commented 4 years ago

Here is the router.js code:

import Vue from "vue"
import Router from "vue-router"
import VueMeta from "vue-meta"

import Index from "./pages/Index.vue"
import About from "./pages/About.vue"
import Programs from "./pages/Programs.vue"
import Poker from "./pages/events-pages/Poker"
import Apply from "./pages/involved-pages/Apply"
import Contact from "./pages/Contact"
import Donate from "./pages/Donate"
import Media from "./pages/involved-pages/Media"
import Live from "./pages/events-pages/Live"
import Signup from "./pages/Signup"
import Newsletter from "./pages/Newsletter"
import James from "./pages/bios/James"
import Logo from "./pages/unlinked-pages/Logo"
import Admin from "./pages/involved-pages/Admin"

import Navbar from "./layout/MainNavbar.vue"
import Footer from "./layout/MainFooter.vue"
import SubpageHeader from "./layout/MainHeader.vue"
import Empathy from "./pages/events-pages/Empathy";
import FAQs from "./pages/about-pages/FAQs";

Vue.use(Router);

Vue.use(VueMeta);

export default new Router({
  mode: 'history',
  routes: [
    {
      path: "/",
      name: "index",
      components: { default: Index, nav: Navbar, footer: Footer },
      props: {
        footer: { type: 'default' }
      }
    },
    {
      path: "/history",
      name: "history",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'history-header.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/team",
      name: "team",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'fullteam-1.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/impact",
      name: "impact",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'kids-joyful.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/training",
      name: "training",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'training-header-1.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/financials",
      name: "financials",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'fullteam-1.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/faqs",
      name: "faqs",
      components: { default: FAQs, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'San Diego Mentors',
          subtitle: 'Founded in 1998, providing leadership training to youth',
          backgroundImage: 'fullteam-1.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/aboutus",
      name: "aboutus",
      components: {default: About, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'About Us',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        },
        default: { aboutPage: true }
      }
    },
    {
      path: "/schools",
      name: "schools",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'Programs',
          subtitle: 'Guiding youth to be better self-leaders',
          backgroundImage: 'school-header-1.jpg'
        },
        default: { aboutPage: false }
      }
    },
    {
      path: "/camps",
      name: "camps",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'Year-round Camps',
          subtitle: 'Guiding youth to be better self-leaders',
          backgroundImage: 'camp-header-1.jpg'
        },
        default: { aboutPage: false }
      }
    },
    {
      path: "/partners",
      name: "partners",
      components: { default: About, nav: Navbar, header: SubpageHeader, footer: Footer },
      props: {
        footer: { type: 'default' },
        header: {
          title: 'Partner',
          subtitle: 'For-profit Social Enterprise',
          backgroundImage: 'mentoring-6.jpg'
        },
        default: { aboutPage: false }
      }
    },
    {
      path: "/poker",
      name: "poker",
      components: {default: Poker, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: '2nd Annual Texas Hold Em',
          subtitle: 'Poker Fundraiser',
          backgroundImage: 'poker.jpg'
        }
      }
    },
    {
      path: "/apply",
      name: "apply",
      components: {default: Apply, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Job Openings',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/contact",
      name: "contact",
      components: {default: Contact, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Contact Us',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/newsletter",
      name: "newsletter",
      components: {default: Newsletter, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Sign Up for our Newsletter',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/donate",
      name: "donate",
      components: {default: Donate, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Join The Cause',
          subtitle: '',
          backgroundImage: 'kids-joyful.jpg'
        }
      }
    },
    {
      path: "/media",
      name: "media",
      components: {default: Media, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Latest Media',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/live",
      name: "live",
      components: {default: Live, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Live Web Events',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/signup",
      name: "signup",
      components: {default: Signup, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Sign Your Child Up for Camp ',
          subtitle: '',
          backgroundImage: 'application-back.jpg'
        }
      }
    },
    {
      path: "/personnel",
      name: "personnel",
      components: {default: About, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Professional Coaching',
          subtitle: '',
          backgroundImage: 'training-header-1.jpg'
        },
        default: { aboutPage: false }
      }
    },
    {
      path: "/james",
      name: "james",
      components: {default: James, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: '',
          subtitle: '',
          backgroundImage: 'history-header.jpg'
        }
      }
    },
    {
      path: "/empathychallenge",
      name: "empathy",
      components: {default: Empathy, nav: Navbar, header: SubpageHeader, footer: Footer},
      props: {
        footer: {type: 'default'},
        header: {
          title: 'Empathy Challenge',
          subtitle: '',
          backgroundImage: 'kids-joyful.jpg'
        }
      }
    },
    {
      path: "/photos",
      name: "logo",
      components: {default: Logo, nav: Navbar, footer: Footer},
      props: {
        footer: {type: 'default'},
      }
    },
    {
      path: "/admin",
      name: "admin",
      components: {default: Admin, nav: Navbar, footer: Footer},
      props: {
        footer: {type: 'default'},
      }
    }
  ],
  scrollBehavior: (to, from, savedPosition) => {
    if (to.hash) {
      return { selector: to.hash }
    } else {
      return { x: 0, y: 0 }
    }
  },
});

And then the main.js:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import "./registerServiceWorker";
//plugins
import NowUIKit from './plugins/now-ui-kit';
import AOS from 'aos'
import 'aos/dist/aos.css'
import VueGtag from "vue-gtag";

Vue.config.productionTip = false;
Vue.use(NowUIKit);

Vue.use(VueGtag, {
  config: { id: "UA-20121011-8"}
}, router)
new Vue({
  created(){
    AOS.init({ disable: 'mobile' })
  },
  router,
  render: h => h(App)
}).$mount("#app");

Anything there that makes sense to be causing the issue?

JoshTheDerf commented 4 years ago

Hmm, looks fine to me. Do you have the same issue if you do not prerender and serve index.html for every route without a corresponding static file?

jeffreykthomas commented 4 years ago

No, the issue disappears if I remove the pretender and the static files...

JoshTheDerf commented 4 years ago

Try setting the base property in vue-router.

jeffreykthomas commented 4 years ago

Thank you for the guidance Josh! Setting the base property didn't have an affect, but did lead me in the correct direction.

It turned out that I had several places with programmatic router links, and changing them solved the issue.

They had been either:

<router-link :to="variableName">
this.$router.push(variableName)

The above worked without the prerender, but in order to get it to work with the prerender I needed to change the links to their path, so something like this:

this.$router.push({ path: `/${variableName}` })

Don't know if that is expected or not...