vue 預渲染遇到的坑


前言:

  最近公司項目需要增加seo搜索引擎優化,到網上找了下資料,有預渲染和服務端渲染兩種方式,考慮到只需要渲染首頁所以我選擇了先啟用比較簡單的預渲染方式來做seo!

步驟:

1、安裝 prerender-spa-plugin,使用淘寶鏡像安裝 cnpm

cnpm install   prerender-spa-plugin -D
  • -D 表示在開發環境下使用
  • cnpm 淘寶鏡像安裝可以避免安裝過程無端報錯

2、預渲染一定要把路由模式變成history

const router = new Router({
  mode: 'history', // 預渲染一定要模式改成history
  routes: baseRoute
})

3、最好修改config/index.js 中的build部分的 assetsPublicPath: '/',

build: {
        // Template for index.html
        index: path.resolve(__dirname, '../dist/index.html'),
 
        // Paths
        assetsRoot: path.resolve(__dirname, '../dist'),
        assetsSubDirectory: 'static',
        assetsPublicPath: '/',
        ....

因為我們是把打包發布后的程序放在了根目錄下,所以base 和 assetsPublicPath 都寫了 / ,如果網站訪問形式是 http://www.XXX.com/web ,則需要把 / 該為 /web/ ,否則訪問不到內容

4、webpack.prod.conf.js 添加如下代碼:

...
  const PrerenderSPAPlugin = require('prerender-spa-plugin')
  const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
 
  ...
  plugins: [
         // 在vue-cli生成的文件的基礎上,只有下面這個才是我們要配置的
    new PrerenderSPAPlugin({
        // 生成文件的路徑,也可以與webpakc打包的一致。
        // 下面這句話非常重要!!!
        // 這個目錄只能有一級,如果目錄層次大於一級,在生成的時候不會有任何錯誤提示,在預渲染的時候只會卡着不動。
        staticDir: path.join(__dirname, '../dist'),
 
        // 對應自己的路由文件,如果index有參數,則prerender-spa-plugin不適用(官方文檔有說明)
        routes: ['/','/index','/login'],
 
        // Server configuration options.
        server: {
          // Normally a free port is autodetected, but feel free to set this if needed.
          port: 80,
          proxy:{
            '/api': {
              target: 'http://www.xxx.com',
              changeOrigin: true, //是否跨域
              pathRewrite: {
                  '^/api': 'api' //需要rewrite重寫的,
              }
            }
          }
        },
        // 這個很重要,如果沒有配置這段,也不會進行預編譯
        renderer: new Renderer({ 
          // 觸發渲染的時間,用於獲取數據后再保存渲染結果
          renderAfterTime: 10000,
          // 是否打開瀏覽器,false 是打開。可用於 debug 檢查渲染結果
          headless: false
           // 在項目的main.js入口中使用 `document.dispatchEvent(new Event('render-event'))` 
        renderAfterDocumentEvent: 'render-event', // render-event: 聲明的方法名 
        })
    }),
   ...
 
  ]

5、main.js 入口文件中添加 document.dispatchEvent

...
new Vue({
  el: '#app',
  router,
  store,
  render: h => h(App),
  /* 這句非常重要,否則預渲染將不會啟動 */
  mounted() {
    document.dispatchEvent(new Event('render-event'))
  }
})

6、前面五步都執行完后,我們開始打包了

npm run build

生成dist文件夾

下面我補充一下:

安裝一個http server插件,可以直接執行dist文件夾下的index.html類似於直接把打包文件在服務器端部署運行了

1.安裝 http server

npm i http-server -g   // 全局安裝

2、進入到dist目錄

cd dist

3、啟動本地服務器

hs -o -p 9999  // 自動啟動本地dist目錄下的index.html

// 瀏覽器啟動 127.0.0.1:9999

4、至此不出意外我們看到了瀏覽器端后端返回來了html文件,支持seo爬蟲了

 

但是。。。。

有幾個坑我這里必須記錄下:

1、history模式下,修改nginx配置,不然頁面刷新會報404

#配置Nginx動靜分離,定義的靜態頁面直接從Nginx發布目錄讀取。
location / {
        alias /data/mystatic/yihao01-iotstatic/;
        try_files $uri $uri/ @router; #需要指向下面的@router否則會出現vue的路由在nginx中刷新出現404
        }
#對應上面的@router,主要原因是路由的路徑資源並不是一個真實的路徑,所以無法找到具體的文件
#因此需要rewrite到index.html中,然后交給路由在處理請求資源
location @router {
        rewrite ^.*$ /index.html last;
        }

2、修改webpack打包js的順序,否則,打包完后會報 vue項目報錯webpackJsonp is not defined

在vue單頁面應用中,我們大概都會使用CommonsChunkPlugin這個插件。 傳送門 CommonsChunkPlugin 

但是在項目經過本地測試沒有任何問題,打包上線后卻會報錯 webpackJsonp is not defined。這是因為公共文件必須在自己引用的js文件之前引用。

可以手動改文件引用,但是推薦以下解決辦法: 

找到build→webpack.prod.conf.js→找到HtmlWebpackPlugin插件,添加如下配置即可

chunks: ['manifest', 'vendor', 'app']

 

 

我是手動修改文件引用的順序的:

這樣配置后真的不會報 webpackJsonp is not defined

3、還有第三個問題目前我還在思考中,就是我的首頁做了登錄攔截,用戶沒登錄則路由跳轉之前被攔截到登錄頁面,

      加了這個pemmision.js到main.js入口文件后,我發現預渲打包后的dist目錄只有 login, static, index.html 三個文件,

   而我預渲染的是三個頁面

 routes: ['/','/index','/login'],


按照需求,應該還要生成一個index文件夾,但是沒有生成,還有index.html也沒有生成有html內容的頁面,還是只有一個<div id="app"></div>,什么內容都沒有了!!!

但是如果我刪掉登錄攔截的js后,就可以生成  index, login, static, index.html 四個文件了,而且index.html 是包含了首頁內容的文件,
目前我還沒搞清楚為什么會這樣,這個先做記錄后續知道了原因再來更新。。。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM