この記事をおすすめしたい人
- Node.jsも知らんのにNuxt.jsを始めようとしてる人
- Nuxt.jsのlayouts機能が気になっている人
- つまりオレ
何も知らない超初心者が脱WordPressしたくてNuxt.jsでサイト構築していくシリーズです。
- pagesフォルダのindex.vueはトップページの内容である
- その中のtemplateタグがHTML部分である
- templateタグはHTMLの知識だけでも書ける
のようなことが分かりました。
ですがtemplateタグの中にあるのは見えている部分だけのコードで、headタグもbodyタグもありません。
今回はindex.vueが最終的なHTMLのどの部分を担当しているのか。
それを学んでいきたいと思います。
WordPressの上でな!
※ このブログはWordPress製です
このページの目次
出力されているHTMLを確認
index.vueを元に出力されたHTMLのソースを確認してみました。
構造が知りたいので簡略化します。
<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div>
<div class="container">
<div>
(ロゴ部分)
<h1 class="title">Hello World</h1>
<div class="links">
(リンク部分)
</div>
</div>
</div>
</div>
</div>
</div>
<script>(略)</script>
</body>
</html>
きちんとしたHTMLの構造になっていて、index.vueにはなかった部分もNuxt.jsが自動で生成してくれているようです。
index.vueのtemplateタグの中身
index.vueの中身を確認します。
<template>
<div class="container">
<div>
<Logo />
<h1 class="title">nuxt-test</h1>
<div class="links">
<a (略)>Documentation</a>
<a (略)>GitHub</a>
</div>
</div>
</div>
</template>
templateは「このページに使うHTMLを定義している部分ですよー」という合図なので、これを無視すると「<div class=”container”>」以下がindex.vueから参照されている部分↓(赤字)です。
<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div>
<div class="container">
<div>
(ロゴ部分)
<h1 class="title">Hello World</h1>
<div class="links">
(リンク部分)
</div>
</div>
</div>
</div>
</div>
</div>
<script>(略)</script>
</body>
</html>
赤字の部分をさらに簡略化するとこう↓。
<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div>
(index.vue)
</div>
</div>
</div>
<script>(略)</script>
</body>
</html>
だいぶシンプルになりました。
index.vue以外で何が生成されているのかが分かりやすいですね。
Nuxt.jsの「layouts」という機能
Nuxt.jsには「layouts」という機能があるようで、調べてみると「コンテンツ部分以外の共通レイアウト」を用意する機能のようです。
ヘッダやフッタ、サイドバーなどをここに記述しておけば、各ページのvueファイルではメインの部分だけ書けばいいようになるというわけです。
WordPressで言うところの「page.php」や「single.php」のような役割ですね。
さて、このレイアウト機能。
特に指定しなかった場合は「layouts」フォルダにある「default.vue」を参照するようなので、default.vueの中身を見てみます。
default.vueの中身
index.vueと同じくtemplateタグとstyleタグがあります。 初期設定ではscriptタグはありませんでしたが、追加すると機能することは確認済みです。
つまり構造的にはindex.vueと全く同じですね。
今回はHTML部分の挙動が知りたいのでtemplateタグの中身を確認してみます。
<template>
<div>
<Nuxt />
</div>
</template>
びっくりするほどシンプルです。
「Nuxt」という謎のタグが現れました。
これが何をしているのかを調べるために、外側のdivタグに目印として「default-vue」というクラス名をつけてもう一度HTMLを出力してみます。
<template>
<div class="default-vue">
<Nuxt />
</div>
</template>
結果のHTML↓。
<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div class="default-vue">
(index.vue)
</div>
</div>
</div>
<script>(略)</script>
</body>
</html>
結果から見るにNuxtタグは「ここにindex.vueの内容を表示しますよー」ってことみたいです。
つまり、default.vueが制御しているのはこの↓範囲。
<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
(default.vue)
</div>
</div>
<script>(略)</script>
</body>
</html>
それ以外の部分はNuxt.jsが生成している部分なので、赤字の部分が僕らが触れる部分です。
default.vueには何が出来るのか
初期設定のものは非常にシンプルな形をしていました。
<template>
<div>
<Nuxt />
</div>
</template>
ですが、これは全ページ共通で読み込まれる雛形のように振る舞っているので、ヘッダ、フッタ、サイドバーなどを配置しておくことができます。
<template>
<div>
<header></header>
<Nuxt />
<div class="sidebar"></div>
<footer></footer>
</div>
</template>
このようにレイアウトで共通パーツを指定しておくと、各ページでいちいち共通パーツを呼び出す必要がありません。
レイアウトやデザイン変更の際にも柔軟に対応できるよう、可能な限りレイアウトへぶち込んでおいた方がいいんでしょう。
レイアウトの注意が必要な挙動
<template>直下にはひとつの要素しか置けない
デフォルトのテンプレートがこう↓なっていて、
<template>
<div>
<Nuxt />
</div>
</template>
完全に無駄な<div>があるので、それを省くとこう↓。
<template>
<Nuxt />
</template>
この書き方はNuxt.js的にも問題ないようですが、ここに<header>やらを追加するとエラーが出ます。
<template>
<header></header>
<Nuxt />
</template>
エラー内容はこれ↓。
Errors compiling template:
Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead.
<template>直下にはひとつの要素しか置けませんよ、と。
なので他のパーツを置く際には<div>などで囲ってやらないといけません。
<template>
<div>
<header></header>
<Nuxt />
</div>
</template>
うーむ…。
このすぐ外側に<div id="__layout">があるのに何故なんでしょう。 なんか気持ち悪い。
外部CSSを利用する場合、importはNG
例えば以下のような構成。
- default.vue(下層ページのレイアウト)
- home.vue(トップページのレイアウト)
それぞれのレイアウトで別の外部CSSを読み込むとします。
<script>
import '@/assets/css/default.css'
//home.vueの場合はこっち
//import '@/assets/css/home.css'
</script>
このimportを使ったやり方でCSSを読み込むと、全てのCSSがどのページでも読み込まれてしまいました。
おそらくNuxt.jsが事前に全てのレイアウトを読み込み、その際に全てインポートしてしまうせいでしょう。
これを防ぐには次のやり方でCSSを読み込む必要があるようです。
<style src="@/assets/css/default.css">
(略)
</style>
<style>タグのsrcに指定する方法です。 このやり方だと「default.css」の中身と「(略)」の部分のスタイルが両方読み込まれ、他のページへは影響しません。
CSSプロパティで外部CSSを指定する方法↓も試してみましたが、こちらは読み込みすらしませんでした。
<script>
export default {
css: [
{ src: '~/assets/css/default.css' },
],
};
</script>
nuxt.config.js内だとこれでいけるんですけどね…。
実はこの方法でもスタイルは残っている
上の方法で無事に、<head>の<style>タグにCSSは展開されなくなるんですが、default.cssの内容がトップページにも適用されてしまいます。
ファイル名でgrepかけてみると「/_nuxt/app.js」の中でdefault.cssを読み込んでいるような感じ…。
(↑JavaScript苦手)
う~ん…。
こういう挙動であることを前提にメンテナンスしないとダメですね…。
あとこれ、レイアウト増えて、レイアウト毎にCSS分けてたら「/_nuxt/app.js」のロード時間がどんどん増えていくのでは…。
index.vueはコンテンツ部分のみを担当している
index.vueはやろうと思えばページの内容を全部書くこともできますが、これはメンテナンス性がよくありません。
(共通パーツに変更が入った場合など)
今回触れたレイアウトや、次回お話しするコンポーネントを駆使することによって、index.vueに「そのページのコンテンツのみ」管理させるのが、コンテンツ製作に注力しやすい、良い構造なんじゃないかと思います。
まとめるとこんな↓構造になるのかな。
それでは次回はもうひとつの機能「components」についてお勉強しまーす!
以上、WordPressからお届けしました!
Nuxt.js ページ作成編の目次
- 第1回 index.vueをいじってみた
- 第2回 ページの追加とリンクの設定
- 第3回 layoutsについて(このページ)
- 第4回 componentsについて