J’ai remarqué que les fichiers JS ajoutés via register_asset par les plugins sont transmis sous forme de chaîne de caractères à la fonction eval.
Le problème avec eval est qu’il n’ajoute pas l’objet à la portée globale, comme discuté ici : https://stackoverflow.com/questions/4670805/javascript-eval-on-global-scope, ce qui est essentiel pour utiliser une bibliothèque JS.
Pour être précis, j’essayais d’utiliser https://github.com/muaz-khan/RecordRTC/blob/master/RecordRTC.js dans un plugin, mais les fonctions n’étaient pas accessibles dans les fichiers Ember.
La solution de contournement consiste à traiter le fichier avec webpack en utilisant libraryTarget défini sur umd.
De nombreuses bibliothèques sont traitées de cette manière, ce qui semble fonctionner immédiatement.
Je ne suis pas un expert en la matière, mais je me demandais s’il serait logique que Discourse ajoute les ressources enregistrées à la portée globale.
Note : Désolé si certains points semblent absurdes. Je ne m’attendais pas à devoir manipuler webpack pour faire fonctionner les bibliothèques JS avec Discourse, ce qui m’a motivé à publier ce texte.
Quelque chose semble incorrect ici — j’ai examiné notre plugin lazyYT qui inclut un asset via register_asset et il ne se trouvait pas dans un bloc eval.
Pourriez-vous fournir un petit exemple de plugin qui reproduit le problème ?
J’ai simplement essayé d’appeler la fonction ajoutée par la bibliothèque dans l’initialiseur, et dans la console JS, j’obtiens ReferenceError: RecordRTC is not defined.
J’ai utilisé la version non minifiée de la bibliothèque, ce qui pourrait être utile pour le débogage.
De plus, une capture d’écran de l’onglet sources pour montrer que tout a été transmis à la fonction eval.
Une autre découverte que j’ai faite est que les fichiers JS inclus dans discourse-spoiler-alert et lazy-yt injectent des fonctions dans l’objet jQuery global, mais ne déclarent aucune fonction au niveau supérieur.
J’ai examiné votre plugin et je peux confirmer que eval n’est présent qu’en mode développement. En production, il sera inséré dans la portée globale. Je comprends que ce n’est pas idéal, mais je pense également que les bibliothèques ne devraient normalement pas être distribuées sans une forme de prise en charge des modules (par exemple, UMD).
Ma suggestion serait de reconditionner le JS avec une prise en charge UMD, puis de l’importer, mais cela peut être un peu délicat à configurer si vous n’avez pas beaucoup d’expérience avec les modules JS.
À la place, un moyen simple de faire fonctionner cela consiste à modifier RecordRTC.js et à ajouter la ligne suivante :
window.RecordRTC = RecordRTC;
Ce serait encore mieux d’envelopper l’intégralité du contenu dans une IIFE :
(function(exports) {
// le contenu original du fichier va ici
exports.RecordRTC = RecordRTC;
})(window);
Oui, je suis d’accord. Beaucoup le sont de cette façon et fonctionnent de manière transparente. Merci d’avoir examiné cela et pour la confirmation J’ai opté pour l’empaquetage de la bibliothèque via webpack et cela fonctionne sans même avoir besoin de l’importer. J’aurais dû le tester en mode production, cependant.