Vue項目SEO優化的另外一種姿態

背景:當前項目首頁和登錄後的平臺在一個項目裏,路由採用hash模式,如今要作SEO優化,這時候同構SSR(Server Side Rendering)服務端渲染代價顯然太大,影響範圍比較廣,一樣更改當前項目路由爲history模式採用預渲染(Prerending)代價也不小。最終決定將首頁單獨出一個項目採用預渲染,而後用nginx代理來實現兩個項目之間的跳轉。php

同構SSR服務端渲染這裏就很少贅述了,說一下預渲染:css

1、什麼狀況下用預渲染比較好html

官方文檔建議:若是你調研服務器端渲染(SSR)只是用來改善少數營銷頁面(例如 //about/contact 等)的 SEO,那麼你可能須要預渲染。無需使用 web 服務器實時動態編譯 HTML,而是使用預渲染方式,在構建時(build time)簡單地生成針對特定路由的靜態 HTML 文件。優勢是設置預渲染更簡單,並能夠將你的前端做爲一個徹底靜態的站點。前端

2、選用插件vue

官方文檔建議:若是你使用 webpack,你可使用 prerender-spa-plugin 輕鬆地添加預渲染。它已經被 Vue 應用程序普遍測試 - 事實上,做者是 Vue 核心團隊的成員。webpack

結合vue-meta-info這一類動態設置meta信息的插件,能夠達到更好的效果。nginx

3、插件的使用git

安裝github

# Yarn
$ yarn add prerender-spa-plugin
# or NPM
$ npm i prerender-spa-plugin

vue-cli3 webpack配置web

在vue.config.js中:

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

module.exports = {
    configureWebpack: {
        module: {},
        plugins: process.env.NODE_ENV === 'production' ? [
            new PrerenderSPAPlugin({
                staticDir: path.join(__dirname, process.env.VUE_APP_OUTPUT_DIR),
                // 須要進行預渲染的路由路徑
                routes: ['/', '/about'],
                // html文件壓縮
                minify: {
                    minifyCSS: true, // css壓縮
                    removeComments: true // 移除註釋
                },
                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: {},
                    // 在 main.js 中 new Vue({ mounted () {document.dispatchEvent(new Event('render-event'))}}),二者的事件名稱要對應上。
                    renderAfterDocumentEvent: 'render-event'
                })
            })
        ] : []
    }
}

這裏只在 process.env.NODE_ENV === 'production'的時候進行預渲染,輸入目錄爲 process.env.VUE_APP_OUTPUT_DIR,是在.env   .env.prod  .env.test等全局環境變量中配置的,能夠根據不一樣環境打包,如.env.prod的配置爲:

NODE_ENV = production

VUE_APP_OUTPUT_DIR = 'dist-prod'
VUE_APP_PROJECT_URL = '/platform'

這裏的VUE_APP_PROJECT_URL稍後再作解釋。

以上的new PrerenderSPAPlugin({})配置中刪除了

headless: false // Display the browser window when rendering. Useful for debugging.

目的是爲了避免打開chromium瀏覽器。

在main.js中配置:

new Vue({
    router,
    store,
    render: h => h(App),
    mounted () {
        document.dispatchEvent(new Event('render-event')) // 預渲染
    }
}).$mount("#app")

vue-meta-info安裝使用:

安裝

# Yarn
$ yarn add vue-meta-info
# or NPM
$ npm install vue-meta-info --save

使用

import Vue from 'vue'
import MetaInfo from 'vue-meta-info'

Vue.use(MetaInfo)
<template>
  ...
</template>

<script>
  export default {
    metaInfo: {
      title: 'My Example App', // set a title
      meta: [{                 // set meta
        name: 'keyWords',
        content: 'My Example App'
      }]
      link: [{                 // set link
        rel: 'asstes',
        href: 'https://assets-cdn.github.com/'
      }]
    }
  }
</script>

若是你的title或者meta是異步加載的,那麼你可能須要這樣使用

<template>
  ...
</template>

<script>
  export default {
    name: 'async',
    metaInfo () {
      return {
        title: this.pageName
      }
    },
    data () {
      return {
        pageName: 'loading'
      }
    },
    mounted () {
      setTimeout(() => {
        this.pageName = 'async'
      }, 2000)
    }
  }
</script>

3、項目間跳轉配置

如今說一下VUE_APP_PROJECT_URL這個變量,這個變量即是兩個項目間跳轉的關鍵。在本地開發中,能夠經過設置.env中的變量:

VUE_APP_PROJECT_URL = 'http://localhost:8080'
另外一個項目
VUE_APP_PROJECT_URL = 'http://localhost:8081'

而後經過window.location.href的方式進行兩個本地項目之間的跳轉:

export function toUrl (query) { // 動態更改href
    window.location.href = process.env.VUE_APP_PROJECT_URL + query
}

至於線上怎麼進行跳轉,能夠這麼配置.env.prod中的變量:

VUE_APP_PROJECT_URL = '/'
另外一個項目
VUE_APP_PROJECT_URL = '/platform'

而後在nginx中配置:

### 默認進入的項目 ###
server {
    listen 30002;
    server_name xxx.xx.xxx.xxx;
    proxy_buffer_size 8k;
    proxy_buffers 8 32k;
    set $root /var/www/page-for-seo/dist-prod;
    root $root;
    index index.html index.htm index.php;

    error_log   /var/nginx/logs/error.log error;
    access_log  /var/nginx/logs/access.log;

    #access_log off;

    ### 客戶端請求錯誤處理 ###
    error_page  403 404  /404.html;
    location = /404.html {
        return 404 'Sorry, File not Found!';
    }

    ### 服務端請求錯誤處理 ###
    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
            root  /usr/share/nginx/html;
    }

    ### 靜態資源有效期 ###
    location ~ .*\.(jpeg|png|jpg|gif)$ {
        expires 1d;
    }

    ### 匹配全部請求 ###
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    ### 匹配 platform/ 而後進行代理 ###
    location ^~ /platform/ {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://xxx.xx.xxx.xxx:30012/;
    }
}

### 要進行跳轉的項目 ###
server {
    listen 30012;
    server_name xxx.xx.xxx.xxx;
    proxy_buffer_size 8k;
    proxy_buffers 8 32k;
    set $root /var/www/platform/dist-prod;
    root $root;
    index index.html index.htm index.php;

    error_log   /var/nginx/logs/error.log error;
    access_log  /var/nginx/logs/access.log;

    #access_log off;

    ### 客戶端請求錯誤處理 ###
    error_page  403 404  /404.html;
    location = /404.html {
        return 404 'Sorry, File not Found!';
    }

    ### 服務端請求錯誤處理 ###
    error_page  500 502 503 504  /50x.html;
    location = /50x.html {
            root  /usr/share/nginx/html;
    }

    ### 靜態資源有效期 ###
    location ~ .*\.(jpeg|png|jpg|gif)$ {
        expires 1d;
    }

    ### 匹配全部請求 ###
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }
}
相關文章
相關標籤/搜索