Skip to content

refactor(build): webpack + gulp から esbuild へ移行 - #7013

Open
nanasess wants to merge 7 commits into
EC-CUBE:4.4from
nanasess:feature/esbuild
Open

refactor(build): webpack + gulp から esbuild へ移行#7013
nanasess wants to merge 7 commits into
EC-CUBE:4.4from
nanasess:feature/esbuild

Conversation

@nanasess

@nanasess nanasess commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

概要(Overview・Refs Issue)

フロントエンドのビルドツールを webpack + gulp から esbuild へ移行します。

サプライチェーン耐性の強化(依存パッケージの削減)が主目的です。#6745 (Rspack 導入) のコメントで「サプライチェーン攻撃の増加が多く、gulp から esbuild への移行を考えております。RSpack と esbuild のメリットデメリットを考え、比較検討をさせていただきます」とご意見をいただいており、その比較検討の結果としての実装です。

先行実績として ec-cube2 の EC-CUBE/ec-cube2#1391 (Webpack 5 → esbuild、マージ済み) があります。

実測結果

指標 現行 (webpack+gulp) 本 PR (esbuild)
npm ci パッケージ数 561 110 (-80%)
npm audit 9 件 (high 6 / moderate 3) 0 件
node_modules 183 MB 149 MB
フルビルド 24.1 秒 1.0 秒
JS の差分ビルド (watch) 13 秒 約 50 ms
html/bundle の生成物 783 ファイル / 28 MB 19 ファイル / 8.8 MB

バンドルサイズ:

ファイル 現行 本 PR
front.bundle.js 229,486 B 235,735 B (+2%)
admin.bundle.js 1,340,149 B 1,267,915 B (-5%)
install.bundle.js 1,221,919 B 402,069 B (-67%)

install.bundle.js が大きく減るのは、現行バンドルに CSS の source map (sourcesContent) が約 800 KiB 混入していたためです。

#6745 (Rspack) との比較

同一の 4.4 上で、#6745package.json 変更を適用した構成を作って計測しました(依存数・脆弱性はいずれも lock なし最新解決で条件を揃えています。計測日 2026-07-31)。

指標 現行 #6745 相当 本 PR
インストール数 538 678 93
npm audit 9 件 (high 6 / moderate 3) 13 件 (high 6 / moderate 7) 0 件
node_modules 183 MB 298 MB 148 MB
html/bundle 783 469 19

Rspack は webpack 設定をほぼそのまま移植できる利点がある一方、gulp / browser-sync / 各 loader が残るため、#6745 の構成のままでは依存が現行より増加します。

なお #6745@rspack/cli は、gulp/task/rspack.js@rspack/core を直接呼んでいるためコードからは参照されておらず、外せる余地があります。外して計測すると 515 パッケージ / 268 MB / npm audit 9 件となり、現行 (538 / 183 MB / 9 件) に対して依存数は 23 減、脆弱性は同数、node_modules は 85 MB 増でした。現行に対する脆弱性の増加分 4 件はすべて @rspack/cli 由来です。

#6745 の現状 (2026-07-31 時点): base は 4.3、最新コミットは 2026-04-29 の 458b666c で、以降の更新はありません。本 PR は 4.4 が base のため、そのままでは同一ブランチ上での二者択一にはなりません。

方針(Policy)

  • テンプレートの変更を伴わないことを優先しました。CSS は現行の style-loader と同じく JavaScript から <style> として注入するため、default_frame.twig 等を上書きしている既存サイトでも表示が壊れません(ec-cube2 は静的ファイル分離を採用しましたが、本 PR では見送っています)
  • Rspack導入によるgulpビルド高速化 #6745 の良い部分は取り込みましたsass-embedded の採用です。SCSS のコンパイルは sass (JS) 比で約 2 倍高速になります
  • browser-sync は廃止しました。145 パッケージを持ち込み、npm audit の high 2 件 (immutable@3.8.3 / brace-expansion@1.1.17) の経路にもなっているためです。npm start は esbuild の watch のみになります(差分ビルドが約 50 ms のため、手動リロードで支障のない速度です)
  • ビルド定義は esbuild.config.mjs 1 ファイルに集約し、gulp のタスク分割は廃止しました

実装に関する補足(Appendix)

ace エディタ

ace-builds/webpack-resolverfile-loader?esModule=false!... という webpack 固有の inline loader 構文を使っており、esbuild では解決できません。管理画面のテンプレートで実際に使用しているモードを調べたうえで、必要なファイルのみを html/bundle/ace へ静的配置し、ace.config のパス設定から解決する方式に変更しました。

  • 使用モードは mode-twig (ページ/ブロック/レイアウト管理) / mode-css (CSS 管理) / mode-javascript (JS 管理)、テーマは theme-tomorrow のみ
  • worker は mode-twig が javascript / css / html の 3 つを参照するため同梱
  • これにより html/bundle の生成物が 763 ファイル削減されます

パスはサブディレクトリ設置でも解決できるよう、document.currentScript.src を基準に算出しています(webpack の自動 publicPath 相当)。

ace は読み込み時に自身の置き場を basePath だけでなく modePath / themePath / workerPath にも入れ、config.moduleUrl()options[component + 'Path']basePath より優先します。そのため basePath だけを上書きすると mode / theme / worker が html/bundle 直下を見て 404 になります(@ttokoro20240902 さんのご指摘。当初この不具合を入れていました)。4 つとも設定しています。snippetsPath は設定しません — 設定すると moduleUrl() が component と区切り文字を落とし、ace/snippets/fooace/foo.js に解決されて逆に壊れるためです(未設定なら basePath にフォールバックします)。

ace のバージョン更新時は npm ci && npm run buildhtml/bundle/ace が丸ごと入れ替わります(1.32.3 → 1.44.0 で追随を確認済み)。列挙したファイルが ace 側で無くなった場合はビルドが exit 1 で落ちるため気付けますが、テンプレートで新しいモードを使い始めた場合は esbuild.config.mjsaceFiles への追加が必要です(コード内にコメントを記載しています)。

jQuery UI

jQuery UI の各モジュールは UMD の AMD 分岐で内部依存を解決していますが、esbuild は AMD を解釈しないためグローバル分岐に落ち、内部依存が読み込まれずに実行時エラーになります($.ui.position$.ui.plugin.add の 2 段階で発生)。必要なモジュールを依存順に明示的に require しています。

なお #6745 でも同様の対応が入っており、これは esbuild 固有のコストではありません。

normalize.css

postcss-import の廃止に伴い、style.scss@import url('...normalize.css') が展開されずに出力されるようになりました。node_modules を含まない本番環境では 404 になるため、sass 側で展開される形(拡張子なしの @import)に変更しています。

CI

e2e-test.yml (2 箇所) と e2e-test-throttling.yml (1 箇所) のビルドキャッシュキーを gulpfile.js / webpack.config.js / gulp/**/*.js から esbuild.config.mjs に更新しました。coverage.yml には該当のキャッシュキーがないため変更していません。

dependabot の依存更新時に成果物を再生成 (dependabot-assets.yml)

EC-CUBE はビルド成果物をコミットして配布していますが、dependabot は package.json / package-lock.json しか更新しないため、依存を更新しても実際に配信されるバンドル・CSS は古いままになります(現行の webpack 構成でも同様です)。

dependabot の npm ブランチへの push を受けてビルドし、差分があれば同じブランチへ追記コミットするワークフローを追加しました。nanasess/setup-chromedriver の dependabot-dist.yml と同じ方式です。

  • e2e (Playwright) の依存は成果物に影響しないため !dependabot/npm_and_yarn/e2e/** で除外(branchesbranches-ignore は併用できないため否定パターンを使用)
  • github.actor == 'dependabot[bot]' を安全弁とし、contents: write はジョブレベルでのみ付与
  • GITHUB_TOKEN による push は workflow を再トリガーしないため、追記コミットによる無限ループは発生しません
  • ace のバージョンアップでファイルが増減し得るため、git add してから --cached で差分判定し、追跡外のファイルも拾います

本 PR で成果物が 783 → 19 ファイルになるため、この自動コミットの差分も追いやすくなります。

テスト(Test)

  • クリーン環境 (rm -rf node_modules) で npm ci && npm run build が成功
  • 同一入力からの出力がハッシュ一致(決定的なビルド)
  • Docker (docker-compose.nodejs.yml, node:20-bullseye) でのビルド成功
  • jsdom で 3 バンドルを評価しエラー 0 を確認。admin.bundle.js$ jQuery bootstrap $.fn.sortable $.fn.resizable $.fn.tooltip $.fn.qrcode ace Chart FilePond Ladda Spinner FilePondLocale_ja が定義され、<style> 4 枚が注入されることを確認
  • CSS 出力が現行と同等 (app.css ±0% / bootstrap.css ±0% / style.css ±0% / min 系 ±1%)
  • watch モード (npm start) で SCSS・JS の差分ビルドを確認
  • symfony cli で起動し、管理画面の ace エディタの動作を確認(当初 mode / theme / worker が 404 になる不具合があり、@ttokoro20240902 さんのご指摘を受けて修正済み。退行を検知できるよう admin-contents.spec.ts にテーマとモードのアサーションを追加)
  • dependabot-assets.yml を actionlint で検証(警告 0)。使用する actions の SHA は他ワークフローと同一のものに統一
  • E2E (CI で実行)

相談(Discussion)

  • Rspack導入によるgulpビルド高速化 #6745 と目的が重なるため、どちらを採用するかご判断いただければと思います。速度は Rspack でも十分改善しますが、依存パッケージ数・脆弱性では逆方向になります
  • esbuild は 0.x のためマイナーで破壊的変更が入る可能性があります。本 PR では ^0.28.1 としています
  • CSS の静的ファイル分離(<link> 化)は FOUC 解消などの利点がありますが、テンプレートを上書きしている既存サイトへの影響を避けるため本 PR では見送りました。別 PR で検討する余地があります
  • SCSS のレガシー @import に対する deprecation 警告は現行でも 84 件出ており、本 PR では抑止していません。Dart Sass 3.0 で @import は削除されるため、@use / @forward への移行は別途対応が必要です
  • 差分 828 ファイルのうち大半 (785 ファイル) はビルド成果物の削除です

マイナーバージョン互換性保持のための制限事項チェックリスト

  • 既存機能の仕様変更はありません
  • フックポイントの呼び出しタイミングの変更はありません
  • フックポイントのパラメータの削除・データ型の変更はありません
  • twigファイルに渡しているパラメータの削除・データ型の変更はありません
  • Serviceクラスの公開関数の、引数の削除・データ型の変更はありません
  • 入出力ファイル(CSVなど)のフォーマット変更はありません

※ PHP のコード変更はありません。開発時の npm start から browser-sync のライブリロードとプロキシが無くなる点のみ、開発フローの変更となります。

レビュワー確認項目

  • 動作確認
  • コードレビュー
  • E2E/Unit テスト確認(テストの追加・変更が必要かどうか)
  • 互換性が保持されているか
  • セキュリティ上の問題がないか
    • 権限を超えた操作が可能にならないか
    • 不要なファイルアップロードがないか
    • 外部へ公開されるファイルや機能の追加ではないか
    • テンプレートでのエスケープ漏れがないか

🤖 Generated with Claude Code

Summary by CodeRabbit

  • 新機能
    • Ace Editor に検索・置換UIを追加
  • 改善
    • ビルド処理を esbuild に移行し、開発時のウォッチに対応
    • E2E ビルド成果物のキャッシュ判定を更新
    • ブラウザ上のグローバル公開先を整理
    • Bootstrap を更新し、画面スタイルを改善
  • 影響
    • Ace Editor の言語モード、スニペット、テーマ構成を整理
  • ドキュメント
    • ビルド手順とフロントエンド技術スタックの記載を更新

nanasess and others added 2 commits July 30, 2026 16:52
ビルドツールを webpack + gulp から esbuild へ移行し、依存パッケージと
ビルド時間を削減する。

- 依存パッケージ 561 → 110 (-80%)
- npm audit の既知の脆弱性 9 件 → 0 件
- フルビルド 24.1 秒 → 1.0 秒 (JS の差分ビルドは約 50ms)
- html/bundle の生成物 783 ファイル → 19 ファイル

CSS は従来の style-loader と同じく JavaScript から <style> として注入するため、
テンプレートの変更は不要。

- ace は webpack-resolver (file-loader) を廃止し、使用する mode / theme / worker
  のみを html/bundle/ace へ静的配置して basePath から解決する。basePath は
  サブディレクトリ設置でも解決できるようバンドル自身の URL を基準にする
- jQuery UI は UMD の AMD 分岐が esbuild では使われず内部依存が読み込まれないため、
  必要なモジュールを依存順に明示的に require する
- SCSS は sass-embedded でコンパイルする
- browser-sync を廃止し、npm start は esbuild の watch のみとする
- normalize.css は postcss-import の廃止に伴い sass で展開する

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Gulp/Webpackベースのフロントエンドビルドをesbuildへ移行し、JavaScript・SCSS・Ace資産のビルド、watch処理、生成物、CSS、CI設定、技術資料を更新しました。

Changes

フロントエンドビルド移行

Layer / File(s) Summary
esbuildビルドパイプライン
esbuild.config.mjs, package.json
JavaScript、SCSS、PostCSS、Ace資産コピー、watch処理をesbuildへ移行し、npm scriptsと依存関係を更新しました。
Ace資産とワーカーの再構成
html/bundle/ace/*, html/bundle/*.js
Aceのモード、スニペット、テーマ、検索拡張、ワーカーなどの生成済み資産を更新しました。
生成済みフロントエンド成果物
html/bundle/front.bundle.js, html/template/*/assets/js/bundle.js
生成済みJavaScript、ライセンス出力、ブラウザ向けのwindow公開処理を更新しました。
CSS成果物の更新
html/template/admin/assets/css/bootstrap.css, html/template/default/assets/css/style.css, html/template/default/assets/scss/style.scss
Bootstrap、テンプレートCSS、SCSS import形式を更新しました。
ワークフローと技術資料
.github/workflows/*, AGENTS.md, README.md, llms.txt
Dependabot成果物生成、CIキャッシュキー、ビルドツールに関する資料を更新しました。

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested labels: refactor

Suggested reviewers: dotani1111, ttokoro20240902

Poem

ぴょんと跳ねればビルドが走る
SCSSの葉が風に舞う
Aceの森に新芽が咲き
うさぎは月で祝います

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.77% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed タイトルは、Webpack と Gulp から esbuild へのビルド基盤移行というプルリクエストの主な変更を明確に要約しています。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nanasess
nanasess marked this pull request as draft July 30, 2026 07:57
@nanasess
nanasess marked this pull request as ready for review July 30, 2026 07:57
dependabot は package.json / package-lock.json のみを更新するため、git 管理下の
ビルド成果物 (html/bundle, html/template/**/assets/css) は古いまま残る。
EC-CUBE は成果物をコミットして配布するため、依存を更新しても再ビルドしなければ
実際に配信されるバンドル・CSS には反映されない。

dependabot の npm ブランチへの push を受けてビルドし、差分があれば同じブランチへ
追記コミットする。

- e2e (Playwright) の依存は成果物に影響しないため否定パターンで除外する
- GITHUB_TOKEN による push は workflow を再トリガーしないため、追記コミットによる
  無限ループは発生しない
- ace のバージョンアップでファイルが増減し得るため、git add してから
  --cached で差分を判定し、追跡外のファイルも拾う

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@html/bundle/ace/snippets/html.js`:
- Line 1: HTML スニペット定義内の audio、bdi、hgroup.、map#、ol.、ol#、select.、time、track
などのテンプレートを確認し、欠落した引用符と不一致の終了タグを正しい HTML 構文へ修正してください。元のスニペットソースを更新した後、生成物である
ace/snippets/html.js を再生成し、Ace 展開時に有効な HTML が挿入される状態を保ってください。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment thread html/bundle/ace/snippets/html.js
@nanasess nanasess added this to the 4.4.0 milestone Jul 30, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/dependabot-assets.yml:
- Around line 25-47: Separate dependency-executing steps from write access:
change the build job’s permissions to contents: read and disable persisted
checkout credentials in the Checkout step, then pass only the generated assets
as an artifact to a separate contents: write job that checks out with its own
credentials and performs the Git push. Keep npm ci and npm run build in the
read-only job and move the regeneration commit/push logic to the write job.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 68491ae0-9562-4677-8ddf-c5ed04bcfcfb

📥 Commits

Reviewing files that changed from the base of the PR and between 6d17537 and 3de6659.

📒 Files selected for processing (1)
  • .github/workflows/dependabot-assets.yml

Comment thread .github/workflows/dependabot-assets.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
html/template/default/assets/css/style.css (1)

8736-8749: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

SCSS 側で height の計算式を単位対応にする必要があります。

$line-height-computed は現在 floor(...) px, $input-height-base(... ) px と単位付きの文字列連結になり、その後 * px があると Sass Embedded 1.99 で無効/互換性のない出力になります。html/template/default/assets/scss/mixins/_variables.scss$line-height-computed$input-height-basefloor(...) * 1px, (... ) * 1px に変え、既存の * px / px 付き指定を消してください。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@html/template/default/assets/css/style.css` around lines 8736 - 8749, Update
the SCSS variables $line-height-computed and $input-height-base in
_variables.scss to produce numeric pixel values using multiplication by 1px
rather than concatenating the px unit. Remove the existing * px and other
redundant px suffixes from dependent height calculations so the generated CSS
remains valid under Sass Embedded 1.99.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@html/bundle/front.bundle.js`:
- Around line 7-27: Update the esbuild configuration used to generate
front.bundle.js so legalComments is set to inline or eof, ensuring bundled
`@license/`@preserve notices from slick-carousel and `@popperjs/core` are included
alongside the existing jQuery and Bootstrap license information, then rebuild
the bundle.

---

Outside diff comments:
In `@html/template/default/assets/css/style.css`:
- Around line 8736-8749: Update the SCSS variables $line-height-computed and
$input-height-base in _variables.scss to produce numeric pixel values using
multiplication by 1px rather than concatenating the px unit. Remove the existing
* px and other redundant px suffixes from dependent height calculations so the
generated CSS remains valid under Sass Embedded 1.99.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

Comment thread html/bundle/front.bundle.js
@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.48%. Comparing base (e6876f4) to head (a7b1a54).
⚠️ Report is 13 commits behind head on 4.4.

Additional details and impacted files
@@            Coverage Diff             @@
##              4.4    #7013      +/-   ##
==========================================
+ Coverage   77.42%   77.48%   +0.06%     
==========================================
  Files         561      562       +1     
  Lines       27836    27898      +62     
==========================================
+ Hits        21552    21618      +66     
+ Misses       6284     6280       -4     
Flag Coverage Δ
Unit 77.48% <ø> (+0.06%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

npm ci / npm run build は更新された依存パッケージのコード (postinstall や
esbuild / sass-embedded のバイナリ) を実行する。これを書き込みトークンと同一
ジョブに置くと、依存コードが $GITHUB_PATH / $GITHUB_ENV へ書き込んで後続
ステップの実行ファイル解決や環境を汚染できるため、トークンを push ステップの
env に限定しても git フックを無効化しても奪取を防げなかった。
$GITHUB_PATH / $GITHUB_ENV はジョブ単位でジョブを跨いで引き継がれないため、
権限境界をジョブで切る。

- build ジョブ: contents: read のみ。checkout は persist-credentials: false。
  生成物の 3 ディレクトリだけを artifact 化する (.git / .husky を含めない)。
- push ジョブ: 依存パッケージのコードを一切実行せず、artifact を展開して
  contents: write で commit / push する。
- html/bundle は全ファイルが生成物なので展開前に削除し、ace のバージョンアップに
  よるファイル減少も削除としてコミットできるようにする。assets/css は対応する
  .scss を持たない vendor ファイル (tempusdominus) があるため上書き展開のみ。
- 展開先がずれたときに html/bundle の削除だけがコミットされないよう、展開結果を
  検証するステップを追加する。
- build と push の間に dependabot が追い越し push すると古い package-lock.json
  由来の成果物をコミットする窓があるため、concurrency で古い run を取り消す。

artifact の受け渡しパスは env.ASSET_PATHS に一本化し、upload の path・展開後の
検証・git add がずれて成果物を取りこぼさないようにする。

zizmor 1.28.0 で artipacked / undocumented-permissions / anonymous-definition /
concurrency-limits が解消することを確認 (actionlint 1.7.12 もクリーン)。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/dependabot-assets.yml:
- Around line 61-63: Update both checkout steps in the Dependabot workflow to
use github.sha instead of github.ref_name, including the checkout near the build
and the checkout near the push. Preserve the existing detached-HEAD-compatible
push command so delayed runs fail via the normal non-fast-forward check.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8bca8cc6-41fa-444e-b4d7-3da9a97f5fdd

📥 Commits

Reviewing files that changed from the base of the PR and between 3de6659 and f93ae96.

📒 Files selected for processing (1)
  • .github/workflows/dependabot-assets.yml

Comment thread .github/workflows/dependabot-assets.yml Outdated
checkout の ref にブランチ名 (github.ref_name) を渡すと、チェックアウト時点の
ブランチ先端が解決される。build ジョブと push ジョブは別ランナー・別時刻に解決
するため、build 後に dependabot が追加 push すると、古い成果物を新しい
package-lock.json の先端へコミットしてしまい、生成物と依存が食い違う。

両ジョブの checkout を github.sha (push イベントではトリガとなった tip commit)
に固定する。追い越された run が作るコミットはブランチ先端の子孫にならないため、
push が non-fast-forward で拒否されて赤くなる。concurrency は競合の窓を縮める
だけで原子的には防げないので、git 自身のチェックを最後の砦にする。

GITHUB_TOKEN による push は新しい run を作らない (無限ループ防止としてこの性質を
利用している) 以上、不整合な成果物がコミットされても自動では修復されない。
黙ってコミットするより失敗させるほうが安全。

push は HEAD:$BRANCH の形なので detached HEAD のままで動く。push 先を指す
BRANCH (github.ref_name) と push コマンドは変更していない。

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
dotani1111
dotani1111 previously approved these changes Jul 30, 2026
@dotani1111

dotani1111 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@nanasess
ありがとうございます。

esbuild 化に伴い、CSS のソースマップだけ挙動が変わっている点が気になりました。
ローカルで npm run build して確認したところ、.css / .min.css / JS バンドルはコミット済みと byte 一で、機能面は問題ありませんでした。

一方 .css.map の sources が、webpack 時代の相対パスから ビルドマシンの絶対 file:// パスに変わっています。

コミット済み(このブランチ)
file:///home/nanasess/git-repos/ec-cube.worktrees/feature/esbuild/node_modules/bootstrap/scss/...

4.4 base(webpack)
../../node_modules/bootstrap/scss/...

このため、生成物をコミットする運用と相性が悪く、誰が再ビルドしても .map だけ必ず差分化します(CSS/JS は無変更でも map の 6 ファイルが churn)。
コミット済み map に作者のローカルパスが焼き込まれる副作用もあります。

原因は sass-embedded が sources を絶対 URL で返すためで、書き出し直前に出力ディレクトリ基準の相対へ直すと解消します。

if (processed.map) {
  const mapDir = path.dirname(cssPath)
  const map = processed.map.toJSON()
  map.sources = map.sources.map((src) => {
    const abs = src.startsWith('file://') ? fileURLToPath(src) : src

    return path.isAbsolute(abs) ? path.relative(mapDir, abs) : abs
  })
  fs.writeFileSync(path.join(mapDir, mapName), JSON.stringify(map))
}

このパッチをローカルで当てて再ビルドし、sources が相対化されること・2回ビルドで map が byte 一致すること・CSS/JS 出力は無変更のままであることを確認済みです。
JS バンドルの .map は esbuild が既に相対で出しているため対応不要でした。

@dotani1111
dotani1111 dismissed their stale review July 31, 2026 00:54

ローカルビルド検証で CSS ソースマップの絶対パス(非決定的な生成物)問題が判明したため、承認を一旦取り消します。詳細は別コメントに記載しています。

@ttokoro20240902

Copy link
Copy Markdown
Contributor

@nanasess dependabot-assets.yml の権限について、CodeRabbit の指摘に同意です。

update-assetscontents: write を持ったまま、actions/checkoutpersist-credentials は既定 true)→ npm cigit push を同一ジョブで実行しています。dependabot のブランチでは更新された依存そのものを npm ci が実行するため、悪意ある npm リリースが push 権限に届きます。package-lock.json 上 install script を持つのは esbuild@parcel/watcher の2つで、後者は optional な sass 経由なので linux-x64 では入らず、実際に走るのは esbuildpostinstall 1本です。

対応は CodeRabbit の案(contents: read + persist-credentials: false のビルドジョブ → artifact → npm を実行しない push ジョブ)のほか、npm ci --ignore-scripts でも足りるかもしれません。手元で試したところ esbuild 0.28.1 / linux-x64 では --ignore-scripts でインストールしても CLI・JS API とも動作しました(bin/esbuild が JS のシムで、optional dependency の @esbuild/linux-x64 を実行時に解決するため)。

sass-embedded は sources を file:// の絶対 URL で返すため、ビルドしたマシンの
絶対パスがコミット済みの .map に焼き込まれていた。EC-CUBE は生成物をコミットして
配布するため、誰が再ビルドしても CSS / JS が無変更のまま .map の 6 ファイルだけが
差分化し、あわせて作者のローカルパスが公開リポジトリに残る状態だった。

webpack 時代の .map は sources が相対パスだったので、これは esbuild 移行に伴う回帰。

map ファイルからの相対パスへ直してから書き出す。区切り文字は POSIX 固定にして、
Windows で再ビルドしても同じバイト列になるようにする (source map の sources は
URL なのでバックスラッシュは不正)。

- .css / .min.css / JS バンドルは byte 無変更で、変わるのは .map のみ
- 相対化後の sources は 6 ファイル計 442 件すべてが実在パスへ解決することを確認
- sourcesContent は保持され、DevTools での表示は劣化しない
- 2 回ビルドして .map が byte 一致することを確認

JS バンドルの .map は esbuild が元から相対パスで出しているため対応不要。

Reported-by: dotani1111
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nanasess

Copy link
Copy Markdown
Contributor Author

@dotani1111 ご指摘ありがとうございます。おっしゃるとおりでした。修正しました。70149aaad04c940f8ce3016d8f6ab093306552a9

手元でも再現を確認しました。

  • コミット済みの .mapfile:///home/nanasess/.../node_modules/bootstrap/scss/... が焼き込まれていました
  • 4.4 base (webpack) の同ファイルは ../../node_modules/bootstrap/scss/... で相対だったので、esbuild 移行に伴う回帰です
  • git grep で HEAD の全追跡ファイルを走査したところ、本 PR で変更したもののうち絶対パスを含むのはご指摘の .map 6 ファイルのみでした
  • JS バンドルの .map は esbuild が元から相対で出しており、対応不要という点もそのとおりでした

生成物をコミットして配布する以上、再ビルドのたびに .map だけが churn するのと、作者のローカルパスが公開リポジトリに残るのはどちらも見過ごせないので、いただいたパッチをベースに取り込んでいます。

1 点だけ追加しています

path.relative() は OS 依存の区切り文字を返すため、そのままだと Windows で再ビルドしたときに ..\..\node_modules\... になり、同じ churn が再発します。source map の sources は URL なのでバックスラッシュは不正でもあり、POSIX 固定にしました。

return path.isAbsolute(abs) ? path.relative(mapDir, abs).split(path.sep).join('/') : abs

なお fileURLToPathesbuild.config.mjs の冒頭で既に import 済みだったので、import の追加は不要でした。

検証結果

  • 絶対パスの残存: 0file:/// / ローカルパスとも全消滅)
  • 変更されたのは .map 6 ファイルのみで、.css / .min.css / JS バンドルは byte 無変更
  • 相対化後の sources は 6 ファイル計 442 件すべてが実在パスへ解決することを確認(例: ../../../../../node_modules/normalize.css/normalize.css
  • sourcesContent は全件保持され、DevTools での表示は劣化しません
  • 2 回ビルドして .map が byte 一致することを確認

パッチまで添えていただき助かりました。

@nanasess

Copy link
Copy Markdown
Contributor Author

@ttokoro20240902 f93ae96 154044e で解消済みと思われます。ご確認よろしくお願い致します🙇‍♂️

@nanasess
nanasess enabled auto-merge July 31, 2026 02:06
@ttokoro20240902

ttokoro20240902 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

@nanasess 実機で確認したところ、ace の mode / theme / worker が読み込めていませんでした。

症状

ace を使う全画面(CSS管理 / JavaScript管理 / ページ管理 / ブロック管理 / レイアウト管理 / 受注メール)で 404 になります。

GET /html/bundle/mode-javascript.js  404
GET /html/bundle/theme-tomorrow.js   404
  • シンタックスハイライトとテーマが適用されません(.ace_editor の class が既定の ace-tm のまま)
  • JavaScript管理では worker も 404 になり、構文チェックが動きません

エディタ自体はプレーンテキストとして動作し値の取得・保存もできるため、E2E は緑のまま通ります。

修正前(JavaScript管理・意図的に構文エラーを入れたコード。単色で、6行目にエラーマーカーが出ない)

02-js-syntaxcheck-before

修正後(着色され、6行目に赤いエラーマーカーが出る)
02-js-syntaxcheck-after

原因

ace は読み込み時(ace/loader_build)に document.currentScript(= admin.bundle.js)から自身の置き場を推定し、basePath だけでなく modePath / themePath / workerPath にも同じ値を入れます。

// node_modules/ace-builds/src-noconflict/ace.js
scriptOptions.basePath   = scriptOptions.base;
scriptOptions.workerPath = scriptOptions.workerPath || scriptOptions.base;
scriptOptions.modePath   = scriptOptions.modePath   || scriptOptions.base;
scriptOptions.themePath  = scriptOptions.themePath  || scriptOptions.base;

config.moduleUrl()options[component + 'Path']basePath より優先して参照するため、basePath だけの上書きでは効きません。実測では basePath.../html/bundle/ace/modePath / themePath / workerPath.../html/bundle でした。

base では ace-builds/webpack-resolverace.config.setModuleUrl() を464回呼んで最優先の $moduleUrls を埋めていたため、この挙動が表に出ていませんでした。

修正案

html/template/admin/assets/js/bundle.js

const acePath = new URL('ace/', bundleSrc).href;
['basePath', 'modePath', 'themePath', 'workerPath'].forEach((key) => window.ace.config.set(key, acePath));

これを当てて再ビルドすると mode-twig.js / theme-tomorrow.js / snippets/*.js / worker-javascript.js がすべて 200 になり、ハイライトとテーマが適用され、JavaScript管理の構文チェックも動作しました(aceFiles の内容は変更不要でした)。

併せてご検討いただきたい点

この件はファイルが存在するのに参照先だけが違うため、E2E は通り抜けます。admin-contents.spec.ts に「.ace_editor の class に ace-tomorrow が付く」程度のアサーションを足しておくと、同種の退行を CI で止められます。

ace は読み込み時に自身の置き場 (= admin.bundle.js の位置) を basePath だけでなく
modePath / themePath / workerPath にも入れる (ace.js の scriptOptions 処理)。
config.moduleUrl() は options[component + 'Path'] を basePath より優先して参照する
ため、basePath だけを上書きしても mode / theme / worker は html/bundle 直下を見て
404 になっていた。

影響は ace を使う全画面 (CSS 管理 / JavaScript 管理 / ページ管理 / ブロック管理 /
レイアウト管理 / 受注メール)。エディタはプレーンテキストとして動作し値の取得・保存も
できてしまうため、ハイライトとテーマが効かず JavaScript 管理の構文チェックも
動かないまま E2E は素通りしていた。

移行前は ace-builds/webpack-resolver が setModuleUrl() を 463 回呼んで最優先の
$moduleUrls を埋めていたため、この挙動が表に出ていなかった。

4 つのキーすべてを html/bundle/ace へ向ける。snippetsPath は設定しない: 設定すると
moduleUrl() が component と区切り文字を落とし、ace/snippets/foo が ace/foo.js に
解決されて逆に壊れる (未設定なら basePath へフォールバックする)。

退行を CI で止められるよう、admin-contents.spec.ts の create page に
テーマ (ace-tomorrow) とモード (ace/mode/twig) のアサーションを追加した。
どちらも解決失敗時は既定値 (ace-tm / ace/mode/text) のままになるため検知できる。

Reported-by: ttokoro20240902
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@nanasess

nanasess commented Jul 31, 2026

Copy link
Copy Markdown
Contributor Author

@ttokoro20240902 実機での確認とスクリーンショットまでありがとうございます。ご指摘のとおりの不具合でした。修正しました。 a7b1a54

原因の説明も正確でした。こちらでもコードを追って裏取りしています。

  • ace.jsscriptOptions 処理が basePath / workerPath / modePath / themePath の 4 つとも scriptOptions.base(= admin.bundle.js の位置)で埋めている
  • config.moduleUrl()options[component + 'Path'] を先に見て、null のときだけ basePath へフォールバックする
  • 実際に読み込んでいる src-min-noconflict/ace.js にも同じロジックが入っている

moduleUrl() の実装をそのまま移植して、静的配置した実ファイルと突き合わせた結果です。ご報告の 404 URL と一致しました。

モジュール 修正前 修正後
ace/mode/javascript 404 /html/bundle/mode-javascript.js OK /html/bundle/ace/mode-javascript.js
ace/mode/twig 404 /html/bundle/mode-twig.js OK /html/bundle/ace/mode-twig.js
ace/mode/css 404 /html/bundle/mode-css.js OK /html/bundle/ace/mode-css.js
ace/theme/tomorrow 404 /html/bundle/theme-tomorrow.js OK /html/bundle/ace/theme-tomorrow.js
ace/mode/javascript_worker 404 /html/bundle/worker-javascript.js OK /html/bundle/ace/worker-javascript.js
ace/snippets/javascript OK(snippetsPath 未設定で basePath にフォールバック) OK

修正案をそのまま取り込みました。

検証中に分かった注意点を 1 つ

snippetsPath は追加してはいけません。 moduleUrl()snippetsPath が設定されていると component と区切り文字を空にするため、ace/snippets/javascript/html/bundle/ace/javascript.js に解決され、今度は snippets が 404 になります(未設定なら basePath にフォールバックして正しく解決されます)。

いただいた 4 キーちょうどが正解でした。将来「ついでに全部設定しておこう」とやられないよう、コードにコメントを残しています。

E2E について

ご提案どおり admin-contents.spec.tscreate page にアサーションを追加しました。テーマだけだと themePath しか守れないので、モードも併せて見ています。

await expect(page.locator('#editor')).toHaveClass(/ace-tomorrow/);
await expect
  .poll(() =>
    page.evaluate(() => (window as any).ace.edit('editor').session.getMode().$id),
  )
  .toBe('ace/mode/twig');

どちらも解決に失敗すると既定値(ace-tm / ace/mode/text)のままになるので、同種の退行を検知できます。npx playwright test --list で 19 テストが列挙されることまで確認しました(CI での実行結果はこれからです)。

PR 本文の「ace エディタ」節と確認項目にも、この経緯を反映しました。E2E が素通りする穴をご指摘いただけたのが特に助かりました。

@ttokoro20240902 ttokoro20240902 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@ttokoro20240902
ttokoro20240902 self-requested a review July 31, 2026 04:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants