前エントリーのGo 1.16のembedとchiとSingle Page Applicationでは、Vue.jsで生成したファイルをバンドルしました。Vue.jsや、Parcel V2でビルドしたコンテンツを配信するにはこれで問題ありません。しかし、React(Next.js)は要注意です。
フロントエンドの環境整備をどうやって行うかはいつも悩みの種ですが、そんな中、僕が3年ほど前から他の人にお勧めしていたのがNext.jsでした。ほとんどの最低限必要なツール群は整備済みで、最近のバージョンであればTypeScriptを使うのも簡単。Linter(npm exec eslint –init)とFormatter(npm install prettierと環境整備)ぐらいでコードを書き始められます。
しかし、環境構築が簡単なNext.js製のウェブアプリケーションのビルド済みのフロントエンドのファイル群をGoアプリにバンドルしようとしたらうまく動かず、それの追試をしました。
試した環境
go:embedはフォルダ指定するときは現在地よりも親のフォルダは指定できません。ディレクトリトラバーサルの脆弱性を生み出さないための制約かと思われます。こんな感じのフォルダ構成にしてました。
├── cmd |
embed.goはこんな感じです。
package goweb |
何が起きたのか
作ったNext.jsのファイルを取り込んでウェブサーバーとして起動するコードを書いたのですが、トップページの静的なタグは表示されるものの、具体的にはファイルがいくつか取得できないようでうまく動きませんでした。こんな感じです。
2021/03/17 08:52:23 not found /_next/static/chunks/pages/_app-e86e439f5882a1d9aed3.js |
エラーになったファイル以外のindex.htmlとか他のファイルは読み込めていました。go embedの説明によると、ディレクトリを自動で探索する場合にアンダースコアとピリオドスタートのファイルは無視されるとのこと。ただし、明示的に指定すれば良いみたいです。
If a pattern names a directory, all files in the subtree rooted at that directory are embedded (recursively), except that files with names beginning with ‘.’ or ‘_’ are excluded. So the variable in the above example is almost equivalent to:
実験してみました。
├── _test |
それぞれ、go:embedディレクティブに書いたセレクターと選択されるファイルの相関は次の通りです。
ファイル | _test , test |
_test/* , test/* |
_test/* , _test/*/* , test/* |
---|---|---|---|
_test/a.txt |
✔︎ | ✔︎ | ✔︎ |
_test/_b.txt |
✔︎ | ✔︎ | |
_test/dir/c.txt |
✔︎ | ✔︎ | ✔︎ |
_test/dir/_d.txt |
✔︎ | ||
test/e.txt |
✔︎ | ✔︎ | ✔︎ |
text/_f.txt |
✔︎ | ✔︎ |
深いフォルダでもアスタリスクを駆使すればなんとかなりそうです。 ということで、改めてNext.jsのファイルのバンドルに挑戦。
新たな敵、空フォルダ
というわけでバシバシ追加していったのですが、次のようなエラーがビルド時に出るようになりました。
$ go build |
Next.jsがビルド時にこのフォルダを作るのですが、ファイルが一個もなく、それを処理できないようです。選択可能なファイルがない場合にエラーになるので、.keepみたいなファイルをおいてもダメです(選択がアスタリスクとアンダースコアは無視されるので)。一番簡単なのはこういうフォルダを削除しておくことです。空フォルダが絶対必要です、というシステムがあるとダメなので、その場合は別の方法が必要ですね。
完成
最終的にアセットをバンドルするディレクティブコメントはこのようになりました。これで無事、実行に必要なファイルを全てバンドルできました。きちんとGo製のサーバーも動きました。
少なくともNext.js 10.0.9ではこれで動きそうです。まあとてもシンプルな画面しか作っていないのでもっといろんな要素を入れていったり、Next.jsのバージョンが上がると動かなくなる可能性もありますが・・・
//go:embed frontend/out/* |
前回とちょっと違うところが1つあります。Next.jsの静的サイト生成の場合、pages/page2.tsx
ファイルはpage2.html
ファイルとなります。しかし、他のページから遷移すると/page2
というパスがアドレスバーに表示されます。ここでリロードしたりすると、最初に/page2
という拡張子なしのファイルを読み込もうとしますが、それではうまく動作しません。index.html
にフォールバックしてもダメでした。
この場合は、/page2
にリクエストがきたら、/page2.html
を返してあげれば良いので、失敗時のフォールバックをもう1つ増やして、拡張子つきで再リトライしてみるようにしてあげる必要があります。
|
これでNext.jsで作った静的サイトも、Go 1.16にバンドルできるようになります。