Nuxt.jsのHTMLから「data-n-head」などを削除する

シェアする:

この記事をおすすめしたい人

  • Nuxt.jsのHTMLから「data-n-head」を削除したい人
  • Nuxt.jsのHTMLからJavaScriptを削除したい人
  • つまりオレ

何も知らない超初心者が脱WordPressしたくてNuxt.jsでサイト構築していくシリーズです。

最近PageSpeed Insights(以下PSI)のスコアアップを目指していたんですが、PSIのスコアが気になり出すと1バイトでもいいからファイルを軽くしたくなるものでして、そうなってくると気になるのがNuxt.jsのコレ↓。

data-n-head="ssr"

静的HTMLに出力した後にもついてくるので、めちゃめちゃ気になります。

そもそもSSRちゃうやん?

他にもけっこうな数の属性をNuxt.jsは追加するので、今回はそれをばっさり削除してみようと思います。

WordPressの上でな!

※ このブログはWordPress製です

削除予定の属性一覧

Nuxt.jsが出力したHTMLをざーっと眺めて、以下の5属性を削除することに決めました。

  • data-n-head-ssr
  • data-n-head
  • data-hid
  • data-vue-ssr-id
  • data-server-rendered

静的出力した場合には不要でしょう(たぶん)。

Hooksプロパティで静的出力時のみ削除する

AMP Optimizerの時に気が狂うほど苦労したHooksプロパティを使います。

使用するフックはNuxt.js公式サイトを参考に「generate:page」です。 静的HTMLを出力する時に割り込むフックっぽい。

なので基本的なコードはこんな↓感じ。
(nuxt.config.js内)


export default {
  hooks: {
    generate: {
      page (page) {
        (略)
      },
    },
  },
}

引数「page」について

Nuxt.js公式サイトには引数が「({route, path, html})」となっていて、実際、それで実験を始めました。

ところが「html」に加工済みの値を戻せど戻せど出力結果に変化がありません。

そこでしょうがなくHooksのGenerator クラスのソースを眺めていると「this.nuxt.callHook()」でフックを定義しているっぽくて、例えば「generate:before」ならこう↓。


await this.nuxt.callHook('generate:before', this, this.options.generate)

これは「generate:before」の引数「(generator, generateOptions)」と格好が似ていますが、「generate:page」を見てみると、


await this.nuxt.callHook('generate:page', page)

と全然違います。

そもそもの引数に{}が付いているのも気になっていたので、「pageの中身を展開して受け取っているだけでは?」と考え、試しに引数を「page」とし、「page.html」を参照するとうまくいきました。

属性の削除には「cheerio」モジュールを使う

やりたいことは「特定の属性を持つタグから、その属性を削除する」です。

正規表現でもやれそうですが、jQueryと同じように要素にアクセスできるcheerioというモジュールを見つけたのでこれを使います。

jQueryと同じ書き方でいけるので楽でいいですね。

まぁ。

僕はjQueryを触ったことがないので関係ありませんが。

「cheerio」のインストールと設定

公式サイトに習い、プロジェクトフォルダへ移動し、以下のコマンドでインストールします。


$ npm install cheerio

nuxt.config.jsのmodulesプロパティに設定する必要はなく、処理時にrequireするタイプです。

完成したコード

cheerioのマニュアルを参考に出来上がったコードがコレ↓です。

初期設定だと日本語が全部URLエンコード?されちゃうので「decodeEntities」オプションをオフにしています。


export default {
  hooks: {
    generate: {
      page (page) {
        const cheerio = require('cheerio')
        const $ = cheerio.load(page.html, { decodeEntities: false })
        
        const attrs = [
          'data-n-head-ssr',
          'data-n-head',
          'data-hid',
          'data-vue-ssr-id',
          'data-server-rendered',
        ]
        
        attrs.forEach(value => {
          $('*[' + value + ']').removeAttr(value)
        })
        
        page.html = $.html()
      },
    },
}

JavaScriptの書き方を全然知らないので、慣れた人が見ると妙なコードかもしれません。

意図通り動いているのでとりあえずはOKとします。

以下、JavaScript/jQuery無知目線でのメモ書き。

謎のドルマーク

cheerioのマニュアルに書いてたので真似しましたが、「$」に値を代入しています。

正直意味が分かりません。

MDNを見ていると以下のような記述がありました。

JavaScript の識別子は必ず文字、アンダースコア (_)、あるいはドル記号 ($) から始まらなくてはなりません。

変数名の頭文字として「$」が許可されていて、その1文字だけでも変数として認識する、と捕らえればいいんでしょうか。

少し変な感じはしますが、実際に変数として機能しているのでこのまま受け入れようと思います。

forEachのアロー関数

登場するたびに僕を混乱させるアロー関数…。 慣れていかなきゃと自分でも書いてみました。

引数がどうなってるのかが分からなかったんですが、forEach()の説明を見ると、関数側で決まってるようですね。

forEachの場合だと1~3個の引数を設定できて、順番は必ず「配列の要素」「配列番号」「元の配列」の順。 変数名は自由に設定可能。

慣れると便利そう…ではある…。

cheerioのセレクタ

公式にも「jQueryっぽくいけるよ!」と書いていたので、jQueryで調べた方が書き方が見つかりやすかったです。

今回は「指定の属性を持つ全てのタグ」という意味で書いているつもりです。

Nuxt.jsが追加するJavaScriptも削除

これ、やっていいんですか?

僕が自前でJavaScriptを追加していないせいだと思うんですが、nuxt.config.jsのrenderプロパティでinjectScriptsをオフにしても、HTMLに問題が発生しないんですよね…。 SSRとかSPAの時に必要なもの?

ほんとは削除したらダメかもしれないけど現状は問題ないので、静的出力の際にはJavaScriptも削除しようと思います。

JavaScriptがあるとPageSpeed Insightsがうるさいですからね!

injectScriptsオフで簡単に削除はできますが、これだとSSR時にも削除されちゃうので、同様に「generate:page」をフックします。

まずは「rel=preload」の削除

<head>内に読み込むJavaScriptの「rel=preload」があります。


<link rel="preload" href="/_nuxt/runtime.js" as="script">
<link rel="preload" href="/_nuxt/commons.app.js" as="script">
<link rel="preload" href="/_nuxt/vendors.app.js" as="script">
<link rel="preload" href="/_nuxt/app.js" as="script">
<link rel="preload" href="/_nuxt/pages/index.js" as="script">

これまた同様にcheerioで削除。


$('link[rel="preload"][href^="/_nuxt/"][as="script"]').remove()

セレクタは「linkタグで、rel=preloadがあり、hrefで/_nuxt/から始まるファイルが指定されており、かつas=script指定があるもの」のつもりです。

ちょっと条件厳しすぎかもしれない。

今回は属性の削除ではなくタグごと削除なのでremove()を使っています。

<script>タグの削除

<body>末尾に追加される<script>タグ本体を削除します。


<script src="/_nuxt/runtime.js" defer></script>
<script src="/_nuxt/pages/index.js" defer></script>
<script src="/_nuxt/commons.app.js" defer></script>
<script src="/_nuxt/vendors.app.js" defer></script>
<script src="/_nuxt/app.js" defer></script>

こちらも先ほどと同様に↓。


$('script[src^="/_nuxt/"]').remove()

ただ、これ、自分で意図して組み込んだJavaScriptも「/_nuxt/」以下に置かれてるともろとも削除されてしまうので、その場合はきっちりファイル名までチェックかけた方がいいと思います。

残った<script>も削除

「/_nuxt/」でフィルタかけるとひとつ<script>が残ります。


<script>window.__NUXT__={(略)};</script>

まずは、<script>タグを全部拾ってきて、内側に「window.__NUXT__」を含んでいれば削除する方法。


$('script').each((i, value) => {
  if ( $(value).html().indexOf('window.__NUXT__') >= 0 ) {
    $(value).remove()
  }
})

jQueryのeachのアロー関数を書いてみましたが、引数の順序がJavaScriptのforEachとは違うんですね…。

他にも、セレクタを上手に使えば1行↓で書けるようでした。


('script:contains("window.__NUXT__")').remove()

JavaScript削除のまとめコード

上記3つの削除をまとめるとこう↓なります。


$('link[rel="preload"][href^="/_nuxt/"][as="script"]').remove()
$('script[src^="/_nuxt/"]').remove()
$('script:contains("window.__NUXT__")').remove()

まとめ

今回の削除コードのまとめです。


export default {
  hooks: {
    generate: {
      page (page) {
        const cheerio = require('cheerio')
        const $ = cheerio.load(page.html, { decodeEntities: false })
        
        const attrs = [
          'data-n-head-ssr',
          'data-n-head',
          'data-hid',
          'data-vue-ssr-id',
          'data-server-rendered',
        ]
        
        attrs.forEach(value => {
          $('*[' + value + ']').removeAttr(value)
        })
        
        $('link[rel="preload"][href^="/_nuxt/"][as="script"]').remove()
        $('script[src^="/_nuxt/"]').remove()
        $('script:contains("window.__NUXT__")').remove()
        
        page.html = $.html()
      },
    },
}

赤字の部分はNuxt.jsが読み込むJavaScriptを削除するコードなので、本当に不要な場合のみに限定した方がよさそう。

このコードの有無で、HTMLのファイルサイズが1,434バイト減らせました。 まぁ満足です!

ここまでやっておいて、「実はオプションで消せるよ」とか言われたら笑うな!

以上、WordPressからお届けしました!

Nuxt.js HEADタグ操作編の目次

シェアする: