ymmooot

Nuxt のルーティングを PC とスマートフォンで切り替える

概要

Nuxt.js は基本 pages ディレクトリをリネームできない
なのでユーザーエージェントやサブドメインで View のパスを切り替えるといった Web Application Framework でたまに欲しくなる機能が Nuxt の基本機能だけでは実現できない。
それをモジュールを用いて実現したのでメモ :pencil:

pages
├── PC
└── MOBILE

こんな感じで PC とスマートフォンを別のディレクトリに置いた上で、URL はそのままにする。

モジュール

モジュール とは Nuxt のコア機能を拡張する仕組みで、ビルド後の Nuxt が必要とする機能を差し込むことができる。

Nuxt Router Module

Nuxt Router Module は Nuxt によって生成される router.js をまるっと差し替えることができるモジュールであり、これにより自分でカスタムした router を使えるようになる。
また、keepDefaultRouter オプションを用いるとデフォルトの pages ディレクトリのツリー構造によるルーティングを defaultRouter.js として残しておくことができる。

keepDefaultRouter オプションが追加されたのはこちらのPR → #16 Feature: add option keepDefaultRouter
感謝です 🙏

モジュールの追加

$ yarn add @nuxtjs/router

or

$ npm install @nuxtjs/router

でインスコ 🍻

Nuxt の設定

nuxt.config.js{
  modules: [
    ['@nuxtjs/router', { keepDefaultRouter: true }]
  ],
},

Nuxt Router Module の README 通り。

pages ディレクトリを分割する

$ tree pages -L 1
pages
├── PC
└── MOBILE

こんな感じでディレクトリを分ける。Nuxt のデフォルトルーティングと区別するために大文字にしているが、開発者にわかりやすくしているだけなので、別に小文字でも構わない。

カスタム Router の作成

router.jsexport const fixPath = (path, isMobile) => {
  const regex = isMobile ? /^\/MOBILE\/?/ : /^\/PC\/?/;
  return path.replace(regex, '/');
};

export const fixName = (name, isMobile) => {
  const regex = isMobile ? /^MOBILE-?/ : /^PC-?/;
  return name.replace(regex, '') || 'index';
};

export const fixRoutes = (defaultRoutes, isMobile) => {
  const regex = isMobile ? /^\/MOBILE\/?/ : /^\/PC\/?/;

  return defaultRoutes.filter(route => regex.test(route.path)).map(route => ({
    ...route,
    path: fixPath(route.path, isMobile),
    name: fixName(route.name, isMobile),
  }));
};

export const createRouter = (ssrContext, createDefaultRouter) => {
  const defaultRouter = createDefaultRouter(ssrContext);
  const isMobile = detectMobile(ssrContext);
  return new Router({
    ...defaultRouter.options,
    routes: fixRoutes(defaultRouter.options.routes, isMobile),
  });
};

このようにして fixRoutes 内部で defaultRouter.options.routes の中身を一つずつ書き換えている。
このとき、 SPA によるクライアントの遷移時は ssrContextundefined になることに気をつける。

こうしておくと

<nuxt-link :to="{ name: 'users-id', params: { id: userId } }">hoge</nuxt-link>

こう書いたときに、 pages/PC/users/_id.vue / pages/MOBILE/users/_id.vue へのルーティングとなり、URL も /users/:id となる。

まとめ

カスタムすればするほど、 設定より規約 という Nuxt の基本思想から離れていくので、カスタムする際に独自の実装をするのではなく、上記のサンプルコードで PC・MOBILE とハードコーディングしてるところも pages 直下階層の大文字ディレクトリ名を抜き出すようにするなどして、新しい規約を追加するような実装にするといいのかもしれない。