388 votes

Avec Rails 3.1, où placez-vous votre code JavaScript "spécifique à la page" ?

D'après ce que j'ai compris, tout votre JavaScript est fusionné en un seul fichier. Rails fait cela par défaut lorsqu'il ajoute //= require_tree . au bas de votre application.js fichier manifeste.

Cela semble être un véritable gain de temps, mais je suis un peu préoccupé par le code JavaScript spécifique à la page. Ce code est-il exécuté sur chaque page ? La dernière chose que je souhaite, c'est que tous mes objets soient instanciés pour chaque page alors qu'ils ne sont nécessaires que sur une seule page.

De plus, n'y a-t-il pas un potentiel pour un code qui entre en conflit aussi ?

Ou vous mettez un petit script en bas de la page qui appelle simplement une méthode qui exécute le code javascript de la page ?

N'avez-vous plus besoin de require.js alors ?

Merci

EDIT : J'apprécie toutes les réponses... et je ne pense pas qu'elles touchent vraiment au problème. Certaines parlent de style et ne semblent pas avoir de rapport avec le problème... et d'autres ne font que mentionner... javascript_include_tag ... dont je sais qu'il existe (évidemment...) mais il semblerait que la méthode Rails 3.1 consiste à regrouper tout votre JavaScript dans un seul fichier plutôt que de charger des JavaScript individuels en bas de chaque page.

La meilleure solution que j'ai trouvée est d'envelopper certaines fonctionnalités dans des fichiers div tags avec id ou class es. Dans le code JavaScript, vous vérifiez simplement si le bouton id o class est sur la page, et s'il l'est, vous exécutez le code JavaScript qui lui est associé. Ainsi, si l'élément dynamique ne se trouve pas sur la page, le code JavaScript ne s'exécute pas, même s'il a été inclus dans le fichier massif. application.js fichier emballé par Sprockets.

La solution que je propose ci-dessus présente l'avantage que si un champ de recherche est inclus dans 8 des 100 pages, il ne fonctionnera que sur ces 8 pages. Vous n'aurez pas non plus à inclure le même code sur 8 des pages du site. En fait, vous ne devrez plus jamais inclure de balises script manuelles sur votre site.

Je pense que c'est la réponse réelle à ma question.

11 votes

"La méthode Rails 3.1 consiste à regrouper tout votre Javascript dans un seul fichier plutôt que de charger des Javascript individuels en bas de chaque page" - Seulement parce que l'équipe centrale de Rails est, et a toujours été, très mauvaise dans la gestion de JavaScript. Les petits fichiers sont généralement meilleurs (voir mes commentaires ailleurs). Lorsqu'il s'agit de JavaScript, la méthode Rails est rarement la bonne (à l'exception du pipeline d'actifs, qui déchire, et de l'encouragement de CoffeeScript).

0 votes

Donc vous allez inclure vos fichiers js spécifiques à chaque page sur chaque page ? Je pense que c'est du gaspillage, je suis plus d'accord avec la réponse de ClosureCowboy.

1 votes

Avez-vous jeté un coup d'œil à la réponse acceptée pour cette question ? stackoverflow.com/questions/6571753/

157voto

meleyal Points 7367

La documentation d'Asset Pipeline suggère comment faire du JS spécifique au contrôleur :

Par exemple, si un ProjectsController est généré, il y aura un nouveau fichier à l'adresse app/assets/javascripts/projects.js.coffee et un autre à app/assets/stylesheets/projects.css.scss . Vous devez placer tout JavaScript ou CSS propre à un contrôleur dans ses fichiers d'actifs respectifs, car ces fichiers peuvent ensuite être chargés uniquement pour ces contrôleurs avec des lignes telles que <%= javascript_include_tag params[:controller] %> o <%= stylesheet_link_tag params[:controller] %> .

Lien vers : pipeline_de_biens

50 votes

C'est la manière la plus élégante de le faire. Mais aussi, vous devrez supprimer la ligne //= require_tree . de l'application.js.coffee

2 votes

Je suis tout à fait d'accord avec cette méthode. Les autres méthodes semblent très maladroites et finissent toujours par charger un fichier js géant. Le projet sur lequel je travaille a presque 2 mb de fichiers JS / plugins etc APRÈS avoir été combiné / minifié.

2 votes

Je suis assez novice en matière de Rails, mais il me semble que cela devrait être le comportement par défaut.

77voto

welldan97 Points 1962

Pour le js spécifique à la page, vous pouvez utiliser La solution Garber-Irish .

Ainsi, votre dossier javascripts Rails pourrait ressembler à ceci pour deux contrôleurs - voitures et utilisateurs :

javascripts/
├── application.js
├── init.js
├── markup_based_js_execution
├── cars
│   ├── init .js
│   ├── index.js
│   └── ...
└── users
    └── ...

Et les javascripts ressembleront à ça :

// application.js

//= 
//= require init.js
//= require_tree cars
//= require_tree users

// init.js

SITENAME = new Object();
SITENAME.cars = new Object;
SITENAME.users = new Object;

SITENAME.common.init = function (){
  // Your js code for all pages here
}

// cars/init.js

SITENAME.cars.init = function (){
  // Your js code for the cars controller here
}

// cars/index.js

SITENAME.cars.index = function (){
  // Your js code for the index method of the cars controller
}

et markup_based_js_execution contiendront du code pour l'objet UTIL, et pour l'exécution de l'UTIL.init prête pour le DOM.

Et n'oubliez pas de mettre cela dans votre fichier de mise en page :

<body data-controller="<%= controller_name %>" data-action="<%= action_name %>">

Je pense également qu'il est préférable d'utiliser des classes plutôt que des data-* pour un meilleur css spécifique à la page. Comme Jason Garber l'a mentionné : les sélecteurs CSS spécifiques à une page peuvent devenir vraiment gênants (lorsque vous utilisez des attributs data-* attributs)

J'espère que cela vous aidera.

4 votes

Que faire si vous avez besoin d'une variable disponible pour toutes les actions dans le contrôleur des utilisateurs, mais non disponible dans les autres contrôleurs ? Cette méthode ne pose-t-elle pas des problèmes de champ d'application ?

0 votes

@tybro0103, je pense que pour mettre en œuvre ce comportement, vous devriez écrire quelque chose comme window.varForOneController='val' dans la fonction init de ce contrôleur. Aussi gon gem peut aider ici( github.com/gazay/gon ). Il peut y avoir d'autres solutions de contournement.

0 votes

Actuellement, j'essaie de ne pas utiliser de js spécifique à une page. J'essaie de rester avec $(.classname) sélecteurs, mais je ne mets pas beaucoup de logique dans les js.

65voto

sujal Points 931

Je vois que vous avez répondu à votre propre question, mais voici une autre option :

Fondamentalement, vous faites l'hypothèse que

//= require_tree .

est nécessaire. Ce n'est pas le cas. N'hésitez pas à le supprimer. Dans mon application actuelle, la première que je réalise avec la 3.1.x honnêtement, j'ai créé trois fichiers JS de haut niveau différents. Mon application.js n'a que

//= require jquery
//= require jquery_ujs
//= require_directory .
//= require_directory ./api
//= require_directory ./admin

Ainsi, je peux créer des sous-répertoires, avec leurs propres fichiers JS de premier niveau, qui ne contiennent que ce dont j'ai besoin.

Les clés sont :

  1. Vous pouvez supprimer require_tree - Rails vous permet de changer les hypothèses qu'il fait
  2. Il n'y a rien de spécial dans le nom application.js - tout fichier dans le assets/javascript peut inclure des directives de pré-processeur avec des directives //=

J'espère que cela vous aidera et ajoutera quelques détails à la réponse de ClosureCowboy.

Sujal

8 votes

+1 C'est bon à savoir pour un débutant comme moi. Je lui donnerais +2 si je pouvais.

6 votes

@sujal Exactement. L'équipe principale de Rails est réputée pour sa gestion abyssale du JavaScript. N'hésitez pas à ignorer leurs suggestions et à utiliser simplement la fonction bon des parties du pipeline d'actifs :)

1 votes

Merci beaucoup pour ces conseils. Je n'ai pas plusieurs fichiers JS "top-level", selon le module de mon application. Cela fonctionne bien.

41voto

ClosureCowboy Points 5023

Une autre option : pour créer des fichiers spécifiques à une page ou à un modèle, vous pouvez créer des répertoires à l'intérieur de l'arborescence de votre site Web. assets/javascripts/ dossier.

assets/javascripts/global/
assets/javascripts/cupcakes
assets/javascripts/something_else_specific

Votre principal application.js pourrait être configuré pour charger ses fichiers à partir de global/ . Des pages spécifiques ou des groupes de pages pourraient avoir leurs propres manifestes qui chargent des fichiers à partir de leurs propres répertoires spécifiques. Sprockets combinera automatiquement les fichiers chargés par application.js avec vos fichiers spécifiques à la page, ce qui permet à cette solution de fonctionner.

Cette technique peut être utilisée pour style_sheets/ également.

13 votes

Tu me donnes envie de gâteaux maintenant Dangit !

0 votes

J'aime beaucoup cette solution. Le seul problème que j'ai avec elle est que ces manifestes supplémentaires ne sont pas compressés/uglifiés. Ils sont pourtant correctement compilés. Existe-t-il une solution ou ai-je manqué quelque chose ?

1 votes

Cela signifie-t-il que le navigateur charge un seul fichier js, qui est une combinaison du fichier global et du fichier spécifique à la page ?

23voto

Fire Emblem Points 2439

J'apprécie toutes les réponses... et je ne pense pas qu'elles touchent vraiment au problème. Certaines parlent de style et ne semblent pas avoir de rapport avec le problème... et d'autres ne font que mentionner... javascript_include_tag ... dont je sais qu'il existe (évidemment...) mais il semblerait que la méthode Rails 3.1 consiste à regrouper tout votre Javascript dans un seul fichier plutôt que de charger des Javascript individuels en bas de chaque page.

La meilleure solution que j'ai trouvée est d'envelopper certaines fonctionnalités dans des fichiers div tags avec id ou class es. Dans le code javascript. Ensuite, il suffit de vérifier si le id o class est sur la page, et si c'est le cas, vous exécutez le code javascript qui lui est associé. De cette façon, si l'élément dynamique ne se trouve pas sur la page, le code javascript ne s'exécute pas - même s'il a été inclus dans le fichier massif. application.js fichier emballé par Sprockets.

La solution que je propose ci-dessus présente l'avantage que si un champ de recherche est inclus dans 8 des 100 pages, il ne fonctionnera que sur ces 8 pages. Vous n'aurez pas non plus à inclure le même code sur 8 des pages du site. En fait, vous ne devrez plus jamais inclure de balises script manuelles sur votre site - sauf peut-être pour précharger des données.

Je pense que c'est la réponse réelle à ma question.

0 votes

Mais vous voulez vraiment ces manuels <script> tags. Oui, les classes et les identifiants font partie de la réponse, mais il n'est pas logique que l'utilisateur charge du JavaScript dont cette page particulière n'a pas besoin.

4 votes

@MarnenLaibow-Koser la raison pour laquelle il ne faut pas ajouter des balises script manuelles à chaque page unique est que vous devez télécharger ce contenu script à chaque affichage de page. Si vous êtes en mesure de regrouper tout le javascript dans application.js en utilisant le pipeline d'actifs, alors l'utilisateur télécharge ces scripts une seule fois et tire application.js du cache à tous les chargements de pages ultérieurs

0 votes

@jakeonrails "la raison pour ne pas ajouter des balises script manuelles à chaque page unique est que vous devez télécharger ce contenu script à chaque vue de la page"- tout à fait faux. La balise script sera téléchargée une fois, puis sera récupérée dans le cache du navigateur lors des prochaines requêtes. "Si vous êtes en mesure de regrouper tout le javascript dans application.js en utilisant le pipeline d'actifs, l'utilisateur ne téléchargera ces scripts qu'une seule fois" - vrai, mais au prix de beaucoup de code inutile. Si vous pouvez structurer votre JS en plusieurs petits fichiers au lieu d'un gros, vous bénéficiez des avantages de la mise en cache sans code inutile.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X