🚀

Laravel 8.70 @json ディレクティブの改訂版、Js::from() メソッドを試す

2021/11/12に公開

前書き

PHP の変数を JS で使えるように json 形式で出力してくれる @json ディレクティブというのがありましたが、その改訂版とでも言うべき Js::from() メソッドが誕生しました。

@json の場合、コンポーネントとの親和性がよろしくなかったので、それを解決すべく誕生した感じです。

参考:#39389, #39460, bbf47d5

使ってみる

ということで、早速使ってみます。

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