GAミント至上主義

Web Monomaniacal Developer.

NuxtJSでhead内のbaseタグをhooksを使って無理やり消してAMPエラー解消した

ちょっと無理やりなややこしいことをしたのでその経緯を含めてメモ。設定でできるようになるといいな。

NuxtJSでAMP対応をしてますが、router.baseを設定しサブディレクトリに公開しているため、headにbaseタグが入ってしまい、これがAMPテストツールのエラーの原因になっていました。

テストツールはこれ→https://search.google.com/test/amp?hl=ja


f:id:uyamazak:20200702184539p:plain

一通りググったけどそれらしい方法は見つからず。
サブディレクトリかつ、AMP対応というレアケースのためでしょうか。

API: router プロパティ - NuxtJS

ドキュメントには

base がセットされているときは Nuxt.js はドキュメントのヘッダーに を追加します。

と書いてあるだけで消し方などは書いてありません。

pageファイル内のhead()で試しましたがダメ。

ということでソースコードにあたりました。デフォルトブランチへのリンクなので変わってしまうかも。

今日(2020/7/2)時点のdevブランチだと、SSRの場合ここでbaseタグを挿入してます。
github.com

文字列連結してるのでhead()でいじれないのは当たり前でした。

    // Add <base href=""> meta if router base specified
    if (this.options._routerBaseSpecified) {
      HEAD += `<base href="${this.options.router.base}">`
    }

this.options._routerBaseSpecifiedを変える手もあるかと思いましたが今後、他でも使われるかもしれないし、_がついてるので触っちゃだめなはず。nuxt.config.jsからも渡せません。

何か方法はないものかと、ソースコードをたどるとhookというものを見つけました。

https://github.com/nuxt/nuxt.js/blob/dev/packages/vue-renderer/src/renderers/ssr.js#L268

await this.serverContext.nuxt.callHook('vue-renderer:ssr:templateParams', templateParams, renderContext)

hookの使い方の例はここにありました。
API: hooks プロパティ - NuxtJS

import fs from 'fs'
import path from 'path'

export default {
  hooks: {
    build: {
      done (builder) {
        const extraFilePath = path.join(builder.nuxt.options.buildDir, 'extra-file')
        fs.writeFileSync(extraFilePath, 'Something extra')
      }
    }
  }
}

ということでやってみた。vue-renderer:ssr:templateParamsをコロンで切ってオブジェクト化して、最後を関数にすればいいらしい。


nuxt.config.js

export default {
  hooks: {
    'vue-renderer': {
      ssr: {
        templateParams(templateParams, renderContext) {
          // AMPページでbaseタグを無理やり消してる
         if (renderContext.url && renderContext.url.match(/\/amp\/?$/)) {
            templateParams.HEAD = templateParams.HEAD.replace(
              `<base href="${BASE_PATH}/">`,
              ''
            )
            console.log('base tag removed', renderContext.url)
          }
        },
      },
    },
  },

今回baseタグを消すのは、AMPページだけでいいので判定にはrenderContext.urlの最後に/amp/が付いているかどうかを使いました。
というかこれぐらいしか見つからなかった。

これで無事?AMPページだけ消えました。
設定でやりたいから要望、プルリクを思ったけどレアケースかもしれないので悩んでる。

Nuxt.jsビギナーズガイド

Nuxt.jsビギナーズガイド

Vue.js&Nuxt.js超入門

Vue.js&Nuxt.js超入門

Vue.js (NuxtJS) + TypeScriptでSlickを使うならvue-slick-carouselがおすすめ

デザイナーさんが作ったHTML + CSSをNuxtJS + TypeScript化していましたが、カルーセルにslickというライブラリが使われていました。

レスポンシブにも対応していて、非常に高機能です。

kenwheeler.github.io


しかし、jQueryに依存しており、メンテナンス性や、ファイルサイズ的によろしくないので代替案を探しました。

結論

結論としてはvue-slick-carouselを使いました。
slickと互換性もあり、TypeScriptの型定義はなかったもののSSRにも対応していて素晴らしい。

www.npmjs.com


他の選択肢

Vueのコンポーネントとして使えるだけで、結局jQueryを使うし、メンテが終わっているのでNG
github.com


シンプルで良かったけどwindowを使っており、SSR対応が面倒そうだったのでNG
ssense.github.io

PC画面で3つ表示させたいけど対応してなかった、機能的にNG。関係ないけどMacへのインストール大変だった。
vuetifyjs.com

型定義

TypeScriptでエラーが出てしまうので、とりあえずdeclareだけしました。型書きたい。

# ./types/vue-slick-carousel.d.ts
declare module 'vue-slick-carousel'
# tsconfig.json
// 省略
"types": [
      "@types/node",
      "@nuxt/types",
      "./types/"
    ]
// 省略


プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

  • 作者:Boris Cherny
  • 発売日: 2020/03/16
  • メディア: 単行本(ソフトカバー)
Nuxt.jsビギナーズガイド

Nuxt.jsビギナーズガイド

Firebase Functions + TypeScriptで複数リージョン指定する方法

デフォルトでus-central1で動くFirebase Functionsですが、やっぱりネットワークでレスポンス遅くなるので日本でも動かしたいなと思ってやってみたら下記のエラーが起きたのでメモ。

Cloud Functions のロケーション  |  Firebase

functions.region() でカンマ区切りの複数のリージョン文字列を渡すことで、複数のリージョンを指定できます。推奨手順の詳細については、関数のリージョンを変更するをご覧ください。

「カンマ区切りの複数のリージョン文字列」って'us-central1,asia-northeast1'だろって思って書いたのが下記。

# だめだったコード1
export const example = functions
  .region('us-central1,asia-northeast1')
  .https
  .onRequest(app)

エラー内容↓

Error: The only valid regions are: us-central1, us-east1, us-east4, europe-west1, europe-west2, europe-west3, asia-east2, asia-northeast1

TypeScriptでビルドできません。

試しにregionをつなげて見たところ、ビルドは通るものの、ローカルエミュレータでは後ろのasia-northeast1しか起動していないもよう。

# だめだったコード2
export const example = functions
  .region('us-central1')
  .region('asia-northeast1')
  .https
  .onRequest(app)

落ち着いてVS Codeで型定義を見てみると・・・

(method) FunctionBuilder.region(...regions: ("us-central1" | "us-east1" | "us-east4" | "europe-west1" | "europe-west2" | "europe-west3" | "asia-east2" | "asia-northeast1")[]): functions.FunctionBuilder

なんかよくわからない・・・。

リファレンスを見たらExampleがありました。こっちを最初にみるべきだった。
https://firebase.google.com/docs/reference/functions/function_builder_.functionbuilder#region

Example
functions.region('us-east1')

Example
functions.region('us-east1', 'us-central1')

# OKなコード
export const example = functions
  .region('us-central1', 'asia-northeast1')
  .https
  .onRequest(app)

あいまいな「カンマ区切りの複数のリージョン文字列」という説明に振り回されただけだった。

でも、ここまで来たら型定義も"us-central1" 、"us-east1"等の配列を「...」で展開したものっていうのがわかった。

結局ローカルエミュレーターは最初の一つのリージョンしか起動しなかったけど、firebase deployしたところ無事2つ生えました。

Step #3 - "Deploy to Firebase": i  functions: creating Node.js 10 function example(asia-northeast1)...
Step #3 - "Deploy to Firebase": i  functions: updating Node.js 10 function example(us-central1)...


プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

プログラミングTypeScript ―スケールするJavaScriptアプリケーション開発

  • 作者:Boris Cherny
  • 発売日: 2020/03/16
  • メディア: 単行本(ソフトカバー)