2020年3月30日 更新

【備忘録】Nuxt.jsでJAMstackサイトを作るときのハマりポイント

Nuxt.jsでJAMstackを開発するにあたって筆者自身が躓いたポイントとその解決方法について、備忘録として残しておきます。同じような場面に遭遇した際に解決の糸口になれば幸いです。

nuxt generateしても生成されたHTMLの中身が空なんだけど・・?

nuxt generate(npmの場合はnpm run generate、yarnの場合はyarn generate)のコマンドを実行すると静的化されたindex.htmlが生成されると公式サイトに書いてあります。じゃあ実際にやってみよう!としてコマンドを叩いてみます。

sh-3.2# yarn generate
yarn run v1.22.0
$ nuxt generate
ℹ Production build                                                                                                         14:26:14
✔ Builder initialized                                                                                                        14:26:14
✔ Nuxt files generated                                                                                                       14:26:14

✔ Client
 Compiled successfully in 4.14s


Hash: f7ece106df30a97b78db
Version: webpack 4.41.6
Time: 4140ms
Built at: 2020-03-16 14:26:19
             Asset    Size Chunks             Chunk Names
../server/client.manifest.json  8.13 KiB     [emitted]        
    0db2bf4bc93cff6e695c.js  5.77 KiB    3 [emitted] [immutable] pages/index
    476bfcc8be385302226d.js  3.15 KiB    2 [emitted] [immutable] pages/contact
    98672295aeb35cfbf08f.js  164 KiB    1 [emitted] [immutable] commons.app
           LICENSES 389 bytes     [emitted]        
    e1d2b016a29d974242c5.js  4.3 KiB    5 [emitted] [immutable]  
    e46e6e01d4aa6b3718b6.js  47.9 KiB    0 [emitted] [immutable] app
    f2f8341d29ed552b90fe.js  2.35 KiB    4 [emitted] [immutable] runtime
   icons/icon_120.5f6a36.png  4.68 KiB     [emitted]        
   icons/icon_144.5f6a36.png  5.8 KiB     [emitted]        
   icons/icon_152.5f6a36.png  6.1 KiB     [emitted]        
   icons/icon_192.5f6a36.png  7.83 KiB     [emitted]        
   icons/icon_384.5f6a36.png  18.1 KiB     [emitted]        
   icons/icon_512.5f6a36.png   20 KiB     [emitted]        
   icons/icon_64.5f6a36.png  2.35 KiB     [emitted]        
    manifest.cb11056c.json 780 bytes     [emitted]        
 + 1 hidden asset
Entrypoint app = f2f8341d29ed552b90fe.js 98672295aeb35cfbf08f.js e46e6e01d4aa6b3718b6.js
ℹ Generating pages                                                                                                         14:26:19
✔ Generated /contact                                                                                                        14:26:19
✔ Generated /                                                                                                            14:26:19
✨ Done in 5.90s.


できたっぽい!
それでdistディレクトリを見にいくと、

sh-3.2# ls -l
total 80
-rw-r--r--  1 root admin   0 3 16 14:26 .nojekyll
-rw-r--r--  1 root admin  3520 3 16 14:26 200.html
-rw-r--r--  1 root admin  435 3 16 14:26 README.md
drwxr-xr-x 11 root admin  352 3 16 14:26 _nuxt
drwxr-xr-x  4 root admin  128 3 16 14:26 admin
drwxr-xr-x  3 root admin   96 3 16 14:26 contact
-rw-r--r--  1 root admin  1393 3 16 14:26 favicon.ico
-rw-r--r--  1 root admin  242 3 16 14:26 form.html
-rw-r--r--  1 root admin 12699 3 16 14:26 icon.png
drwxr-xr-x  3 root admin   96 3 16 14:26 img
-rw-r--r--  1 root admin  3520 3 16 14:26 index.html
-rw-r--r--  1 root admin  995 3 16 14:26 sw.js


いい感じ!index.htmlとかcontact.htmlが出来てますね。
で、中身を確認してみます。

sh-3.2# cat index.html 
<!doctype html>
<html lang="en" data-n-head="%7B%22lang%22:%7B%221%22:%22en%22%7D%7D">
 <head>
  <title>netlify-nuxt</title><meta data-n-head="1" charset="utf-8"><meta data-n-head="1" name="viewport" content="width=device-width,initial-scale=1"><meta data-n-head="1" data-hid="description" name="description" content="My fantastic Nuxt.js project"><meta data-n-head="1" data-hid="mobile-web-app-capable" name="mobile-web-app-capable" content="yes"><meta data-n-head="1" data-hid="apple-mobile-web-app-title" name="apple-mobile-web-app-title" content="netlify-nuxt"><meta data-n-head="1" data-hid="author" name="author" content="sho-zy"><meta data-n-head="1" data-hid="theme-color" name="theme-color" content="#fff"><meta data-n-head="1" data-hid="og:type" name="og:type" property="og:type" content="website"><meta data-n-head="1" data-hid="og:title" name="og:title" property="og:title" content="netlify-nuxt"><meta data-n-head="1" data-hid="og:site_name" name="og:site_name" property="og:site_name" content="netlify-nuxt"><meta data-n-head="1" data-hid="og:description" name="og:description" property="og:description" content="My fantastic Nuxt.js project"><link data-n-head="1" rel="icon" type="image/x-icon" href="/favicon.ico"><link data-n-head="1" rel="manifest" href="/_nuxt/manifest.cb11056c.json"><link data-n-head="1" rel="shortcut icon" href="/_nuxt/icons/icon_64.5f6a36.png"><link data-n-head="1" rel="apple-touch-icon" href="/_nuxt/icons/icon_512.5f6a36.png" sizes="512x512"><link rel="preload" href="/_nuxt/f2f8341d29ed552b90fe.js" as="script"><link rel="preload" href="/_nuxt/98672295aeb35cfbf08f.js" as="script"><link rel="preload" href="/_nuxt/e46e6e01d4aa6b3718b6.js" as="script">
 </head>
 <body>
  <div id="__nuxt"><style>#nuxt-loading{visibility:hidden;opacity:0;position:absolute;left:0;right:0;top:0;bottom:0;display:flex;justify-content:center;align-items:center;flex-direction:column;animation:nuxtLoadingIn 10s ease;-webkit-animation:nuxtLoadingIn 10s ease;animation-fill-mode:forwards;overflow:hidden}@keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}@-webkit-keyframes nuxtLoadingIn{0%{visibility:hidden;opacity:0}20%{visibility:visible;opacity:0}100%{visibility:visible;opacity:1}}#nuxt-loading>div,#nuxt-loading>div:after{border-radius:50%;width:5rem;height:5rem}#nuxt-loading>div{font-size:10px;position:relative;text-indent:-9999em;border:.5rem solid #f5f5f5;border-left:.5rem solid #fff;-webkit-transform:translateZ(0);-ms-transform:translateZ(0);transform:translateZ(0);-webkit-animation:nuxtLoading 1.1s infinite linear;animation:nuxtLoading 1.1s infinite linear}#nuxt-loading.error>div{border-left:.5rem solid #ff4500;animation-duration:5s}@-webkit-keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes nuxtLoading{0%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}</style><script>window.addEventListener("error",function(){var e=document.getElementById("nuxt-loading");e&&(e.className+=" error")})</script><div id="nuxt-loading" aria-live="polite" role="status"><div>Loading...</div></div></div>
 <script type="text/javascript" src="/_nuxt/f2f8341d29ed552b90fe.js"></script><script type="text/javascript" src="/_nuxt/98672295aeb35cfbf08f.js"></script><script type="text/javascript" src="/_nuxt/e46e6e01d4aa6b3718b6.js"></script></body>
</html>


一見上手くいってそうに見えますが、 bodyタグの中身がありませんねぇ・・・
おかしい・・・これは静的化されていないじゃん・・・

という事象がありました。

こんな時はnuxt.config.jsmodeを確認してみましょう!
「SPA」モードになっていませんか?

実は「Universal」モードで実行しないと正しく静的化されないのです。

実際に変更して再度nuxt generateしてみます。

sh-3.2# yarn generate
yarn run v1.22.0
$ nuxt generate
ℹ Production build                                                                                                         14:38:40
✔ Builder initialized                                                                                                        14:38:40
✔ Nuxt files generated                                                                                                       14:38:40

✔ Client
 Compiled successfully in 4.25s

✔ Server
 Compiled successfully in 955.57ms


Hash: 7870e0bb8803edb865c7
Version: webpack 4.41.6
Time: 4254ms
Built at: 2020-03-16 14:38:45
             Asset    Size Chunks             Chunk Names
../server/client.manifest.json  8.16 KiB     [emitted]        
    0db2bf4bc93cff6e695c.js  5.77 KiB    3 [emitted] [immutable] pages/index
    476bfcc8be385302226d.js  3.15 KiB    2 [emitted] [immutable] pages/contact
    7595360bec8e3948b6bf.js  47.9 KiB    0 [emitted] [immutable] app
    98672295aeb35cfbf08f.js  164 KiB    1 [emitted] [immutable] commons.app
           LICENSES 389 bytes     [emitted]        
    e1d2b016a29d974242c5.js  4.3 KiB    5 [emitted] [immutable]  
    f2f8341d29ed552b90fe.js  2.35 KiB    4 [emitted] [immutable] runtime
   icons/icon_120.5f6a36.png  4.68 KiB     [emitted]        
   icons/icon_144.5f6a36.png  5.8 KiB     [emitted]        
   icons/icon_152.5f6a36.png  6.1 KiB     [emitted]        
   icons/icon_192.5f6a36.png  7.83 KiB     [emitted]        
   icons/icon_384.5f6a36.png  18.1 KiB     [emitted]        
   icons/icon_512.5f6a36.png   20 KiB     [emitted]        
   icons/icon_64.5f6a36.png  2.35 KiB     [emitted]        
    manifest.cb11056c.json 780 bytes     [emitted]        
 + 2 hidden assets
Entrypoint app = f2f8341d29ed552b90fe.js 98672295aeb35cfbf08f.js 7595360bec8e3948b6bf.js

Hash: 4fa54700dcd0ba67f76f
Version: webpack 4.41.6
Time: 956ms
Built at: 2020-03-16 14:38:46
         Asset    Size Chunks             Chunk Names
43634cd07bbbcddbd278.js  5.55 KiB    2 [emitted] [immutable] pages/index
b9505899fc2e9573d9c5.js  1.93 KiB    1 [emitted] [immutable] pages/contact
       server.js  28.8 KiB    0 [emitted]       app
  server.manifest.json 203 bytes     [emitted]        
Entrypoint app = server.js
ℹ Generating pages                                                                                                         14:38:46
✔ Generated /contact                                                                                                        14:38:46
✔ Generated /                                                                                                            14:38:46
✨ Done in 7.27s.


今度はサーバーのビルドも走りました。
出力ファイルを見てみます。

sh-3.2# cat index.html 
<!doctype html>
<html data-n-head-ssr lang="en" data-n-head="%7B%22lang%22:%7B%22ssr%22:%22en%22%7D%7D">
 <head>
  <title>netlify-nuxt</title><meta data-n-head="ssr" charset="utf-8"><meta data-n-head="ssr" name="viewport" content="width=device-width,initial-scale=1"><meta data-n-head="ssr" data-hid="description" name="description" content="My fantastic Nuxt.js project"><meta data-n-head="ssr" data-hid="mobile-web-app-capable" name="mobile-web-app-capable" content="yes"><meta data-n-head="ssr" data-hid="apple-mobile-web-app-title" name="apple-mobile-web-app-title" content="netlify-nuxt"><meta data-n-head="ssr" data-hid="author" name="author" content="sho-zy"><meta data-n-head="ssr" data-hid="theme-color" name="theme-color" content="#fff"><meta data-n-head="ssr" data-hid="og:type" name="og:type" property="og:type" content="website"><meta data-n-head="ssr" data-hid="og:title" name="og:title" property="og:title" content="netlify-nuxt"><meta data-n-head="ssr" data-hid="og:site_name" name="og:site_name" property="og:site_name" content="netlify-nuxt"><meta data-n-head="ssr" data-hid="og:description" name="og:description" property="og:description" content="My fantastic Nuxt.js project"><link data-n-head="ssr" rel="icon" type="image/x-icon" href="/favicon.ico"><link data-n-head="ssr" rel="manifest" href="/_nuxt/manifest.cb11056c.json"><link data-n-head="ssr" rel="shortcut icon" href="/_nuxt/icons/icon_64.5f6a36.png"><link data-n-head="ssr" rel="apple-touch-icon" href="/_nuxt/icons/icon_512.5f6a36.png" sizes="512x512"><script data-n-head="ssr" src="https://identity.netlify.com/v1/netlify-identity-widget.js"></script><link rel="preload" href="/_nuxt/f2f8341d29ed552b90fe.js" as="script"><link rel="preload" href="/_nuxt/98672295aeb35cfbf08f.js" as="script"><link rel="preload" href="/_nuxt/7595360bec8e3948b6bf.js" as="script"><link rel="preload" href="/_nuxt/0db2bf4bc93cff6e695c.js" as="script"><style data-vue-ssr-id="3191d5ad:0 932a8f60:0 6759f5ab:0 e46b6ba2:0 377d51af:0">.nuxt-progress{position:fixed;top:0;left:0;right:0;height:2px;width:0;opacity:1;transition:width .1s,opacity .4s;background-color:#fff;z-index:999999}.nuxt-progress.nuxt-progress-notransition{transition:none}.nuxt-progress-failed{background-color:red}html{font-family:Source Sans Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-size:16px;word-spacing:1px;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;box-sizing:border-box}*,:after,:before{box-sizing:border-box;margin:0}.button--green{display:inline-block;border-radius:4px;border:1px solid #3b8070;color:#3b8070;text-decoration:none;padding:10px 30px}.button--green:hover{color:#fff;background-color:#3b8070}.button--grey{display:inline-block;border-radius:4px;border:1px solid #35495e;color:#35495e;text-decoration:none;padding:10px 30px;margin-left:15px}.button--grey:hover{color:#fff;background-color:#35495e}.container{margin:0 auto;min-height:100vh;display:flex;justify-content:center;align-items:center;text-align:center}.title{font-family:Quicksand,Source Sans Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;display:block;font-weight:300;font-size:55px;color:#35495e;letter-spacing:1px;text-transform:capitalize;margin:25px 0}.subtitle{font-weight:300;font-size:1.1rem;color:#526488;word-spacing:2px;padding-bottom:15px;max-width:600px}.subtitle a{font-weight:500;color:inherit}.links{padding-top:15px;margin-bottom:20px}.content-logos{display:flex;align-items:center;justify-content:center;min-width:500px}.plus{font-size:2.5rem;margin:15px;color:#35495e}.h3{font-family:Quicksand,Source Sans Pro,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;font-weight:400;margin:10px}.NuxtLogo{-webkit-animation:appear 1s;animation:appear 1s;margin:auto}@-webkit-keyframes appear{0%{opacity:0}to{opacity:1}}@keyframes appear{0%{opacity:0}to{opacity:1}}.vuesax-logo{width:100%;max-width:170px}.vuesax-logo svg{width:100%;fill:#35495e}</style>
 </head>
 <body>
  <div data-server-rendered="true" id="__nuxt"><!----><div id="__layout"><div><div class="container"><div><header class="content-logos"><svg width="245" height="180" viewBox="0 0 452 342" xmlns="http://www.w3.org/2000/svg" class="NuxtLogo"><g fill="none" fill-rule="evenodd"><path d="M139 330l-1-2c-2-4-2-8-1-13H29L189 31l67 121 22-16-67-121c-1-2-9-14-22-14-6 0-15 2-22 15L5 303c-1 3-8 16-2 27 4 6 10 12 24 12h136c-14 0-21-6-24-12z" fill="#00C58E"></path> <path d="M447 304L317 70c-2-2-9-15-22-15-6 0-15 3-22 15l-17 28v54l39-67 129 230h-49a23 23 0 0 1-2 14l-1 1c-6 11-21 12-23 12h76c3 0 17-1 24-12 3-5 5-14-2-26z" fill="#108775"></path> <path d="M376 330v-1l1-2c1-4 2-8 1-12l-4-12-102-178-15-27h-1l-15 27-102 178-4 12a24 24 0 0 0 2 15c4 6 10 12 24 12h190c3 0 18-1 25-12zM256 152l93 163H163l93-163z" fill="#2F495E" fill-rule="nonzero"></path></g></svg> <span class="plus">+</span> <div class="vuesax-logo"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 680.69 725.78"><title>Recurso 47</title> <g id="Capa_2" data-name="Capa 2"><g id="Capa_1-2" data-name="Capa 1"><polygon points="680.42 59.35 555.03 59.35 340.34 391.82 125.67 59.35 0.27 59.35 340.35 586 680.42 59.35"></polygon> <polygon points="340.34 644.59 52.42 198.71 0 198.71 340.33 725.78 680.69 198.71 628.26 198.71 340.34 644.59"></polygon> <polygon points="518.83 10.13 340.33 281.52 161.87 10.13 293.21 43.27 293.21 0 387.48 0 387.48 43.27 518.83 10.13"></polygon></g></g></svg></div></header> <h1 class="title">
   Nuxt.js + Vuesax
  </h1> <h2 class="subtitle"><a href="https://vuesax.com/">Vuesax</a> is a framework of ui components
   for <a href="https://vuejs.org/">Vuejs</a>, It was created to make new
   interfaces that have a new trend and are visually beautiful
  </h2> <div class="links"><h3 class="h3">
    Vuesax
   </h3> <a href="https://vuesax.com/" target="_blank" class="button--green">
    Documentation
   </a> <a href="https://discordapp.com/invite/9dsKtvB" target="_blank" class="button--grey">
    Discord
   </a> <a href="https://github.com/lusaxweb/vuesax" target="_blank" class="button--grey">
    GitHub
   </a></div> <div class="links"><h3 class="h3">
    Nuxt.js
   </h3> <a href="https://nuxtjs.org/" target="_blank" class="button--green">
    Documentation
   </a> <a href="https://github.com/nuxt/nuxt.js" target="_blank" class="button--grey">
    GitHub
   </a></div></div></div></div></div></div><script>window.__NUXT__={layout:"default",data:[{}],error:null,serverRendered:!0}</script><script src="/_nuxt/f2f8341d29ed552b90fe.js" defer></script><script src="/_nuxt/0db2bf4bc93cff6e695c.js" defer></script><script src="/_nuxt/98672295aeb35cfbf08f.js" defer></script><script src="/_nuxt/7595360bec8e3948b6bf.js" defer></script>
 </body>
</html>


bodyタグの中身がしっかり出てる!
これで無事、静的化されました👏

動的ルーティングページが生成されない・・・?

ブログやECサイトなど、必ず実装するであろう動的ページについてです。
例えば下記の構成でページを用意したとします。

page/
 ┗index.vue
 ┗_slug.vue


また、_slug.vueには「page1」「page2」のページが存在するとします。
この時nuxt generateを実行すると、

sh-3.2# yarn generate
yarn run v1.22.0
$ nuxt generate
OgpGenerater:start                                                                                                         15:06:08
OgpGenerater:finish                                                                                                         15:06:08
ℹ Production build                                                                                                         15:06:08
✔ Builder initialized                                                                                                        15:06:08
✔ Nuxt files generated                                                                                                       15:06:08

✔ Client
 Compiled successfully in 4.02s

✔ Server
 Compiled successfully in 893.25ms


Hash: da668f3b0a1e64e360ba
Version: webpack 4.42.0
Time: 4027ms
Built at: 2020-03-16 15:06:12
             Asset    Size Chunks             Chunk Names
../server/client.manifest.json   7 KiB     [emitted]        
    0ea42793f04152981ea9.js  2.88 KiB    2 [emitted] [immutable] pages/_slug
    30e904c4e756d0fe8c49.js  2.33 KiB    4 [emitted] [immutable] runtime
    84b92d46d7719fcfa224.js  3.04 KiB    3 [emitted] [immutable] pages/index
    916e57f2f628f5a93b60.js  151 KiB    1 [emitted] [immutable] commons.app
           LICENSES 389 bytes     [emitted]        
    aa64ef1b2a4c254bf743.js   43 KiB    0 [emitted] [immutable] app
 + 2 hidden assets
Entrypoint app = 30e904c4e756d0fe8c49.js 916e57f2f628f5a93b60.js aa64ef1b2a4c254bf743.js

Hash: cabdd36e6f8d1b9ad16b
Version: webpack 4.42.0
Time: 894ms
Built at: 2020-03-16 15:06:13
         Asset    Size Chunks             Chunk Names
0547ecc69c21437607a2.js  2.64 KiB    1 [emitted] [immutable] pages/_slug
6230783e481d889cea72.js  3.13 KiB    2 [emitted] [immutable] pages/index
       server.js   26 KiB    0 [emitted]       app
  server.manifest.json 203 bytes     [emitted]        
Entrypoint app = server.js
ℹ Generating pages                                                                                                         15:06:13
✔ Generated /                                                                                                            15:06:13
✨ Done in 7.39s.


あれ・・・出来てなさそう?
一縷の望みをかけてdistディレクトリを見てみます。

sh-3.2# ls -l dist
total 72
-rw-r--r-- 1 root admin   0 3 16 15:06 .nojekyll
-rw-r--r-- 1 root admin  2448 3 16 15:06 200.html
-rw-r--r-- 1 root admin  435 3 16 15:06 README.md
drwxr-xr-x 8 root admin  256 3 16 15:06 _nuxt
-rw-r--r-- 1 root admin  1393 3 16 15:06 favicon.ico
drwxr-xr-x 3 root admin   96 3 16 15:06 font
-rw-r--r-- 1 root admin 12699 3 16 15:06 icon.png
drwxr-xr-x 4 root admin  128 3 16 15:06 img
-rw-r--r-- 1 root admin  4371 3 16 15:06 index.html
drwxr-xr-x 5 root admin  160 3 16 15:06 ogp


index.htmlしかありませんね。page1.htmlとかpage2.htmlは案の定ありませんでした・・・

実は、動的ルーティングの場合は自動で出力してくれないのです。「こんなルーティングがあるよ」とnuxt.config.jsに定義して教えてあげないといけません。
設定する場所は、nuxt.config.jsgenerateの中です。下記のように定義します。

  generate: {
    routes() {
      const routes = []
      const fs = require('fs')
      const fileNames = fs.readdirSync('./data')
      for (const key in fileNames) {
        const page = JSON.parse(
          fs.readFileSync('./data/' + fileNames[key], 'utf8')
        )
        routes.push({
          route: '/' + page.slug,
          payload: page
        })
      }
      return routes
    }
  }


解説すると、dataディレクトリの中にあるJsonファイルを取得して、「route」にURL、「payload」にJsonデータを渡しています。
そしてnuxt generateしてみます。

sh-3.2# yarn generate
yarn run v1.22.0
$ nuxt generate
OgpGenerater:start                                                                                                         15:18:40
OgpGenerater:finish                                                                                                         15:18:41
ℹ Production build                                                                                                         15:18:41
✔ Builder initialized                                                                                                        15:18:41
✔ Nuxt files generated                                                                                                       15:18:41

✔ Client
 Compiled successfully in 4.01s

✔ Server
 Compiled successfully in 891.94ms


Hash: da668f3b0a1e64e360ba
Version: webpack 4.42.0
Time: 4007ms
Built at: 2020-03-16 15:18:45
             Asset    Size Chunks             Chunk Names
../server/client.manifest.json   7 KiB     [emitted]        
    0ea42793f04152981ea9.js  2.88 KiB    2 [emitted] [immutable] pages/_slug
    30e904c4e756d0fe8c49.js  2.33 KiB    4 [emitted] [immutable] runtime
    84b92d46d7719fcfa224.js  3.04 KiB    3 [emitted] [immutable] pages/index
    916e57f2f628f5a93b60.js  151 KiB    1 [emitted] [immutable] commons.app
           LICENSES 389 bytes     [emitted]        
    aa64ef1b2a4c254bf743.js   43 KiB    0 [emitted] [immutable] app
 + 2 hidden assets
Entrypoint app = 30e904c4e756d0fe8c49.js 916e57f2f628f5a93b60.js aa64ef1b2a4c254bf743.js

Hash: cabdd36e6f8d1b9ad16b
Version: webpack 4.42.0
Time: 893ms
Built at: 2020-03-16 15:18:46
         Asset    Size Chunks             Chunk Names
0547ecc69c21437607a2.js  2.64 KiB    1 [emitted] [immutable] pages/_slug
6230783e481d889cea72.js  3.13 KiB    2 [emitted] [immutable] pages/index
       server.js   26 KiB    0 [emitted]       app
  server.manifest.json 203 bytes     [emitted]        
Entrypoint app = server.js
ℹ Generating pages                                                                                                         15:18:46
✔ Generated /                                                                                                            15:18:46
✔ Generated /page1                                                                                                         15:18:46
✔ Generated /page2                                                                                                         15:18:46
✨ Done in 7.56s.


お、今度は上手くいってそうです。
distディレクトリを見てみます。

sh-3.2# ls -l dist
total 72
-rw-r--r-- 1 root admin   0 3 16 15:18 .nojekyll
-rw-r--r-- 1 root admin  2448 3 16 15:18 200.html
-rw-r--r-- 1 root admin  435 3 16 15:18 README.md
drwxr-xr-x 8 root admin  256 3 16 15:18 _nuxt
-rw-r--r-- 1 root admin  1393 3 16 15:18 favicon.ico
drwxr-xr-x 3 root admin   96 3 16 15:18 font
-rw-r--r-- 1 root admin 12699 3 16 15:18 icon.png
drwxr-xr-x 4 root admin  128 3 16 15:18 img
-rw-r--r-- 1 root admin  4371 3 16 15:18 index.html
drwxr-xr-x 5 root admin  160 3 16 15:18 ogp
drwxr-xr-x 3 root admin   96 3 16 15:18 page1
drwxr-xr-x 3 root admin   96 3 16 15:18 page2


「page1」「page2」というディレクトリが出来ていますね。
中を見てみます。

sh-3.2# ls -l dist/page1
total 8
-rw-r--r-- 1 root admin 3858 3 16 15:18 index.html


ありました!これで動的ページの生成も完了です!

ちなみに「payload」ですが設定は任意です。
動的ページの中で、

<script>
export default {
  async asyncData({ params, error, payload }) {
    if (payload) {
      return { page: payload }
    } else {
      return { page: await require(`~/data/${params.slug}.json`) }
    }
  },


このように設定しておくとclientとserverのビルドでそれぞれファイル読み込みせず、2度目はpayloadからデータを取得するように出来ます。
例えばAPIのコール制限などあった場合にコール回数を抑える事が出来るので有効です。

サーバーサイドとクライアントサイドのDOM構造が一致しない・・・?

JAMstackな開発をしていて下記のようなコンソールエラーが出る場合があります。

Mismatching childNodes vs. VNodes


vue.runtime.esm.js?2b0e:619 [Vue warn]: The client-side rendered virtual DOM tree is not matching server-rendered content. This is likely caused by incorrect HTML markup, for example nesting block-level elements inside <p>, or missing <tbody>. Bailing hydration and performing full client-side render.


これは、createされた後にDOM構造に変更があった場合に起こるようです。
例えば、レスポンシブ対応するために画面幅で表示を出しわけしたり、子コンポーネントから親コンポーネントにemitして親コンポーネントの表示が変わったりなど。
この場合は構造不一致の対象となる部分を<client-only>タグで下記のように囲ってあげましょう。

<client-only>
  [対象部分]
<client-only>


するとエラーが回避できます。
但し、該当部分は静的サイトとして出力されないのでご注意ください。


躓きポイントは以上です!
また何かあった場合は追記していこうと思います。
記事についての質問や、ここも躓いた!などありましたらお問い合わせより連絡ください。
出来るだけお答えしたいなと思っています。

それでは失礼します!