ビルドスクリプトのトップレベルawaitを関数内に移動してインポート時の破損を修正

shoelace-style/webawesome

ビルドスクリプト build.js がモジュールとしてインポートされる際に、トップレベルで package.json を読み込もうとして失敗していた問題を修正しました。バージョン情報の取得を build() 関数内に移動することで、実際のビルド実行時まで評価を遅延させています。

背景

build.js がアプリ側からインポートされると、モジュール評価時点でトップレベルの await readFile(...) が即座に実行されていました。アプリのビルド環境では、この時点でバンドルされたディレクトリがまだ生成されていないケースがあり、package.json の読み込みに失敗してビルドスクリプト全体が壊れる原因となっていました。

PR の説明にある通り、「このファイルはアプリからインポートされる可能性があり、その時点ではバンドル済みディレクトリがまだ生成されていない場合がある」という前提が考慮されていなかったことが問題の本質です。

技術的な変更

packageDataversion の取得、および初期ログ出力をトップレベルから build() 関数の先頭へ移動しました。

変更前:

const packageData = JSON.parse(await readFile(join(getRootDir(), 'package.json'), 'utf-8'));
const version = packageData.version;
let buildContexts = { ... };

console.log(`${chalk.hex('#ef6741')('🦊 Web Awesome')} v${version}\n`);
if (isDeveloping) spinner.info('Development mode');

export async function build(options = {}) {
  // ...
}

変更後:

let buildContexts = { ... };

export async function build(options = {}) {
  // packageData and version need to be set within the `build()` function because this file gets imported by the app,
  // which may not have generated its bundled directory yet, so this needs to be "lazily" evaluated.
  const packageData = JSON.parse(await readFile(join(getRootDir(), 'package.json'), 'utf-8'));
  const version = packageData.version;
  console.log(`${chalk.hex('#ef6741')('🦊 Web Awesome')} v${version}\n`);
  if (isDeveloping) {
    spinner.info('Development mode');
  }
  // ...
}

あわせて if (isDeveloping) のブロックが波括弧付きのスタイルに統一されました。これは機能的な変更ではなく、スタイルの一貫性のための修正です。

設計判断

「遅延評価(Lazy Evaluation)」によるファイルシステムアクセスのタイミング制御が採用されました。

ES モジュールのトップレベル await はモジュール評価時に即座に実行されるため、import するだけで副作用が発生します。ビルド対象のアプリがこのスクリプトをインポートした場合、ビルド完了前の状態でファイルシステムにアクセスしてしまうという競合状態が生じていました。修正では package.json の読み込みを build() 関数内に閉じ込めることで、実際にビルドが実行されるまでアクセスを遅延させています。

副作用を持つ処理を関数スコープに限定するこのアプローチは、モジュールの再利用性と安全性を高める設計原則に沿っています。

まとめ

トップレベル await によるモジュール評価時の副作用が、インポートされる側のスクリプトで問題を引き起こすという典型的なパターンへの対処です。ファイルシステムアクセスのような副作用を関数スコープに限定することで、モジュールのインポート安全性を確保しています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
2511f2fe

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
リトライ後承認
Review Count:
2回 (改善を経て承認)
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

「総論→各論→結論」の構成が明確です。リード文で要旨を述べ、背景、技術詳細、設計判断、まとめという各セクションが論理的に配置されています。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きシンタックスハイライト(`javascript:packages/webawesome/scripts/build.js`)およびGitHubのPRリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

トップレベルawaitやESモジュールの評価タイミングといった専門的なトピックを扱っており、対象読者であるエンジニアに適した技術レベルと表現です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが「総論→各論」で構成され、各段落がトピックセンテンスで始まるなど、パラグラフ・ライティングの原則が守られており、非常に読みやすい構造になっています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

変更前後のコードブロックは、提供されたDiffの内容を正確に反映しています。文脈を補うためのコードの引用や省略(`...`)も適切です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「トップレベルawait」「モジュール評価」「遅延評価 (Lazy Evaluation)」「副作用」といった技術用語が、文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

トップレベルawaitがモジュールインポート時に即時実行されるという挙動と、それを関数内に移動することで評価を遅延させるという解決策の説明は、技術的に正確かつ論理的です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内の主張はすべてPR DescriptionやDiff内のコード、特に「lazily evaluated」というコメントによって裏付けられており、ハルシネーションは一切見られません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#2190)、ファイルパス、関数名などの固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

PRのタイトル「fix broken app builds」の意図を汲み取り、「トップレベルawaitを関数内に移動してインポート時の破損を修正」という、より具体的で分かりやすいタイトルになっています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

記事の内容はすべて提供されたPR情報に基づいており、バージョンのサポート状況など、PRに記載のない外部知識の追加はありません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「モジュール評価時点」「ビルド実行時」といった技術的なタイミングに関する表現は正確であり、時間表現の歪曲はありません。