pw generate
pw generate [--code-only] [--debug] [--backend nethttp|fasthttp]pw generate は pw build から最後の手順を引いたもの
です。バイナリは作りません。コンパイラが読める状態のツリーを残して止まります。
- テンプレート、SQL、ページツリー、カタログ、バインディングの呼び出し箇所を
ソースの隣の
_pw_gen.goにコンパイルする - Tailwind が有効なら、スタイルシートを最小化してビルドする
- アセットツリーを
dist/publicに構築 する。圧縮サイドカーとマニフェストも含む project.mainが開発専用パッケージに依存していれば拒否する
pw build がリンクの前に行うのと同じ内容、同じ順序です。pw build が「この
コマンド+コンパイラ」として定義されているためで、両者がずれることはありません。
4 番目がコンパイラの隣ではなくここにあるのには理由があります。このコマンドは
自分が実行しないコンパイラにツリーを渡します。contrib/devidp — パスワードを
確認せずにユーザーをサインインさせる開発用の IdP — を配布バイナリから締め出す
検査は、渡したあとではなく渡す前に済んでいなければなりません。
| オプション | 効果 |
|---|---|
--code-only |
手順 1 で止まる。スタイルシートもアセットツリーも書かない |
--debug |
ビルド済みツリーにソースマップを残す |
--backend |
依存チェックが依存グラフを列挙するときの build tag を選ぶ |
--target は provider 向けのパッケージングを選ぶもので、
pw build の役割です。ここでは受け付けません。
--debug は pw build --debug と
同じようにソースマップを残します。ただしそのフラグのもう半分はこのコマンドの
持ち物ではありません。-ldflags は自分で書くコンパイラ行に属するので、ここで
デバッグ用の成果物を作るなら pw generate --debug と、strip を指示しない
go build の組み合わせになります。
--code-only
Section titled “--code-only”--code-only が書くのは _pw_gen.go だけです。内側のループとエディタのタスク
のためのフラグです。診断が指し示す先は生成された Go であり、テンプレートの
エラーを見るために最小化済みスタイルシートを待つ時間は誰も払いたくありません。
その出力をコンパイラに渡さないでください。public.go は dist/public を
go:embed で名指ししているので、このフラグ付きで生成したツリーは、一度も
作られなかったディレクトリでコンパイルに失敗します。Tailwind を使っていれば
スタイルシートも欠けますが、こちらはもっと静かに、もっと遅れて表面化します。
ページがスタイル無しで描画されるだけです。
手順 4 は変わらず走ります。このフラグが飛ばすのはファイルを書き出す手順だけ
で、開発用 IdP をバイナリから締め出す検査の抜け道にはなりません。--debug は
併用を拒否します。ソースマップの置き場所であるツリーを、このフラグは作らない
からです。
コンパイルを他のものが担当するとき
Section titled “コンパイルを他のものが担当するとき”コンパイルを他のものが担当するのでなければ pw build を使ってください。担当が
移るのは次の 3 つの場合です。
TinyGo のビルド。 pw build は必ずホストの go でリンクするので、TinyGo の
プロジェクトは生成してから自分のコンパイラを呼びます。
pw generatetinygo build -scheduler=threads -o myapp ./cmd/myapp制御したい go build。 変わったターゲットへのクロスコンパイル、-ldflags の
指定、一つのツリーから複数のバイナリ。どれもコンパイラの行を自分で書く理由です。
pw generateGOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o dist/myapp ./cmd/myappgo build を握るイメージビルダー。 ko や Cloud Native Buildpacks は自分で
コンパイルし、生成は代行してくれません。作業ツリーでこれを先に実行してから、
ビルダーを呼びます。
コンテナイメージではこのコマンドを
Dockerfile.tinygo の中で使っています。そもそも Popcorn Web のビルドに
ホストフェーズがある理由も、そちらにあります。
読み込む対象
Section titled “読み込む対象”生成の範囲は用途ごとです。各用途は読んでよいディレクトリを列挙し、それ以外は 読みません。
[generate]handlers = ["handlers"]templates = ["handlers", "templates"]queries = ["queries"]config = ["cmd/myapp"]pages = ["pages"]dynamo = []firestore = ["entities"]| 用途 | 読むもの | 生成するもの |
|---|---|---|
handlers |
Go 中のルート登録、pw.Parse、レスポンス呼び出し |
リクエストバインディング、JSON コーデック、OpenAPI フラグメント |
templates |
.pw.html |
型付きレンダラ。ドキュメントシェルとエラーページを探す場所でもある |
queries |
.pw.sql |
context ベースのクエリ関数 |
config |
Go 中の pw.RegisterConfig, pw.RegisterSubCommand |
設定とサブコマンドのバインディング |
pages |
ページツリーのルート | 探索型ルーティングのルート登録とページパラメータ |
dynamo |
dynamo タグ付き Go 型と .pw.dynamo |
レコードのコーデック、キー、型付き DynamoDB クエリ |
firestore |
firestore タグ付き Go 型と .pw.firestore |
エンティティのコーデック、キー、Datastore mode の型付きクエリ |
1 つのディレクトリが複数の用途に現れて構いません。ページテンプレートはそれを描画する
ハンドラの隣に置くため、handlers は通常 handlers と templates の両方に現れます。
列挙したディレクトリは再帰的に走査されるので、入れ子のパッケージを個別に書く必要は
ありません。
以前からある handlers、templates、queries、config の 4 キーは必須で、既定値は
ありません。pages、dynamo、firestore は古いプロジェクトとの互換性のため省略できます。
それでも、その用途では何も生成しないという判断は空リストで明示するのが分かりやすい書き方です。
queries = [] # このプロジェクトに .pw.sql はないこの区別には意味があります。キーの書き忘れはエラーになり、[] は次に読む人に見える
判断として残ります。
自分の用途の外にあるソースはビルドを失敗させず、報告してスキップします。意図して置いた サンプルやフィクスチャがコードの隣にあっても構わないためです。
pw: samples/home.pw.html is outside generate.templates and is not generated from; list its directory to include itGo のソースは報告しません。普通の Go コードはプロジェクト全体にあり、用途の外にある
呼び出し箇所は単にバインディングが生成されないだけだからです。以前のレイアウトが
どの用途にも属さない場所に残した _pw_gen.go は報告します。もう再生成も削除も
されないファイルだからです。
宣言ファイルに加えて、Go のソースから呼び出し箇所も読み取ります。
| 呼び出し | 生成されるもの |
|---|---|
pw.Parse[T] |
T のリクエストバインディング |
pw.WriteAPI[T] |
T の JSON エンコーディング |
pw.WriteStream[T] |
T のストリームエンコーディング |
pw.RegisterConfig[T] |
T の設定バインディング |
pw.RegisterSubCommand[T] |
T のサブコマンドのパース |
pw.BadRequest などのエラーコンストラクタ |
ドキュメント化されるエラーレスポンス |
同じ根拠から、パッケージごとに 1 つの OpenAPI 3.1 フラグメントも生成されます。 ビルド時に決定的にマージされるため、API 記述は別のアノテーション群ではなくコードに 追従します。
書き出すもの
Section titled “書き出すもの”生成された Go はソースではなくビルド生成物です。
- ファイル名は
{ソース名}_pw_gen.goで、常にソースの隣に置かれる - スキャフォールドされた
.gitignoreによりバージョン管理から除外される .vscode/settings.jsonによりエディタから隠される- アプリケーションのビルドのたびに作り直される
いつでも再生成できます。編集もコミットもしないでください。
ルートテーブル
Section titled “ルートテーブル”pw generate は dist/routes.json も書きます。アプリケーションが提供する全パターンが
1 つのファイルに入ります。Go で登録されたルート——それぞれが登録されたファイルと行付き
——と、ページツリーが生むルート。ページツリーとハンドラ登録が別々の場所に持っている
URL 空間の、両方の半分です。
実行時には誰も読みません。ツールが解析をやり直さずに済むために存在します。
pw doctor が衝突するパターンを検査し、エディタ拡張が一覧に
します。dist/manifest.json と同じくビルド生成物で、スキャフォールドされた .gitignore
に含まれ、実行のたびに作り直されます。これより前に作られたプロジェクトには、無視行を
足す必要があります。
パターンがコンパイル時定数でない登録は読み取れないので、握り潰さずに未解決として記録 します。表を読むツールは、裏付けの取れないきれいなルート一覧を出すかわりに、その旨を 述べます。
エラーをテンプレートに向け直す
Section titled “エラーをテンプレートに向け直す”生成ファイルは誰も書いていない出力なので、その中のエラーは、開いてもいなければ
ブックマークもできないファイルを名指しします。popcornweb.toml の
generate.line_directives がそれを直します。ジェネレータが Go の //line
ディレクティブを書き、Go の位置情報を読むツールが一斉に追随します — コンパイラ、
go vet、デバッガ、gopls、そしてエディタ。
[generate]line_directives = trueテンプレートの式の型エラーはこう出るようになります。
./queries/users.pw.sql:8: invalid operation: mismatched types untyped int and untyped stringusers_pw_gen.go ではなく .pw.sql の行です。生成された .pw.sql 関数の中で
panic した場合も、スタックフレームが .pw.sql を名指しします。
既定は無効で、無効のままにする理由が 2 つあります。
go test -cover と引き換えです。 有効にすると、カバレッジプロファイルは生成
ファイルのパスを保ったまま写像後の行番号を書くので、名指ししたファイルに存在しない行を
報告します。しかも go tool cover -html は文句を言わずに誤った行を塗り、exit 0 で
終わります。テンプレートの位置か、カバレッジか。両取りはできません。
.pw.html では半分だけです。 コンパイル時のエラーはどの方言でも写ります。実行時の
スタックフレームが写るのは .pw.sql だけです。.pw.html はレンダープランにコンパイル
され、それを共有ランタイムが歩くので、失敗したフレームは生成コードの中ではなくその
ランタイムの中にあり、生成ファイルに付けたディレクティブでは動かせません。
この設定がフラグではなくプロジェクト単位なのは、生成出力が実行者によって変わっては
ならないからです。pw check はツリーを新しい生成結果と
比較するので、あるマシンが渡してあるマシンが渡さないフラグがあると、全マシンで
ドリフトが報告されます。
cmd/<name>/popcornweb_bootstrap_pw_gen.go は種類として例外です。ドキュメントシェルと
埋め込み公開アセットをバイナリにリンクするためのブランクインポートだけを含む生成
ファイルで、これによりハンドラがそれらを参照する必要がなくなります。どちらも存在しない
場合は自動的に削除されます。
dist/public は公開アセットが 1 つもないプロジェクトでも作られます。public.go が
go:embed でそのディレクトリを名指ししており、コンパイラが読むのはツリーではなく
ディレクティブだからです。
CBOR API ボディ
Section titled “CBOR API ボディ”generate.api.cbor を有効にすると、生成されるすべてのバインダとライタが JSON に加えて
application/cbor のリクエスト・レスポンスボディをネゴシエートするようになります。
[generate.api.cbor]enabled = trueこれが生成時・プロジェクト単位の設定なのは line_directives と同じ理由です。どの
メディアタイプを受け付けるかはサービスの属性であり、出力が実行者によって変わっては
なりません。隣に置ける 2 つのプロファイルキー reject_floats と sorted_keys は生成
フィンガープリントの一部なので、どちらかを変えるとコーデックが再生成され、コミット
するまで pw check に現れます。ワイヤ上で何が変わるか、
いつ切っておくべきかは CBOR ガイドが主題として扱います。
ドキュメント 1 つの規則
Section titled “ドキュメント 1 つの規則”プロジェクトに document.pw.html はちょうど 1 つです。ツリーのどこかに 2 つ以上あると
次のように失敗します。
pw: multiple default documents: templates/document.pw.html, admin/document.pw.html別のシェルは名前なしスロットを持つ通常のエクスポート済みコンポーネントとして書き、
ハンドラごとに pw.WriteHTMLChain で選択してください。
テンプレートを参照。
パッケージプロジェクトでは
Section titled “パッケージプロジェクトでは”コンポーネントパッケージにはエントリポイントも
public.go もドキュメントシェルもないので、手順 2 から 4 には対象がなく、生成された
Go を書いたところでコマンドは終わります。--code-only と同じ結果ですが、選ぶのは
project.kind であって、作者が覚えておくべきフラグではありません。
ビルド系のコマンドでパッケージプロジェクトが受け付けるのはこれだけです。
pw build と pw dev はどちらも
拒否します。動かすものがないからです。
CI での使い方
Section titled “CI での使い方”生成コードが最新かを検証してから、生成してコンパイルします。
pw checkpw generatego build ./cmd/myapppw check は何も書かず、古い出力があれば失敗します。
生成された Go は Git 管理外なので、リポジトリの差分では気づけません。
