Partager du code JavaScript client/server

Update : Pour ceux ayant lu l’article avant le 15/05/2013, la solution n’était pas bonne. L’article est mis à jour avec une autre solution qui elle, fonctionne 😀
L’avantage d’utiliser le JavaScript (CoffeeScript dans mon cas) côté serveur  (avec nodejs) et côté client, est de pouvoir partager du code.

Seulement un petit problème se pose. En effet, côté client, afin de créer un système de module, la solution la plus connue est d’utiliser RequireJS. Celle-ci s’appuie sur l’AMD (Asynchronus Module Definition) alors que côté serveur, nodejs repose sur CommonJS qui a une structure différente.

La première solution est de créer deux fichiers ayant la même fonction métier mais avec une structure différente. Pas très avantageuse, on a de la redondance alors qu’on travaille avec le même langage…

La deuxième solution consiste à importer la librairie requirejs dans node puis de l’utiliser. Je ne m’étendrais pas plus sur celle-ci dans ce billet.

Une autre solution consiste à modifier un peu nos fichiers JavaScript(ou CoffeeScript) afin qu’il soit compatible CommonJS du côté serveur et AMD côté client. Alors comment procéder ? Voici l’exemple de deux fichiers ayant la même fonction métier. C’est une simple classe avec une dépendance.

serveur :


client :


Le premier problème que nous voyons est que la classe Dog n’est pas au même niveau(en terme de scope) dans les deux fichiers. Côté serveur elle se situe dans le scope du “fichier” tandis que côté client, elle se trouve dans le scope de la fonction define.

Donc dans un premier temps, nous allons changer la structure du fichier sous RequireJS afin de faire ressortir la classe Dog afin qu’elle soit dans le scope voulu.


Petite parenthèse, lorsque je dis que le scope sera au niveau du fichier, cela ne signifie pas que le scope est le fichier. En effet, si on regarde comment est compilé ce fichier en JavaScript, on voit que le tout est englobé dans une fonction dont le scope est this(passé en paramètre de la fonction call) :


Notre scope “au niveau du fichier” est ce qu’est this à la dernière ligne (window par exemple du côté client). Si vous ne comprenez pas bien la manière dont fonctionnent les scopes, revoyez les notions de this, de scopes et de closures, c’est indispensable de bien comprendre ces notions lorsqu’on fait du JavaScript 🙂

Passons maintenant à la deuxième étape qui est de fusionner nos deux fichiers en un seul. L’astuce consiste à tester quelque chose qui nous permettra de déterminer de quel côté nous sommes. Ici j’ai choisi de tester la variable window. En effet côté serveur, celle-ci n’existe pas. On aurait pu aussi tester la méthode define : si celle-ci n’existe pas, alors nous sommes côté serveur. Bref, voici au final ce que ça donne :


Notre fichier est maintenant compatible AMD et CommonJS 🙂 On voit qu’il y a trois parties : la première concerne la déclaration de Burd ainsi l’import des dépendances avec CommonJS, la seconde notre code métier et la troisième l’import/export d’AMD ainsi que l’export de CommonJS.

Je vous met également la version JavaScript(qui sera donc utilisée côté client) :

2 thoughts on “Partager du code JavaScript client/server

  1. Très bon article et l’idée de partager le code métier entre le client et le serveur est très bonne ! Cependant, je me pose quelques questions, je me demande malgré tout si la solution d’utiliser r.js coté serveur ne serait pas plus perene.

    Avec la solution que tu as adoptée, tu es obligé d’importer (et d’exporter) toutes tes dépendances en double dans tous tes fichiers. L’avantage de RequireJS c’est que tu vas pouvoir avoir deux fichiers de config (une pour le client et une pour le serveur) qui va indiquer où se trouvent les dépendances et dans tes fichiers tu vas donc pouvoir les importer par le nom que tu leur auras donné.

    Un petit exemple pour illustrer :

    config côté serveur :

    config côté client :

    Et ensuite dans ton les fichiers qui ont besoin de Bird (qu’ils soient côté serveur ou côté client), tu as simplement à faire :

    Après je dois te dire que je n’ai pas expérimenté r.js en gestionnaire de dépendances côté serveur, donc je ne parle pas d’expérience ici, mais je pense que c’est une solution à explorer.

    A bon entendeur et merci pour cet article 🙂

    1. En effet oui, sur des petits projets, ou bien en te créant un template, c’est peut-être “valable”. Mais ça peut effectivement être lourd de devoir à chaque fois faire cette comparaison.

      Après tout comme toi, je ne l’ai pas utilisé donc je n’ai pas de retour d’expérience là dessus( pour ça aussi que je ne me suis pas étendu sur cette deuxième solution que j’ai énoncé). Faudra que je me penche sur ça 🙂

      Merci pour ton retour 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *