register_asset による JS ライブラリの読み込み

プラグイン経由で register_asset を使用して追加された JS ファイルが文字列として eval 関数に渡されていることに気づきました。

eval の問題点は、ここで議論されているように、オブジェクトをグローバルスコープに追加しないことです(https://stackoverflow.com/questions/4670805/javascript-eval-on-global-scope)。これは JS ライブラリを使用する際に不可欠です。

具体的には、https://github.com/muaz-khan/RecordRTC/blob/master/RecordRTC.js をプラグインで使用しようとしたところ、関数が Ember ファイル内でアクセスできませんでした。

この回避策として、webpack でファイルを処理し、libraryTargetumd に設定する方法があります。

多くのライブラリがこの方法で処理されており、すぐに動作するようです。

私はこれらの分野の専門家ではありませんが、Discourse が登録されたアセットをグローバルスコープに追加することに意味があるかどうか疑問に思っています。

注:もしこれが馬鹿げているように聞こえる部分があればお詫びします。Discourse で JS ライブラリを動作させるために webpack いじりが必要になるとは予想していなかったので、この投稿を書く動機となりました。:wink:

ここがおかしいようです。register_asset でアセットを含める lazyYT プラグインを確認しましたが、eval ブロック内にはありませんでした。

問題を再現する小さなプラグインの例を提供していただけませんか?

これが意図しない副作用ではないかと思えます

(つまり、これは開発環境でのみ発生します)

私も同じことを思いました。もしそうなら回避策はありますが、再現可能な例が欲しいですね。

もちろん。

興味深いですね。その可能性を確認するために、本番環境でプラグインを実行してみます。

@eviltrout
OP で言及されている同じライブラリを使用した小さなプラグイン GitHub - fzngagan/js-test · GitHub

単に、イニシャライザー内でライブラリによって追加された関数を呼び出してみましたが、JS コンソールで ReferenceError: RecordRTC is not defined というエラーが表示されます。

デバッグに役立つよう、ライブラリの未圧縮バージョンを使用しました。

また、全体が eval 関数に渡されたことを示すための「ソース」タブからのスクリーンショットも添付します。

私が確認したもう一つの事実は、discourse-spoiler-alertlazy-yt の両方に含まれる js ファイルが、グローバルな jQuery オブジェクトに関数を注入していますが、トップレベルの関数を宣言していないことです。

プラグインを確認しましたが、eval は開発モードでのみ存在し、本番環境ではグローバルスコープに挿入されることを確認しました。それが理想的ではないことは理解していますが、ライブラリは通常、何らかのモジュール対応(例えば UMD など)なしに配布されるべきではないとも思いません。

私の提案としては、何らかの UMD 対応を含めて JS を再パッケージ化し、その後 import して使用することですが、モジュールに関する JS の経験があまりない場合、設定がやや複雑になる可能性があります。

代わりに、これを簡単に動作させるには、RecordRTC.js を編集し、以下の行を追加する方法があります。

window.RecordRTC = RecordRTC;

さらに良い方法は、ファイル全体の内容を IIFE で囲むことです。

(function(exports) {
  // 元のファイルの内容をここに記述
  exports.RecordRTC = RecordRTC;
})(window);

はい、同意します。多くのライブラリがそのように配布されており、それらはシームレスに動作します。この件を検討してくださり、確認をありがとうございます :+1: 私はライブラリを webpack でパッケージ化する方式を選びましたが、インポートしなくても動作しました。ただ、本番モードでテストすべきでした。