建設アシストのコードのセキュリティ対策として、CSP(Content Security Policy)でunsafe-evalを禁止した結果、Alpine.js の式評価がブロックされ動作不能になった問題を解決します
1.パッケージ切り替え・ビルド設定
package.json / resources/js/app.js
| 変更内容 | 詳細 |
| alpinejs → @alpinejs/cspに差し替え | npm install @alpinejs/cspを実行、app.jsのインポートを変更 |
| グローバル Alpine コンポーネントを app.jsに集約 | alpine:initイベント内で Alpine.data()を登録 |
app.jsに登録したグローバルコンポーネント:
| コンポーネント名 | 用途 |
| scheduleInitModal(chartType, switchUrl) | 工程表 初期選択モーダル |
| flashMessage | プロフィール保存後フラッシュメッセージ(2秒フェードアウト) |
| dropdownMenu | ナビゲーション ドロップダウン |
| laravelModal(initialShow, modalName, focusable) | Breeze 標準モーダル(フォーカストラップ付き) |
2.変更ファイル一覧(12ファイル)
2-1. resources/js/app.js
- インポートをalpinejs → @alpinejs/cspに変更
- alpine:initブロックに 4 つのグローバルコンポーネントを登録
2-2. resources/views/company_admin/index.blade.php
- 着手前に対応済み(本作業の起点)
- x-data=”companyAdmin”形式で Alpine.data 登録済み
2-3. resources/views/schedules/barchart.blade.php
barChart() 関数に CSP ヘルパーメソッド 32 件を追加。
| 変更前(HTML) | 変更後 |
| @click=”viewMode=’edit’; renderAll()” | @click=”switchToEdit()” |
| :style=”viewMode===’edit’ ? … : …” | :style=”viewModeStyle(‘edit’)” |
| :style=”mode===’DRAW_BAR’ ? … : …” | :style=”modeDrawBarStyle()” |
| @input=”setZoom($event.target.value/100)” | @input=”setZoomFromInput($event)” |
| x-text=”Math.round(zoom*100)+’%'” | x-text=”zoomText()” |
| :disabled=”!scheduleId” | :disabled=”scheduleNotSelected()” |
| :style=”`width:${canvasWidth}px…`” | :style=”hscrollStyle()” |
| :style=”`left:${ctxMenu.x}px…`” | :style=”ctxMenuPosStyle()” |
| x-text=”ctxMenu.type===’bar’ ? … : …” | x-text=”ctxMenuTitle()” |
| x-text=”barModal.startDate + ‘ → ‘ + …” | x-text=”barStartEndText()” |
| :disabled=”!modalBasisTotal()” | :disabled=”applyBasisDisabled()” |
| :class=”barModal.pattern === p.v ? …” | :class=”patternBtnClass(p.v)” |
| x-text=”annotModal.isConnMode ? …” | x-text=”annotModalTitle()” |
| @click=”annotModal.bold=!annotModal.bold” | @click=”toggleAnnotBold()” |
| :style=”cell && cell.isExtra ? … : …”(5段ネスト) | :style=”calCellStyle(cell)” |
| x-show=”createModal.extraHolidays.length > 0″ | x-show=”hasExtraHolidays()” |
| x-text=”createModal.calendarYear + ‘年 ‘ + …” | x-text=”calendarMonthTitle()” |
2-7. resources/views/components/schedule-init-modal.blade.php
scheduleInitModal(chartType, switchUrl)をapp.js`に登録。savedSchedules /openCreateModal() /openLoadModal()`は Alpine プロキシ経由で親スコープ(barChart / networkSchedule)から参照。
| 変更前 | 変更後 |
| x-data=”{ selectedType:{{ $chartType }}’ }” | | x-data=”scheduleInitModal(‘{{ $chartType }}, {{ $switchUrl }})” |
| @click=”selectedType ===…&& savedSchedules.length === 0 ? …” | :class=”loadBtnClass()” |
| x-text=”(+savedSchedules.length+件)” | x-text=”savedCountText()” |
2-4. resources/views/schedules/network.blade.php
networkSchedule() 関数に CSP ヘルパーメソッド 39 件を追加。barchart と共通の変換に加え以下を対応。
| 変更前 | 変更後 |
| @change=”renumberNodes(); renderAll()” | @change=”renumberAndRender()” |
| :class=”mode===’IDLE’ ? ‘text-gray-300: …” | :class=”hintBarClass()” |
| :style=”modal.lineType===’solid ? …” | :style=”lineTypeStyle(‘solid’)” |
| :style=”modal.arrowShape===TL ? …” | :style=”arrowShapeStyle(TL)”` |(6種類) |
| x-text=”fmtDate(modal.startDate)+’ → ‘+calcEndDate()” | x-text=”arrowDateRange()” |
| x-text=”modalCeilDays() ? … + ‘日’ : ‘-'” | x-text=”ceilDaysText()” |
| x-text=”modalBasisTotal() ? … + ‘日’ : ‘-'” | x-text=”basisTotalText()” |
2-5. resources/views/components/modal.blade.php
Breeze 標準モーダルコンポーネントをLaravelModalに完全移行。
| 変更前 | 変更後 |
| x-data=”{show: @js($show), focusables() {…}, …}”|init()`としてapp.js のlaravelModal`内に移行 | x-data=”laravelModal(@js($show), ‘{{ $name }}’, …)” |
| x-init=”$watch(‘show’, value => {…})” | x-on:open-modal.window=”… ? show = true : null” |
| x-on:open-modal.window=”handleOpenModal($event)” | x-on:keydown.tab.prevent=”$event.shiftKey || …” |
| x-on:keydown.tab.prevent=”onTab($event)” | x-on:click=”show = false” |x-on:click=”closeModal()” |
2-6. resources/views/components/dropdown.blade.php
| 変更前 | 変更後 |
| x-data=”{ open: false }” | x-data=”dropdownMenu” |
| @click.outside=”open = false” | @click.outside=”closeMenu()” |
| @click=”open = ! open” | @click=”toggleMenu()” |



