MT7-R5401 とそれ以前で管理画面内の JSON.stringify の動作が違うので注意が必要

MT7-R5401 とそれ以前で JSON.stringify の動作が違うので注意が必要です。

この記事は 「Movable Type Advent Calendar 2022」3日目の記事です。

先日リリースされたMovable Type 7 r.5401の中で、下記の変更点がありました。

[MTC-8706] js/common/JSON.js の利用を停止し、管理画面で読み込まないようにしました。互換性を確保するため、環境変数 UseMTCommonJSON を新設し 1 を設定すると js/common/JSON.js を読み込むようにしました。将来のバージョンでこの環境変数を含めて削除する予定です

普通にMTを使っている分には特にユーザーへの影響は小さいですし、管理画面をカスタマイズしなければ全く関係ないお話ですが、弊社のMTAppjQueryを使うなどして、ゴリゴリと管理画面をカスタマイズしている場合には意外と影響が大きかったりします。

ぱっと見だと、これまで使えていた Object.toJSON という拡張メソッドが使えなくなるので、JSON.stringify を使ってね、というので済みそうな話なのですが、この js/common/JSON.js の有無で JSON.stringify 自体の動作が変わってしまうので要注意です。

例えば、下記のようなオブジェクトを用意します。

const obj = {
  a: 'apple',
  b: [
    'banana',
    {
      c: {
        d: 1,
        e: 2
      }
    }
  ]
}

これを MT7 -R5401 で環境変数 UseMTCommonJSON を定義していない環境で JSON.stringify(obj) すると下記のようになります。

{"a":"apple","b":["banana",{"c":{"d":1,"e":2}}]}

これが想定する結果です。しかし、MT7-R5301 の環境だと以下のようになります。

{"a":"apple","b":"[\\"banana\\",{\\"c\\":{\\"d\\":1,\\"e\\":2}}]"}

これは想定する形にはなっていません。配列が文字列として出力されてしまっています。しかもバックスラッシュも二重になっているのでJSONとしても正しくない形でエラーです。

どうしてこうなるのか「JSON.stringify() - JavaScript | MDN」で調べてみたら、以下のような一文がありました。

値が toJSON() メソッドを持っている場合は、データがどのようにシリアライズされるかを定義する必要があります。

なるほど、確かに js/common/JSON.js をみてみるとばっちり toJSON メソッドを追加しています。この中でも特に、以下のように定義されている Array.prototype.toJSON が今回の問題の根源でした。

Array.prototype.toJSON = function() {
    var out = [ "[" ];
    for( var i = 0; i < this.length; i++ ) {
        if( out.length > 1 )
            out.push( "," );
        out.push( Object.toJSON( this[ i ] ) );
    }
    out.push( "]" );
    return out.join( "" );
}

この点を踏まえて、MTの管理画面では、MTのバージョンと環境変数 UseMTCommonJSON の定義の有無などをみて JSON.stringify を使う必要がありそうですね。もしくは、下記のような関数を用意して、しばらくはそれを使っても良いかもしれません。

function toJSONString (obj) {
    if (typeof Object.toJSON === 'function') {
        return Object.toJSON(obj);
    }
    return JSON.stringify(obj);
}

ちなみに、JSON.stringify を使う前に Array.prototype.toJSON = undefined;delete Array.prototype.toJSON; をすれば通常の動作になりますが、それはそれでMT本体の方の動きに影響があると嫌なので、上記のような関数で対応した方がいいかもしれませんね。

今回のこの変更、管理画面をカスタマイズすることが多く、しかも JSON を多用する場合はなかなか痛い変更でしたね。こういうケースって少ないと思うんですよ。

例えば、jQuery.ajax が使えなくなりますよってなったら fetch で代用したりすると思いますが、でも jQuery.ajax が使える環境では fetch の動作が壊れます、みたいな感じですからね(笑

次回リリースする弊社の MTAppjQuery v2.8.0 は上記の点を踏まえて修正しましたので、こちらがリリースされれば緊急対応的に設定していただいた UseMTCommonJSON も不要になります。

あと数日お待ちください!

Published 2022-12-03
Updated 2022-12-25

「Movable Type」カテゴリの記事一覧