【Next.js】index.htmlファイルを表示する実装を考える

[**WEBCAMP ENGINEER COMMUNITY Advent Calendar 2022**](https://qiita.com/advent-calendar/2022/webccamp-engineer-community)
13日目を担当する、Akiraと申します。

[DMM WEBCAMP](https://web-camp.io/)の卒業生で、今年の4月からスタートアップでエンジニアをしております。フロントからインフラまで色々と携わりながら、日々新しい技術や知識に触れています。エンジニアとして働き始めては半年ほどが経ち、今回初めてアドベントカレンダーに参加します:v:

今回は、一つの機能を実装するにしても様々な方法があり、あらゆることを考慮した上で最適な実装をすることの重要性を感じたので、そのことを記事にします。

それでは、**Next.jsで作成されたWebサイトにLPを埋め込んで表示する**ことを例に、
いくつか考えられる実装方法を見ていきましょう！

# sampleファイルの構成
LPを表示するsampleファイルは、public配下に下記のように格納します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/a6b7ded9-148d-dd62-4fa1-8e5f725436f7.png)

それぞれのファイルは下記のようにします。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <link rel="stylesheet" href="sample-css/index.css">
  <title>Advent Calendar</title>
</head>
<body>
  <p class="p1">Test</p>
  <img src="sample-img/sample.png" width="100px" height="100px">
</body>
</html>
```

```css:index.css
.p1 {
  color: red;
}
```

ちなみにページはこのように表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/0fdc4387-f7dd-6f45-7717-67c11ef403a6.png)

至ってシンプルですね。
それでは、実装方法を見ていきます。


# 【実装1】 特に何もしない
~~何もしないことは実装に当てはまるのか？~~
public配下にファイルを格納し、
特に何もしなくても **/sample/index.html**にアクセスすればLPは表示されます。
しかし、URL末尾にindex.htmlを追記するのはなんだかイケてないな...
と思ったりもするわけです。:confused:

# 【実装2】 pagesで新たにページを用意する
Next.jsで新たにページを作成するとなった際に、まず思い浮かぶのは、
pages配下に新しいファイルを用意することではないでしょうか。

新しく作成したページにゴリゴリコーディングしてLP完成！
みたいなパターンもありますが、
今回はすでに作成されているLPを表示する実装が目的なので、考慮しません。

では、「index.htmlファイルを埋め込む」ことを実現するにはどうしたら良いでしょうか。
私が埋め込みで思い浮かんだのは、**iframe**を用いた実装でした。
それでは、iframeを用いた実装を見てみましょう。

以下のように、pagesフォルダにsample.tsxファイルを作成します。

```tsx:sample.tsx
import styles from '../styles/Sample.module.css'

export default function Home() {
  return (
    <div>
      <iframe className={styles.main} src="sample/index.html"/>
    </div>
  )
}

```
ついでに、Sample.module.cssはこちら。iframeのborderを無効化しています。
```css:Sample.module.css
.main {
  border: none;
}
```
この実装の場合のURLは、**/sample**となります。
これで、URL末尾にindex.htmlを追記しなくともLPのページにアクセスができました。

もちろん、pages配下にsampleフォルダを置いたままなので、
**/sample/index.html**にアクセスした場合でもLPは表示されます。

しかし、iframeを使った実装ではSEOの効果が薄れるようです。:disappointed_relieved:
LPとしての役割を果たせないのでは？という懸念があります。
それでは、他の実装方法も検討してみる必要がありますね。


# 【実装3】 Rewritesでルーティングする
Next.jsには**Rewites**という機能があり、ルーティングを設定することができます。
それでは、**/sample**にアクセスした時にLPが表示されるように設定してみましょう。

next.config.jsを以下のように編集します。

```js:next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  async rewrites() {
    return [
      {
        source: '/sample',
        destination: '/sample/index.html'
      }
    ]
  }
}

module.exports = nextConfig

```
このように、
**source**に指定した **/sample**にアクセスした時に、
**destination**で指定した **/sample/index.html**にルーティングされます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/d91482a0-2bbd-e6a1-780e-05360b9ed843.png)

...が、これではCSSや画像表示が出来ていないではないか。
ネットワークを確認してみると、それぞれの要素の読み取りに失敗しているようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2729568/c04f7afa-a85d-85aa-0764-389af6f22c9f.png)

HTML要素は表示されているので、この原因はパス指定にあるのでは？と考えました。
それでは、既存のLPのパス指定を変更してみましょう。

```diff_html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <link rel="stylesheet" href="sample/sample-css/index.css">
-  <link rel="stylesheet" href="sample-css/index.css">
  <title>Advent Calendar</title>
</head>
<body>
  <p class="p1">Test</p>
+ <img src="sample/sample-img/sample.png" width="100px" height="100px">
- <img src="sample-img/sample.png" width="100px" height="100px">
</body>
</html>
```

パス指定に**sample**を追加するとCSSや画像の読み込みは失敗しなくなりました。
これで、無事にルーティングできるようになりました。

ちなみに、Rewritesを用いることで、
ワイルドカードや正規表現を使った複雑なルーティングの設定も可能なので、
気になった方は、[公式ドキュメント](https://nextjs.org/docs/api-reference/next.config.js/rewrites)を参照してください。

***
ということで、
既存のファイルを変更するという一手間がありましたが、
Rewritesを用いてルーティングする実装方法がベストなのでは、という結論に至りました。
一見、ページの表示結果には大きな差が見られないものの、それぞれの実装方法に特徴があることがわかります。
他にも別の実装方法があれば、コメント等いただければと思います。

それでは、最後までお読みいただきありがとうございました！