くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Nuxt3でpages配下の特定ディレクトリをルートから除外する(`pages:extend` hook)

Next.js関連のこのツイートを見て、
Nuxtでもやりたいなと思ったときにいろいろ調べてみたときの備忘録(*´ω`*)

最近、ディレクトリをカスタマイズするのが便利なのでは?
と思っていろいろ試行錯誤中(*´ω`*)

ディレクトリ構成

やりたい構成はこんな感じ。

./
  - components/*.vue ... 複数ページで使うコンポーネント
  - composables/*.ts ... 複数ページで使うTypeScript
  - pages
    - _components/*.vue ... 特定ページのみで使うコンポーネント
    - _composables/*.ts ... 特定ページのみで使うTypeScript
    - index.vue ... 表示されるページ

そのままだとpages配下のすべてを対象に、
ルートを作成されてしまうので、いくつかを除外する必要がある。

pages:extend hookで除外

nuxt.config.tspages:extend hookを使うと、
指定したページをルーティングから除外できるっぽい。

アンダーバー(_)からはじまるディレクトリを除外する場合はこんな感じ。

// nuxt.config.ts
import type { NuxtPage } from "nuxt/schema";

export default defineNuxtConfig({
  hooks: {
    "pages:extend"(pages) {
      // routesからの除外処理
      function removePagesMatching(pattern: RegExp, pages: NuxtPage[] = []) {
        // 除外するrouteを取得
        const pagesToRemove = [];
        for (const page of pages) {
          if (page.file == null) continue;
          if (pattern.test(page.file)) pagesToRemove.push(page);
          else removePagesMatching(pattern, page.children);
        }
        // 取得した対象routeを除外
        for (const page of pagesToRemove) {
          pages.splice(pages.indexOf(page), 1);
        }
      }
      // 除外処理の実行
      // アンダーバー(_)からはじまるディレクトリを除外
      removePagesMatching(/\/_.*\//, pages);
    },
  },
  // ...
});

_comoponetsをauto registrationの対象にする

デフォルトのcomponents/以外にもコンポーネントを配置したので、
pages/**/_components/*.vueも対象になるように設定を追加。
(pathPrefixは好きじゃないので無効化してる)

// nuxt.config.ts
import type { NuxtPage } from "nuxt/schema";

export default defineNuxtConfig({
  // ...
  components: {
    dirs: [
      {
        path: "components",
        extensions: [".vue"],
        pathPrefix: false,
        global: true,
      },
      {
        path: "pages",
        pattern: "_components",
        extensions: [".vue"],
        pathPrefix: false,
      },
    ],
  },
  // ...
});

_composablesをauto importの対象にする

_comoponetsと同様に、
pages/**/_composables/*.tsも対象になるように設定を追加

// nuxt.config.ts
import type { NuxtPage } from "nuxt/schema";

export default defineNuxtConfig({
  // ...
  imports: {
    dirs: [
      "~/composables", // default
      "~/utils", // default
      "~/pages/**/_composables/*.ts", // add
    ],
  },
  // ...
});

おまけ

TailwindCSSにも追加設定が必要

ディレクトリの追加・変更箇所によっては、 tailwind.config.cjsに設定を追加する必要がある。

デフォルトからの変更点はこんな感じ。
(pages/**/_composables/*.{js,ts}も対象にする)

  // tailwind.config.cjs
  /** @type {import('tailwindcss').Config} */
  export default {
    // ...
    content: [
      `${srcDir}/components/**/*.{vue,js,ts}`,
      `${srcDir}/layouts/**/*.vue`,
-     `${srcDir}/pages/**/*.vue`,
+     `${srcDir}/pages/**/*.{vue,js,ts}`,
      `${srcDir}/composables/**/*.{js,ts}`,
      `${srcDir}/plugins/**/*.{js,ts}`,
      `${srcDir}/utils/**/*.{js,ts}`,
      `${srcDir}/App.{js,ts,vue}`,
      `${srcDir}/app.{js,ts,vue}`,
      `${srcDir}/Error.{js,ts,vue}`,
      `${srcDir}/error.{js,ts,vue}`,
      `${srcDir}/app.config.{js,ts}`
    ],
    // ...
  };

routeの除外はmoduleでもOK

Custom routingのドキュメントには、
自分でもmoduleを使ってもできるっぽい。

.nuxtignoreだとビルド対象からも除外

試してみたけど、だめだったパターン。
直接importすればいいけど、auto-registrationやauto-importも対象外になってしまった。。

ディレクトリ構成をカスタマイズする

pagespublicなども結構自由に変更できる。

// nuxt.config.ts
import type { NuxtPage } from "nuxt/schema";

export default defineNuxtConfig({
  // ...
  dir: {
    layouts: "layouts",
    pages: "pages",
    assets: "assets",
    public: "public",
    static: "public",
    middleware: "middleware",
    modules: "modules",
    plugins: "plugins",
  },
  // ...
});

以上!! これでだいぶ全体の見通しがよくなった気がする(*´ω`*)