Вот пример роутера для vue
// Imports
import Vue from 'vue'
import Router from 'vue-router'
import { authGuard, logoutHabdler } from '@/helpers'
Vue.use(Router)
const router = new Router({
mode: 'history',
base: process.env.BASE_URL,
scrollBehavior: (to, from, savedPosition) => {
if (to.hash) return { selector: to.hash }
if (savedPosition) return savedPosition
return { x: 0, y: 0 }
},
routes: [
{
path: '/logout',
beforeEnter: logoutHabdler,
},
{
path: '/',
component: () => import('@/layouts/home/Index.vue'),
children: [
{
path: '',
name: 'Home',
component: () => import('@/views/home/Index.vue'),
},
{
path: 'about',
name: 'About',
component: () => import('@/views/about/Index.vue'),
},
{
path: 'description',
name: 'Description',
component: () => import('@/views/description/Index.vue'),
},
{
path: 'price',
name: 'Price',
component: () => import('@/views/price/Index.vue'),
},
{
path: 'login',
name: 'Login',
component: () => import('@/views/login/Index.vue'),
},
{
path: 'legal',
name: 'Legal',
component: () => import('@/views/home/Legal.vue'),
},
{
path: 'eula',
name: 'Eula',
component: () => import('@/views/home/Eula.vue'),
},
{
path: 'condition',
name: 'Condition',
component: () => import('@/views/home/Condition.vue'),
},
{
path: 'disclosure/:id?',
name: 'Disclosure',
component: () => import('@/views/home/Disclosure.vue'),
},
{
path: 'userlist/:id?',
name: 'UserList',
component: () => import('@/views/home/UserList.vue'),
},
{
path: 'open/:id?',
name: 'SuccessorList',
component: () => import('@/views/home/SuccessorList.vue'),
},
],
},
{
path: '/user',
component: () => import('@/layouts/user/Index.vue'),
beforeEnter: authGuard,
children: [
{
path: '',
name: 'UserHome',
component: () => import('@/views/user/Index.vue'),
},
{
path: 'store/:id?',
name: 'UserStore',
component: () => import('@/views/user/Store.vue'),
},
{
path: 'faq',
name: 'UserFaq',
component: () => import('@/views/user/Faq.vue'),
},
{
path: 'messages',
name: 'UserMessages',
component: () => import('@/views/user/Messages.vue'),
},
{
path: 'contacts',
name: 'UserContacts',
component: () => import('@/views/user/Contacts.vue'),
},
{
path: 'profile',
name: 'UserProfile',
component: () => import('@/views/user/Profile.vue'),
},
{
path: 'payment/:id',
name: 'Payment',
component: () => import('@/views/user/Payment.vue'),
},
],
},
{
path: '*',
component: () => import('@/layouts/user/Page404.vue'),
children: [
{
path: '*',
name: 'Page404',
component: () => import('@/views/user/Page404.vue'),
},
],
},
],
})
export default router
Вот конкретно этот кусок обрабатывает пути /user/store/какойто_идентификатор
{
path: 'store/:id?',
name: 'UserStore',
component: () => import('@/views/user/Store.vue'),
},
Соответственно вы можете создать путь для ваших страниц
далее
vue.config.js
const path = require('path')
const PrerenderSPAPlugin = require('@dreysolano/prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
const isDev = process.env.NODE_ENV !== 'production'
const plugins = isDev
? []
: [
new PrerenderSPAPlugin({
// Required - The path to the webpack-outputted app to prerender.
staticDir: path.join(__dirname, 'dist'),
// Optional - The path your rendered app should be output to.
// (Defaults to staticDir.)
// outputDir: path.join(__dirname, 'prerendered'),
// Optional - The location of index.html
indexPath: path.join(__dirname, 'dist', 'index.html'),
// Required - Routes to render.
// Генерируйте пути из бд и билдите приложение какким нибудь скриптом на основе базы данных
routes: ['/', '/about', '/description', '/price', '/about'],
// Optional - Allows you to customize the HTML and output path before
// writing the rendered contents to a file.
// renderedRoute can be modified and it or an equivelant should be returned.
// renderedRoute format:
// {
// route: String, // Where the output file will end up (relative to outputDir)
// originalRoute: String, // The route that was passed into the renderer, before redirects.
// html: String, // The rendered HTML for this route.
// outputPath: String // The path the rendered HTML will be written to.
// }
postProcess (renderedRoute) {
// Ignore any redirects.
renderedRoute.route = renderedRoute.originalRoute
// Basic whitespace removal. (Don't use this in production.)
// renderedRoute.html = renderedRoute.html.split(/>[\s]+</gim).join('><');
// Remove /index.html from the output path if the dir name ends with a .html file extension.
// For example: /dist/dir/special.html/index.html -> /dist/dir/special.html
if (renderedRoute.route.endsWith('.html')) {
renderedRoute.outputPath = path.join(
__dirname,
'dist',
renderedRoute.route,
)
}
return renderedRoute
},
// Optional - Uses html-minifier (https://github.com/kangax/html-minifier)
// To minify the resulting HTML.
// Option reference: https://github.com/kangax/html-minifier#options-quick-reference
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
keepClosingSlash: true,
sortAttributes: true,
},
// Server configuration options.
server: {
// Normally a free port is autodetected, but feel free to set this if needed.
port: 8001,
},
// The actual renderer to use. (Feel free to write your own)
// Available renderers: https://github.com/Tribex/prerenderer/tree/master/renderers
renderer: new Renderer({
// Optional - The name of the property to add to the window object with the contents of `inject`.
injectProperty: '__PRERENDER_INJECTED',
// Optional - Any values you'd like your app to have access to via `window.injectProperty`.
inject: {
foo: 'bar',
prerender: false,
},
// Optional - defaults to 0, no limit.
// Routes are rendered asynchronously.
// Use this to limit the number of routes rendered in parallel.
maxConcurrentRoutes: 4,
// Optional - Wait to render until the specified event is dispatched on the document.
// eg, with `document.dispatchEvent(new Event('custom-render-trigger'))`
// renderAfterDocumentEvent: 'custom-render-trigger',
// Optional - Wait to render until the specified element is detected using `document.querySelector`
renderAfterElementExists: '#app',
// Optional - Wait to render until a certain amount of time has passed.
// NOT RECOMMENDED
renderAfterTime: 5000, // Wait 5 seconds.
// Other puppeteer options.
// (See here: https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions)
headless: true, // Display the browser window when rendering. Useful for debugging.
}),
}),
]
module.exports = {
devServer: {
disableHostCheck: true,
progress: false,
before () { // Output the same message as the react dev server to get the Spa middleware working with vue.
console.info('Starting the development server...')
},
},
transpileDependencies: ['vuetify'],
configureWebpack: {
plugins: [...plugins],
},
}
В итоге получите SPA приложение с поисковой оптимизацией