Next.js for DrupalをCentOSで検証してみた（１）


Next.js for Drupalは2021年に公開されたプロジェクトで、現在でもアップデートしています。Advent Calendar 2021に投稿する予定でしたがVercel以外のホストで動かすのに四苦八苦していました。年月の経過とともに解決したのでVPSのCentOS7でapacheで稼働させるまでまとめました。

https://next-drupal.org/

:::note warn
Drupalインストール時にUmamiプロファイルを日本語で選択するとNext.jsが実行エラーになる可能性が高いです。解決策としてLando環境かDDEV環境で英語でインストールしたデータを公開サーバにリストアすることをオススメします・・・。
今回はDrupalは9.5.0とnext-drupalが1.6.0、Next.jsが12.2.3、reactが17.0.2、で動作確認を行いました。
:::

手順は下記サイトを参考にしながら進めていきます。
https://next-drupal.org/learn/quick-start/install-drupal

今回は借りているVPSではCentOS7のApacheサーバでPHP7.4とMySQL５．６環境なので、下記のディレクトリ構成で検証していきます。
DrupalサイトとNext.jsのサイトは同じサーバ内で稼働させます。

<table>
  <caption>公開ディレクトリ構成</caption>
  <thead>
    <tr>
      <th>ディレクトリ</th> <th>用途</th>
    </tr>
  </thead>
  <tr>
    <td>/var/www/umami.hoge.com</td> <td>Drupal</td>
  </tr>
  <tr>
    <td>/var/www/next.hoge.com</td> <td>Next.js</td>
  </tr>
</table>

まずはDrupalでUmamiのプロファイルでインストールします。
```
cd /var/www/
composer create-project drupal/recommended-project umami.hoge.com
cd umami.hoge.com
```

筆者のVPSはPHP7.4とMySQL5.6構成なので、インストールができません。Drupalのバージョンを9.5に限定してインストールするようにcomposer.jsonを修正します。
```diff_php:composer.json
    "require": {
        "composer/installers": "^2.0",
-        "drupal/core-composer-scaffold": "^10.0",
+        "drupal/core-composer-scaffold": "9.5",
-        "drupal/core-project-message": "^10.0",
+        "drupal/core-project-message": "9.5",
-        "drupal/core-recommended": "^10.0"
+        "drupal/core-recommended": "9.5"
    },
```

またMySQL5.6の場合は下記の`drupal/mysql56`ドライバとNext.jsのモジュールとDrushをインストールします。MySQL5.7以降ならスルーでお願いします。
```
composer update
composer require drupal/mysql56
composer require drupal/next
composer require drush/drush
```

続いて再度`composer.json`を修正します。`extra`以下に`patches`を追記します。
```diff_php:composer.json
"extra": {
    "patches": {
        "drupal/subrequests": {
            "Get same results on different request": "https://www.drupal.org/files/issues/2019-07-18/change_request_type-63049395-09.patch"
        },
        "drupal/decoupled_router": {
            "Unable to resolve path on node in other language than default": "https://www.drupal.org/files/issues/2022-11-30/decouple_router-3111456-resolve-language-issue-58.patch"
        }
    },
}
```

修正後、`composer update`を実行します。
`admin_toolbar`と`backup_migrate`は作業簡略化のため入れています。
```
composer require cweagans/composer-patches
composer require drupal/next drupal/jsonapi_menu_items drupal/jsonapi_views 'drupal/jsonapi_resources:^1.0@beta'
composer require drupal/admin_toolbar
composer require drupal/backup_migrate
```

:::note warn
Drupalインストール時にUmamiプロファイルを日本語で選択するとNext.jsが実行エラーになる可能性が高いです。解決策としてLandoかDDEV環境で英語でインストールしたデータを公開サーバにリストアすることをオススメします・・・。
:::

## モジュールを有効
次に下記のモジュールを有効にします。Next.jsの関連モジュールも要求されるので継続して進めます。
`/en/admin/modules`
```
Next.js
Next.js JSON:API
Backup and Migrate
Admin Toolbar
```

## パスエイリアスの設定
次にパスエイリアス構成を設定します。
`/en/admin/config/search/path/patterns/add`
今回はArticleのみ設定します。Recipesも同じように追加すれば
![next-2023-03-19-9.52.44.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/e87a0591-8d78-6b70-19d7-2eda35af274e.jpeg)
```php:パスエイリアス構成
Pattern type: Content
Path pattern: Articles/[node:title]
Content type: Article
Label: Article
Machine name: article
```
でSaveします。

## Next.js sitesの設定
続いてNext.jsモジュールの設定です。左タブのNext.js　sitesからNext.jsを設置するnext.hoge.comドメインを指定します。
`/en/admin/config/services/next`
`Add Next.js site`ボタンから
```Next.js sitesの設定
Label: Next.js
Base URL: http://next.hoge.com
Preview URL: http://next.hoge.com/api/preview
Preview secret: secret
Revalidate URL: http://next.hoge.com/api/revalidate
Revalidate secret: secret
```
でSaveします。

## Next.js entity typesの設定
`/en/admin/config/services/next/entity-types`
`Configure entity type`ボタンから追加します。
```php:Next.js entity typesの設定
Entity type: Article
Plugin: Site selector
Next.js sites: Next.jsをチェック
On-demand revalidation Plugin: Path
On-demand revalidation Revalidate pageをチェック
```

## Rolesの作成
続いてロール（Roles）を作成します。
`/en/admin/people/roles`
`Add role`
```
Role name: Next.js
Machine name: next_js
```
でSaveします。

## Next.jsロールの権限付与
作成したNext.jsロールに以下の権限を与えます。
`/en/admin/people/permissions`

```php:権限付与
Bypass content access control
Issue subrequests
View user information
```

## ユーザー作成
続いてユーザーを作成します。
`/en/admin/people`
`Add user`ボタンから
```
Username: nextjs
Password: nextjs
Roles: Next.js
```
`Create new account`ボタンでユーザーを追加します。

## Simple OAuth Settingsの設定
公開鍵の生成をし、Drupalのドキュメントルート`/var/www/umami.hoge.com/web/`外にディレクトリ`keys`を作成し、フォルダに書き込み権限を与えます。
`/var/www/umami.hoge.com/keys/`にファイルを置く構成になります。
`Generate keys`ボタンを押すとポップアップが表示されます。
```
Directory for the keys: ../keys
```
`Generate`でキーが生成されます。

```
Public Key: ../keys/public.key
Private Key: ../keys/private.key
```
`Save configuration`で設定します。

作成された２つのファイルはパーミッションを644にしておきます。
```php:/var/www/umami.hoge.com/keys
chmod 644 private.key public.key
```

## Consumer entitiesの作成
`/en/admin/config/people/simple_oauth`
`Add Consumer`ボタンから作成します。

```
Labr: nextjs
Client ID: Generate random Client IDボタンでClient ID生成
User: nextjs
New Secret: secret
Scopes: Next.js
```
保存したら`Is Default?`のMake Defaultを押します。

他に認証の設定などありますが、未設定でも動きますので説明は割愛します。

ここまで設定が終わるとArticleのノードを開くと`Service Unavailable`と表示されます。表示するにはNext.jsをインストールしないと表示されません。
![next_not-2023-03-20-17.13.24.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/3110c317-a011-de71-8620-2dbf7c7160e3.jpeg)

# Next.jsのインストール
ここからNext.jsサイトドメインに移ります。Next.jsのインストールを行います。
```
cd /var/www
npx create-next-app -e https://github.com/chapter-three/next-drupal/tree/main/examples/example-umami
? What is your project named? > next.hoge.com
```
`What is your project named?`の箇所は公開するディレクトリ名を`next.hoge.com`と入力します。作成されたディレクトリに移動してリスト取得で以下のファイルなどがあれば問題ありません。
```
cd /var/www/next.hoge.com
ls -a
. 
.. 
.env.example
.eslintrc.json
.gitignore
.next
```

`.env.example`をコピーして`.env.local`として内容を書き換えます。
下記のように`NEXT_PUBLIC_DRUPAL_BASE_URL`と`NEXT_IMAGE_DOMAIN`はデータを取得するDrupalのサイトドメインを指定します。
```diff_php:.env.local
- NEXT_PUBLIC_DRUPAL_BASE_URL=http://localhost:8080
+ NEXT_PUBLIC_DRUPAL_BASE_URL=http://umami.hoge.com
- NEXT_IMAGE_DOMAIN=localhost
+ NEXT_IMAGE_DOMAIN=umami.hoge.com
- NEXTAUTH_SECRET=
+ NEXTAUTH_SECRET=secret
- NEXTAUTH_URL=http://localhost:3000
+ NEXTAUTH_URL=http://next.hoge.com
- DRUPAL_CLIENT_ID=
+ DRUPAL_CLIENT_ID=Consumer entitiesで作成したClient ID
- DRUPAL_CLIENT_SECRET=
+ DRUPAL_CLIENT_SECRET=secret
```

## package.jsonの設定
実行コマンドでのポート変更（デフォルトでは3000ですが変更する場合に設定）。
```diff_php:package.json
  "scripts": {
-    "dev": "next dev",
+    "dev": "next dev -p 3008",
    "debug": "NODE_OPTIONS='--inspect' next dev",
-    "preview": "next build && next start",
+    "preview": "next build && next start -p 3008",
    "lint": "next lint"
  },
```

# apacheの設定
apacheの設定を行います。制御している.confからポート80と433をそれそれ設定しますが、SSLに対応する時間がなければ80のみで検証しましょう。Next.jsを稼働させるドメインにはProxyの設定をします（任意に必要なコンフリクトしないよう違うポートを設定します）。終わったら設定を反映します。
Drupalサイトドメインは通常のVirtualHostの設定で行います。RewriteEngine Onは人によっては必要ありません。
```
# Next.jsサイトドメイン
<VirtualHost *:80>
DocumentRoot /var/www/next.hoge.com
ServerName next.hoge.com
    ServerAlias next.hoge.com
    ServerAdmin admin@hoge.com
    ErrorLog logs/next.hoge.com-error_log
    CustomLog logs/next.hoge.com-access_log combined
RewriteEngine On
ProxyRequests On
ProxyPass / http://localhost:3008/
ProxyPassReverse / http://localhost:3008/
<Directory "/var/www/next.hoge.com">
        AllowOverride All
        Options +Includes +ExecCGI
</Directory>
</VirtualHost>
```

## Next.jsを起動
最後にNext.jsを稼働するよう場所を確認して以下のコマンドで実行します。
```
pwd
/var/www/next.hoge.com
yarn run dev
```
`yarn run dev`で実行するとすぐに確認出来ます。問題があった場合はエラーが表示されます。
![next-dev-2023-03-20-17.30.29.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/a7ae68d2-29ae-ec7c-d6cf-c882ef2c6d87.jpeg)
`yarn run preview`を実行するとビルドするので時間が掛かります。問題があった場合はが表示されたり途中で止まります。
![next_preview-2023-03-20-17.26.28.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/25f6d0bd-f660-241d-099e-e13913a7a382.jpeg)

問題なく実行できたらDrupalのArticle記事を見てみましょう。先程の`Service Unavailable`から切り替わりプレビューが出来ています。`View`ボタンを押すと別タブで`umami.hoge.com`サイトでの表示が確認できます。
![next-umami-2023-03-20-17.15.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/c2b125fa-1c83-5014-f3b2-862952836e41.jpeg)

表示速度は`yarn run preview`でビルドして生成された静的ページと`yarn run dev`　で表示されるページでは表示速度が違うことが分かります。

## Lighthouseで計測

Lighthouseで計測して見ました。
`yarn run preview`での結果。すべて緑の高いパフォーマンスが確認できました。
![next.ssg-2023-03-18-23.05.50.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/3e0ce47e-b00c-6426-9e9d-e5e5e416d079.jpeg)
続いて`yarn run dev`の結果は、Performanceが赤く、パフォーマンスに問題があることが分かりました。
![next.ssr-2023-03-18-23.08.25.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59566/6a4980d7-16be-5842-ce77-807df8a6824a.jpeg)

今回はDrupalをヘッドレスCMSとして使ってみました。最近はヘッドレスCMSのみのサービスも増えてきております。今後、CMSの利用方法が予測できませんが、Drupalを主軸として利用している身としては、Drupalならではの活用方法を探求して行きます。