prerender-spa-plugin 踩坑小記

wfz發表於2018-10-10

在用 prerender-spa-plugin 進行預渲染的時候遇到一些問題,這裡記錄一下,以備後查

安裝

prerender-spa-plugin 在安裝的時候需要安裝 Puppeteer、Chromium,由於這些包很大,可能會報錯,這篇文章 給瞭解決辦法,感謝!

編譯

win 下沒什麼問題,安裝後就可以執行了,可是在 centos 編譯時可能還會需要其他依賴包沒有安裝上,這 篇文章 也給出的解決辦法。

執行

編譯完成後,發現頁面上沒有 id 為 app 的 div,導致程式無法正常執行,檢查後發現由於我的入口檔案 app.vue 的內容是:

<router-view></router-view>
複製程式碼

導致編譯後頁面只有一個赤裸裸的 div ,沒有 id="app",修改後正常了:

<div id="app">
    <router-view></router-view>
</div>
複製程式碼

動態資料缺失

當上面的一切都搞定後我以為就萬事大吉了,但當跑起來後讓人再次絕望~~~

頁面裡只有基礎的 html 結構,並沒有從 api 介面請求過來的內容,如下:

<div id="app"><div class=""><header class="navigation"><div class="content"><a href="/" class="logo router-link-exact-active router-link-active"><canvas id="canvasLogo" width="100" height="72"><img src="/img/logo.61e7b9ce524391dd238ec0a3db6e8758.png"></canvas></a> <nav class="big"><ul><li><a href="/list?arttype=normal" class="">最新文章</a></li> <li><a href="/list?arttype=photos" class="">最新圖集</a></li> <li><a href="/list?categories=4" class="">寫真</a></li> <li><a href="/about" class="">關於我們</a></li> <li><a href="/contact" class="">@聯絡我</a></li> <li><div class="login-trigger"><!----> <div><a href="/auth/login?redirect=%2F" class="">登入</a> <span>|</span> <a href="/auth/register" class="">註冊</a></div></div></li></ul></nav> <div class="more"><a href="#">Follow</a> <div class="follow"><ol><li class="wb"><a href="#">wb</a></li> <li class="fb"><a href="#">fb</a></li> <li class="tw"><a href="#">tw</a></li> <li class="ins"><a href="#">ins</a></li></ol></div></div> <div class="small"><a class="trigger"><span>開啟/關閉</span></a> <!----></div></div></header> <section class="article-and-more"><h2 class="section-title"><span>推薦圖集</span></h2> <div class="loading">loading...</div> <!----> <div class="card_content"><ul class="image_card_list"></ul></div> <div class="magic-button"><a href="/list?arttype=photos" class="core">檢視更多圖集</a></div></section> <section class="article-and-more"><h2 class="section-title"><span>文章推薦</span></h2> <div class="section_content"><div class="article_list"></div> <aside class="article_more"><div class="loading">loading</div> <!----> <!----> <!----></aside></div></section> <footer class="footer"><div class="wapper"><a href="/" class="logo"><img src="/img/logo.61e7b9ce524391dd238ec0a3db6e8758.png"></a> <ul><li><a href="/privacy" class="">隱私策略</a></li> <li><a href="/copyright" class="">使用條款</a></li> <li><a href="/contact" class="">聯絡我們</a></li> <li>© 流水清清 2017</li></ul></div></footer></div></div><script src="/js/common.bf848c8c3e1cacdd2218.js" type="text/javascript"></script><script src="/js/app.bc0c303f3eeb2f32212a.js" type="text/javascript"></script>
複製程式碼

在通過偉大的 google 進行了無盡的探索後,從以下內容中得到了提示:

在入口檔案 app.js 裡,不要立即觸發 render-event,通過設定一個 setTimeout 延時觸發:

// app.js
mounted: function() {
    store.commit('initToken');
    // document.dispatchEvent(new Event('render-event')); // 不要立即觸發 render-event
    setTimeout(() => {
      document.dispatchEvent(new Event('render-event')); 
    }, 5000);
  }
複製程式碼
// webpack.config.js
 plugins: [
    // ...
   new PrerenderSPAPlugin({
      // Index.html is in the root directory.
      staticDir: path.join(__dirname, '../dist/'),
      routes: [ '/' ],
      // Optional minification.
      minify: {
        collapseBooleanAttributes: true,
        collapseWhitespace: true,
        decodeEntities: true,
        keepClosingSlash: true,
        sortAttributes: true
      },
      renderer: new Renderer({
        headless:true,
        renderAfterDocumentEvent: 'render-event'
      })
    })
]
複製程式碼

通過這些設定以後,再次編譯,得到的想到的資料:

<body>
  <div id="app">
    <div class="">
      <header class="navigation">
        ...
      </header>
      <section class="article-and-more">
        <h2 class="section-title"><span>推薦圖集</span></h2>
        <div class="card_content">
          <ul class="image_card_list">
            <li class="card_item">
              <article>
                <div class="card_item_image"><a href="/item/15" class=""><img src="http://static.fuzong.wang/Fm8RiOmuMd-XMw1_9tgZ1OPXRnVp?imageView2/1/w/500/h/500"></a></div>
                <div class="card_item_info">
                  <h3><a href="/item/15" class="">世上最美的風景.在你心裡</a></h3>
                  <aside>
                    <p class="auth"><span>by</span>admin</p>
                    <p class="parts"><a href="/list?categories=4" class="">寫真 </a><a href="/list?categories=1" class="">娛樂
                      </a><span class="times">2018-06-26 13:39:33</span></p>
                  </aside>
                </div>
              </article>
            </li>
            ...
          </ul>
        </div>
        <div class="magic-button"><a href="/list?arttype=photos" class="core">檢視更多圖集</a></div>
      </section>
      <section class="article-and-more">
        <h2 class="section-title"><span>文章推薦</span></h2>
        <div class="section_content">
          <div class="article_list">
            <article class="film_review">
              <header>
                <h3><a href="/item/11" class="">首家共享充電寶企業倒閉:押金50元被指難回本~~</a></h3>
              </header>
              <section class="main_review">
                <p>樂電上線半年宣佈停運,成首家出局企業 40元成本100元押金共享充電寶使用率達40%才能回本?</p>
              </section>
              <footer>
                <p>Posted on <time>2018-09-04 10:27:56</time> by admin</p>
              </footer>
            </article>
            ...
          </div>
          <aside class="article_more">
            <!---->
            <!---->
            <div>
              <h3>最新文章</h3>
              <ul>
                <li><a href="/item/11" class="">首家共享充電寶企業倒閉:押金50元被指難回本~~</a></li>
                <li><a href="/item/10" class="">多國為教科文組織撐腰 俄代表:沒美國工作更輕鬆</a></li>
                <li><a href="/item/9" class="">這個產業韓國比中國早起步10年 專家:中國很快反超</a></li>
                <li><a href="/item/8" class="">中韓續簽貨幣互換協議 延長3年規模560億美元</a></li>
                <li><a href="/item/7" class="">李克強:集中優勢力量攻關疑難高發癌症~</a></li>
              </ul>
            </div>
            ...
          </aside>
        </div>
      </section>
      <footer class="footer">
        ...
      </footer>
    </div>
  </div>
  <script src="/js/common.547188ec0889ef7fa247.js" type="text/javascript"></script>
  <script src="/js/app.bfd9ade52df26656f68f.js" type="text/javascript"></script>
</body>
複製程式碼

不要問我為什麼setTimeout後就取到資料了,我猜是因為 render 的時候和資料請求沒配合好,原理我也沒研究,反正這樣就能用了:)