Next.js+TypeScriptで作ったWebUIをGoのバイナリに組み込んで動かしてみる2
Mar 13, 2022 05:00 · 2278 words · 5 minute read
先日のブログで「Next.jsで作ったWebのUIを静的化し、Goのバイナリに埋め込んでみた」という内容を書きました。
Next.js+TypeScriptで作ったWebUIをGoのバイナリに組み込んで動かしてみる · kapieciiのブログ
実際に試したところ、いくつか問題があることがわかりました。
その後Nuxt.jsを試すなど紆余曲折しながらも調査をしていたところ、課題のいくつかが解決しました。今回は解決策について書こうと思います。
目次
判明していた問題
前回の記事に記載していた問題は下記でした。
- 静的ファイルにビルドするとLinkタグのリンクが切れる
- ビルド実行時に「Error: Missing “key” prop for element in array react/jsx-key」エラーが発生する
- 静的ファイルにビルドすると、一部のアニメーションが動かない
解決方法
それぞれの問題点の原因と解決方法です。
「静的ファイルにビルドするとLinkタグのリンクが切れる」「静的ファイルにビルドすると、一部のアニメーションが動かない」
この2つは、静的にビルドされた後のjsファイルとCSSファイルが読み込めていないことで発生していました。
前回、静的出力したファイルを確認したのは下記の方法です。
- 出力されたファイルを直接ブラウザにドラッグアンドドロップ
- Goの「net/http」で実行しているWebサーバに載せてブラウザからアクセス
まず、ブラウザにドラッグアンドドロップする方法では、
Loading failed for the <script> with source “file:///_next/static/chunks/webpack-69bfa6990bb9e155.js”.
というエラーが発生していました。
続いてGoの「net/http」の場合は、
The resource from “http://localhost:8888/_next/static/chunks/main-f635b472c367d1c7.js” was blocked due to MIME type (“text/plain”) mismatch (X-Content-Type-Options: nosniff).
というエラーで読み込みに失敗していました。
X-Content-Type-Options - HTTP | MDN (mozilla.org)
Goのnet/httpではなくnpmのhttp-serverを使った場合には、適切なContent-Typeが自動で設定されます。結果、jsファイルとcssファイルが正常に読み込まれ、Linkも動作します。
$ npm run build
$ cd out/
$ npx http-server
前回の記事を書いた時点では、出力されるファイルの形式に問題があると考えていたのですが、違いました。
Next.js+TypeScriptで作ったWebUIをGoのバイナリに組み込んで動かしてみる · kapieciiのブログ
ちなみに、前回問題だと考えていた「出力するファイルの形式」は、Next.jsのnext.config.jsで「exportTrailingSlash」を有効にすることで変更できます。
「exportTrailingSlash」の詳細はこちら。
next.config.js: exportPathMap | Next.js (nextjs-ja-translation-docs.vercel.app)
「exportTrailingSlash」を有効にする前の状態がこちら。
「pages/page2.tsx」のようなファイルがある場合、ビルド後には「out/page2.html」というファイルが出力されます。
$ tree -L 2 out/
out/
├── 404.html
├── favicon.ico
├── index.html
├── _next
│ ├── LKyRh4rlfV-VYvOehcGch
│ └── static
├── page2.html
└── vercel.svg
「exportTrailingSlash」を有効にした状態がこちら。
先程と同様に「pages/page2.tsx」のようなファイルがある場合、「out/page2/index.html」というファイルが出力されます。
$ tree -L 2 out/
out/
├── 404
│ └── index.html
├── favicon.ico
├── index.html
├── _next
│ ├── static
│ └── XgY0nMz9OtOCcQjCYkx1v
├── page2
│ └── index.html
└── vercel.svg
どちらの形式で出力した場合も、jsとcssが読み込まれていれば問題なく動作します。
ビルド実行時に「Error: Missing “key” prop for element in array react/jsx-key」エラーが発生する
こちらのエラーは、macOSで動かしていたことに起因していると考えています。
全く同じ方法をWSL2とVMのUbuntuで実行したところ、このエラーは発生しませんでした。
開発をするなら、WSL2なりDockerなりを使って、Ubuntuの上で開発をしたほうがトラブルが少なそうですね。
次の問題
- Goの「net/http」でjsとcssを返す場合に「content-type」をいい感じに設定する
現状、Goの部分は下記のようにしています。「embed」を使って静的ファイルをまるっと読み込む形です。
package main
import (
"embed"
"fmt"
"net/http"
"os"
"io/fs"
)
//go:embed html/*
var html embed.FS
func main() {
fmt.Println("Open http://localhost:8888/")
fmt.Println("Press ctrl+c to stop")
public, err := fs.Sub(html, "html/public")
if err != nil {
panic(err)
}
http.Handle("/", http.FileServer(http.FS(public)))
if err := http.ListenAndServe(":8888", nil); err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
$ tree -L 3
.
├── html
│ └── public
│ ├── 404
│ ├── favicon.ico
│ ├── index.html
│ ├── _next
│ ├── page2
│ └── vercel.svg
└── sample.go
Next.jsのUIをビルドした後は、下記のようなファイル構成になるので、いい感じに「content-type」を設定して返す形にしたいですね。
$ tree -L 3 out/_next/
out/_next/
├── static
│ ├── chunks
│ │ ├── framework-e70c6273bfe3f237.js
│ │ ├── main-01df828e572375b9.js
│ │ ├── pages
│ │ ├── polyfills-5cd94c89d3acac5f.js
│ │ └── webpack-69bfa6990bb9e155.js
│ ├── css
│ │ ├── 149b18973e5508c7.css
│ │ └── 27d177a30947857b.css
│ └── XxyPy8Pu1_cOkBUmMMmDD
│ ├── _buildManifest.js
│ ├── _middlewareManifest.js
│ └── _ssgManifest.js
└── XxyPy8Pu1_cOkBUmMMmDD
最後に
以前の記事に書いていた問題が解決したので、解決編としてブログに残しておきます。
次の問題もみつかったので、引き続き合間を見つけて調査検証していきます。