Vue 项目做SEO优化
• 3 • 478
Table of contents
基于Vue2 + Router 的项目做SEO搜索引擎优化
vue 页面预渲染
- 安装prerender-spa-plugin
yarn add prerender-spa-plugin --save
or
npm install prerender-spa-plugin --save
-
将vue router mode属性改为history
const routes = [ { path: '/', name: 'Home', component: Home } ] const router = new VueRouter({ mode: 'history', base: process.env.BASE_URL, routes })
mode必须为history,如果不改为history,在hash模式下,prerender-spa-plugin打包出来的静态html只有首页的html是完整的,其他页面还是用的首页骨架,然后动态生成生成html替换,就达不到seo的效果。
-
页面中生成meta 元信息
-
安装vue-meta-info
npm install vue-meta-info --save or yarn add vue-meta-info --save
-
在需要的预渲染的页面中加入meta元信息
export default { metaInfo: { title: '★广州APP开发,广州APP开发公司_广州思久信息科技有限公司', meta: [ { name: 'keywords', content: '广州APP开发公司,广州网站建设公司,企业管理系统开发' }, { name: 'description', content: '思久科技专业提供广州app开发,微信开发,h5开发,管理系统开发,网站建设等服务' } ] }, name: 'Home', data(){ return {} } }
-
-
在vue.config.js 配置项或者webpack.config.js 中使用prerender-spa-plugin插件
// 预渲染模式插件,将SPA单页面应用打包成多页面 const PrerenderSpaPlugin = require('prerender-spa-plugin') const Renderer = PrerenderSpaPlugin.PuppeteerRenderer var routes = ['/', '/about', '/enterprise'] module.exports = { configureWebpack: { publicPath: './', outputDir: 'dist', assetsDir: 'static', parallel: false, plugins:[ new PrerenderSpaPlugin({ // 生成文件的路径,也可以与webpakc打包的一致。 // 下面这句话非常重要!!! // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。 staticDir: path.join(__dirname, 'dist'), // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。 routes, // 预渲染代理接口 // server: { // proxy: { // '/api': { // target: 'http://localhost:9001', // secure: false // } // } // }, // 这个很重要,如果没有配置这段,也不会进行预编译 renderer: new Renderer({ // 可选 - 您希望您的应用程序可以通过 `window.injectProperty` 访问的任何值。 inject: { foo: 'bar' }, headless: false, // 渲染时显示浏览器窗口。用于调试 // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。 renderAfterDocumentEvent: 'render-event', // puppeteer参数,标签意思:完全信任在Chrome中打开的内容 args: ['--no-sandbox', '--disable-setuid-sandbox'] }) }) ] } }
-
在main.js 中加入预编译执行事件
new Vue({ router, store, render: h => h(App), mounted () { // 预编译执行事件 document.dispatchEvent(new Event('render-event')) } }).$mount('#app')
-
在App.vue 中加入
data-server-rendered="true"
,防止预渲染时页面空白<template> <div id="app" data-server-rendered="true"> <router-view/> </div> </template>
-
注意
生成预渲染页面最好是在生产环境中打包生成
打包生成的预渲染页面需要在配置nginx中访问,否则资源加载不出来,导致页面空白
对项目中的某几个页面网站进行 SEO 优化,可以使用预渲染,如果网站页面有太多的话就不适用预渲染
生成sitemap 网站地图
-
安装sitemap
yarn add sitemap@4 -D or npm install sitemap@4 -D
-
在vue.config.js 中配置生成sitemap网站地图
const fs = require('fs') const path = require('path') const sm = require('sitemap') const PrerenderSpaPlugin = require('prerender-spa-plugin') const Renderer = PrerenderSpaPlugin.PuppeteerRenderer var routes = ['/', '/about', '/enterprise'] module.exports = { configureWebpack: { plugins:[ new PrerenderSpaPlugin({ // 生成文件的路径,也可以与webpakc打包的一致。 // 下面这句话非常重要!!! // 这个目录只能有一级,如果目录层次大于一级,在生成的时候不会有任何错误提示,在预渲染的时候只会卡着不动。 staticDir: path.join(__dirname, 'dist'), // 对应自己的路由文件,比如a有参数,就需要写成 /a/param1。 routes, // 生成sitemap 网站地图 postProcess (context) { // // content 参数 const { originalRoute, route, html } = context // 全局获取href内容正则 const reg = /(?<=<a\s*.*href=")[^"]*(?=")/g // 过滤不包含http或https开头的url const urlList = html.match(reg).filter(url => url.startsWith('http')) // 将路由添加到全局sitemap容器 siteMapUrls.push(originalRoute) // 将html中的外链添加到全局sitemap容器 if (urlList.length) { urlList.forEach(url => siteMapUrls.push(url)) } // 当当前路由为最后一个生成路由时 if (route === routes[routes.length - 1]) { // 去除重复的链接 let currentSiteMapUrls = Array.from(new Set(siteMapUrls)) // 过滤掉链接中的锚点后内容 currentSiteMapUrls = currentSiteMapUrls.map(url => { const isMao = url.indexOf('#') > -1 // 生成sitemap所需数据,具体参数参详sitemap.js官网 return { url: isMao ? url.split('#')[0] : url, changefreq: 'weekly', priority: 1.0, lastmod: new Date().toLocaleDateString() } }) // 生成siteMap文件 const siteMap = sm.createSitemap({ // 路由前缀地址,全地址自动不会添加hostname(https://www.baidu.com不会添加hostname) hostname: 'http://www.seejoys.com', cacheTime: 600000, // 600 sec (10 min) cache purge period urls: currentSiteMapUrls }) // 将sitemap文件添加搭配打包文件夹dist中 fs.writeFileSync(path.join(__dirname, 'dist/sitemap.xml'), siteMap.toString()) } // 返回当前contet对象 return context }, // 预渲染代理接口 // server: { // proxy: { // '/api': { // target: 'http://localhost:9001', // secure: false // } // } // }, // 这个很重要,如果没有配置这段,也不会进行预编译 renderer: new Renderer({ // 可选 - 您希望您的应用程序可以通过 `window.injectProperty` 访问的任何值。 inject: { foo: 'bar' }, headless: false, // 渲染时显示浏览器窗口。用于调试 // 在 main.js 中 document.dispatchEvent(new Event('render-event')),两者的事件名称要对应上。 renderAfterDocumentEvent: 'render-event', // puppeteer参数,标签意思:完全信任在Chrome中打开的内容 args: ['--no-sandbox', '--disable-setuid-sandbox'] }) }) ] } }