はじめに
Nuxt + Typescriptでアプリケーションを開発している際、device毎(PC, スマホ)で表示するlayoutをそれぞれ分けて作成・表示したかったため、そのために行った内容をまとめます。
環境
- Nuxt.js 2.8.1
- Node.js 8.11.4
- npm 6.4.0
ディレクトリ構成
├── .nuxt
├── node_modules
├── src
│ ├── layouts
│ │ ├── pc
│ │ │ └── default.vue
│ │ └── sp
│ │ └── default.vue
│ ├── pages
│ │ ├── pc
│ │ │ └── index.vue
│ │ └── sp
│ │ └── index.vue
│ ├── server
│ │ └── index.ts
│ └── router.ts
├── nuxt.config.ts
├── package-lock.json
└── package.json
※関連するディレクトリ・ファイルのみ表示
routerをカスタマイズ
Nuxtのrouterをカスタマイズするにあたってnuxt-community/router-module
というモジュールを利用します。
https://github.com/nuxt-community/router-module
このモジュールは独自のrouterを実装することで、Nuxtアプリケーションのroutingをカスタマイズすることを可能とします。
Use your own router.js to handle your routes into your Nuxt.js application.
router-moduleのインストール
以下のコマンドにてモジュールをインストール。
$ npm install --save @nuxtjs/router
router.tsを作成
インストールが完了したらsrcDirに独自のrouterを作成します。
今回はTypescriptでアプリケーションの開発を行っているため、router.ts
を作成しました。
/* eslint @typescript-eslint/no-explicit-any: 0 */
import Vue from 'vue';
import Router, { RouteConfig } from 'vue-router';
import { createRouter as createDefaultRouter } from '~~/.nuxt/defaultRouter.js';
Vue.use(Router);
const fixRoutes = (
defaultRoutes: RouteConfig[],
isMobile: boolean,
): RouteConfig[] => {
const regex = isMobile ? /^\/sp\/?/ : /^\/pc\/?/;
return defaultRoutes
.filter((route: RouteConfig): boolean => regex.test(route.path))
.map(
(route: RouteConfig): RouteConfig => ({
...route,
path: route.path.replace(regex, '/'),
}),
);
};
export const createRouter = (ssrContext: Record<string, any>): Router => {
const defaultRouter: Record<string, any> = createDefaultRouter();
// TODO:mobile判定は後で実装するため、一旦固定でmobile判定
const isMobile = true;
return new Router({
...defaultRouter.options,
routes: fixRoutes(defaultRouter.options.routes, isMobile),
});
};
router.ts
ではNuxtで生成されたdefaultRouter.js
を再利用することでカスタマイズしております。(defaultRouter.js
の生成方法については後述)
実装したfixRoutes
関数では、引数として渡されたmobile判定情報を元にsp
もしくはpc
ディレクトリのどちらかをroutingのpathとして採用し、defaultのroute情報をベースとして新たなrouteを生成します。
それにより、device毎それぞれ別々のroutingが生成され、PCでアクセスした際は/pages/pc/
を、スマホでアクセスした際は/pages/sp/
を表示することが可能となります。
また、device判定の実装については後述とし、ここでは一旦固定で定義しています。
modulesの設定を追加
router.ts
を作成したらnuxt.config.ts
のmodulesに@nuxtjs/router
の設定を追加します。
// ・・・省略
const nuxtConfig: NuxtConfiguration = {
mode: 'universal',
srcDir: 'src/',
// ・・・省略
modules: [
['@nuxtjs/router', { fileName: 'router.ts', keepDefaultRouter: true }],
],
// ・・・省略
optionsとしてはpath
とfileName
、keepDefaultRouter
の指定が可能です。
fileName
に関してはdefault値がrouter.js
なため、今回はtsファイル(router.ts
)を指定。
keepDefaultRouter
はtrueを設定すると.nuxt
ディレクトリにdefaultRouter.js
としてNuxtのデフォルトrouterが保持され、独自に作成したrouterからアクセスし再利用することが可能となります。
deviceの判定
routerのカスタマイズまで完了したら、次にdeviceの判定処理を実装します。
deviceの判定にはhgoebl/mobile-detect.js
というライブラリを利用しました。
https://github.com/hgoebl/mobile-detect.js
このライブラリはUserAgentをもとに、deviceの判定を行います。
mobile-detect.jsのインストール
$ npm install --save mobile-detect
deviceの判定処理実装
インストールが完了したら最後にTODOとしていたdeviceの判定処理を実装します。
// ・・・省略
import MobileDetect from 'mobile-detect';
Vue.use(Router);
const isMobile = (ssrContext: Record<string, any>): boolean => {
const ua = ssrContext
? ssrContext.req.headers['user-agent']
: window.navigator.userAgent;
const md: MobileDetect = new MobileDetect(ua);
return !!md.mobile();
};
// ・・・省略
export const createRouter = (ssrContext: Record<string, any>): Router => {
const defaultRouter: Record<string, any> = createDefaultRouter();
return new Router({
...defaultRouter.options,
routes: fixRoutes(defaultRouter.options.routes, isMobile(ssrContext)),
});
};
isMobile
関数を実装し、固定でtrueを定義していたisMobile
変数と置き換えます。
isMobile
関数の中ではmobile-detect
ライブラリを用いたmobile判定が行われており、MobileDetect
インスタンス生成の際にUserAgentを渡すことで判定が可能になります。(mobile判定の他にもtabletやos、iPhoneであるかどうかなど様々な判定が可能)
以上によりUserAgentの情報を元にdevice毎それぞれlayoutを分けることが可能となりました。