Laravel 8.70 @json ディレクティブの改訂版、Js::from() メソッドを試す
前書き
PHP の変数を JS で使えるように json 形式で出力してくれる @json ディレクティブというのがありましたが、その改訂版とでも言うべき Js::from() メソッドが誕生しました。
@json の場合、コンポーネントとの親和性がよろしくなかったので、それを解決すべく誕生した感じです。
使ってみる
ということで、早速使ってみます。
Ver. 8.70 以降を新規にインストールした場合は大丈夫ですが、そうではなく後からバージョンアップした場合は、以下を追加しておきましょう。
config/app.php
return [
'aliases' => [
// ...
'Js' => Illuminate\Support\Js::class,
],
];
試しに、web.php で以下のように記述します。
Route::get('/', function () {
$user = User::make(['name' => '与太郎']);
return view('welcome', compact('user'));
});
で、welcome.php は、以下のように記述してみます。
<script>
var person = @json($user);
var person = {{ Js::from($user) }};
var person = {!! Js::from($user) !!};
console.log(person)
</script>
出力(ソース)は、以下のようになります。
<script>
var person = {"name":"\u4e0e\u592a\u90ce"};
var person = JSON.parse('{\u0022name\u0022:\u0022\\u4e0e\\u592a\\u90ce\u0022}');
var person = JSON.parse('{\u0022name\u0022:\u0022\\u4e0e\\u592a\\u90ce\u0022}');
console.log(person)
</script>
コンソール画面には、以下の感じで出力されます。
{name: "与太郎"}
この場合は、@json でも Js::from() でも問題無く動作します。
Htmlable を実装している為、{!! !!} ではなく、{{ }} を使って大丈夫です。
で、それから?
さて、問題はここからです。
@json の場合、コンポーネントに引き渡した場合、コンパイルされないという問題がありました。下記のようなコンポーネントがあったとします。
(Alpine.js を想定したコンポーネントです。x-html, x-data は、Alpine.js の記述です)
components/hello.blade.php
<div {{ $attributes }}>
こんにちは、<span x-html="user.name"></span>さん
</div>
このコンポーネントを利用する為、以下のように記述したとします。
<x-hello x-data="{user: @json($user)}" />
しかし、残念ながら、全くダメです。以下の出力となってしまいます。
<div x-data="{user: @json($user)}">
こんにちは、<span x-html="user.name"></span>さん
</div>
もはや構文エラーです。そこで、今回の主役の Js::from() を使ってやります。
<x-hello x-data="{user: {{ Js::from($user) }}}" />
出力は以下の通り
<div x-data="{user: JSON.parse('{\u0022name\u0022:\u0022\\u4e0e\\u592a\\u90ce\u0022}')}">
こんにちは、<span x-html="user.name"></span>さん
</div>
これで無事、Alpine.js が動作し、画面には、「こんにちは、与太郎さん」と出力されます。
@js(追記)
その後すぐ、Js::from() のディレクティブ版の @js() というのも誕生しました。
[8.x] Introduce @js() directive #39522
あとがき
いつかお世話になる時があるかも知れません。
ちなみに、これに伴い @json はドキュメントから姿を消し、代わりに Js::from() が記載される事になりました。今後は、Js::from() を使っておいた方が良いでしょうか。
間違い等ありましたら、コメント下さい。
Discussion