abeshi blog
カテゴリーで検索

ルーティングはハードコーディングするな!

2021年11月17日

保守性の高いシステムを構築するには、変化に強いプログラムを組んでいくことが大切です。
今回はNext.jsを使って解説していきます。

なぜルーディングはハードコーディングしてはいけないのか?


ダメな例です

<Link href="/users">
  <a>ユーザー一覧ページに遷移して!</a>
</Link>


上記はNext.jsのリンクコンポーネントを使い、ユーザー一覧ページへ遷移するコードですが、これは最悪です、、、、、

例えばURLが急な要望で/user_listに変更になったとします。

<Link href="/user_list">
  <a>ユーザー一覧ページに遷移して!</a>
</Link>


上記のように書き換えが発生します。
一見簡単に思えるかもしれないですが、これが大規模システムだった時を想像してみましょう。

極端ですが、/usersのリンクコンポーネントの記述が100個あったとします。
つまりこれを100個分修正しなければいけないのです、、、

一括で修正したとしても、万が一漏れがあったとすると最悪の場合ユーザーを404ページに案内してしまう事態が起きるのです。。。


ハードコーディングしない為の対処法


純粋な対処法としてはルーティングをしっかりと定数のような形でまとめてあげればいいのです。
そしてページ遷移する際は全て定数からルーディングを呼び出します。



const usersListPagePath = "/users"


<Link href="usersListPagePath">
  <a>ユーザー一覧ページに遷移して!</a>
</Link>


定数として定義することで
URLが変わった際は、usersListPagePathの値を変更するだけで100ページ分を一気に安全に修正することができます!!!
イメージがついてきたでしょうか
でも上記は完全に良いとは言い切れません。


では自分が考える最適な対処法を3つほど紹介していくのでみていきましょう!

オブジェクト形式で記述していく



下記が参考コードです!

// routing.ts

export const Routing =  {
  	  // - トップ ======================================
  	   Top: {
  	     path: "/",
  	     pageName: "トップ"
  	  },
  	
  
  	  // - ブログ =====================================
  	  Blog: {
  	    List: {
  	      path: "/blog",
  	      pageName: "ブログ記事一覧"
  	    },
  	    Details: {
  	      path: "/blog/[id]",
  	      pageName: "ブログ記事詳細"
  	    }
  	  }
  }



呼び出す際はRoutingをimportして

<Link href="Routing.Top.path">
  <a>トップページに遷移して!</a>
</Link>


きれいにまとまりましたね。

では動的な場合はどうすればいいのか??

<Link href="Routing.Blog.Details.replace("[id]", 5)>
  <a>ブログidが5のページに遷移して</a>
</Link>


これでいけます。
5の部分を動的にしたい場合は、blog.idのような形で書いてあげるといいと思います。

namespaceで記述していく



2つ目がnamespaceで記述していく方法です。

// routing.ts

export namespace Blog {

  export namespace List {
    export const URI_Path: string = "/blog";
    export const localizedPageName: string = "ブログ一覧";
  }

  export namespace Details {

    export enum PathParameters {
      blogID = "id"
    }
    export const URI_PathTemplate: string = `/blog/:${PathParameters.blogID}`;

    export function buildURI_Path({ targetBlogID }: { targetBlogID: string; }): string {
      return URI_PathTemplate.replace(`:${PathParameters.blogID}`, targetBlogID);
    }

    export const localizedPageName: string = "ブログ詳細";
  }
}

export default Routing;




こちらでも対応可能です。

<Link href="Routing.Blog.Details.buildURI_Path({ targetBlogID: blog.id})>
  <a>ブログidが5のページに遷移して</a>
</Link>



namespaceは非推奨のプロジェクトも多いですが、関数や変数等も記述しやすい為、こういった場合は使ってもいいと思います。

最強ライブラリー pathpida



一番おすすめはこちらです!

pathpidaは最近活用しているライブラリなのですが、Next.jsではpages内のコンポーネントを自動で読み取って、ルーティングを作成してくれます。

まずはライブラリーをinstallします

npm install pathpida npm-run-all --save-dev



packge.jsonのscript部分を変更します。

// packge.json

"scripts": {
	    "dev": "run-p dev:*",
	    "dev:next": "next dev",
	    "dev:path": "pathpida --watch",
	    "build": "pathpida && next build",
}



これで準備は完了です。

npm run dev


プロジェクトを立ち上げるとpagesディレクト裏を読み取って
utils または lib ディレクトリどちらかに $path.ts ファイルが自動生成されます。
両方存在しない場合はlibディレクトリを自動作成してくれます!

下記のようなファイルが自動生成されます。

/* eslint-disable */
	// prettier-ignore
	export const pagesPath = {
	  blog: {
	    _id: (id: string | number) => ({
	      $url: (url?: { hash?: string }) => ({ pathname: '/blog/[id]' as const, query: { id }, hash: url?.hash })
	    }),
	    page: {
	      _id: (id: string | number) => ({
	        $url: (url?: { hash?: string }) => ({ pathname: '/blog/page/[id]' as const, query: { id }, hash: url?.hash })
	      })
	    }
	  },
	  $url: (url?: { hash?: string }) => ({ pathname: '/' as const, hash: url?.hash })
	}
	
	// prettier-ignore
	export type PagesPath = typeof pagesPath




呼び出す際は

<Link href="pagesPath.blog._id(targetBlog.id).$url()")>
  <a>指定したのページに遷移して</a>
</Link>


で簡単に呼び出すことができます!

こちらのライブラリーを導入することでpagesディレクトリ下にファイルが増えるたびに自動でroutingを生成してくれるので、もはや定数化して変更があるたびに、定数を変更することすら
やらなくて済むのです、、、、

詳しい使い方はこちらからご覧ください!