「jQueryで書くとグチャグチャになる」への処方箋、もしくは昔々のJSでのモジュール化について

f:id:ms2sato:20180805232858j:plain

はじめに

TECHDRIVE の佐藤です。

ちょっとあるところで盛り上がったので、ちゃんと書いたらどうなるかなと*1。 「『jQueryで書くとグチャグチャになる』という話を聞くけれど、それってモジュール化をちゃんとしていないからじゃないか」 という話から発しています。

以前からJavaScriptと付き合っている人にとっては、ただの古めかしいイディオムです。ただ、SPAするレベルでなく「ちょっとした動き」をさせたいような場合もソコソコあると思うので、そういう人には参考になるかもしれません。

というわけでこれはレガシーなJavaScriptと付き合う場合のあるあるな方法を今更紹介したものです。特に何か目新しいものがあるわけでもなく、最新のJavaScriptを相手にしていける環境の人には全く関係のないものです(周辺技術が既にこういう部分をカバーして進んでいますし、今後ブラウザにも追加されていくだろうからです)。

解決したい問題

  • RailsなどでAssetsCompileしていると、そもそも全てのJSが動いてしまって「どれが動くのか」わからない。「他の画面の為の内容が影響してバグる」
  • 外部ライブラリ等と名前が被ってしまう問題を回避したい。
  • 動作するものの単位がわかりやすいようにしたい。

どうやるの?

サンプルプロジェクトがあった方が解りやすそうだったのでババっと書いてみました。 github.com 今回のイメージは下記です。

  • index.html(画面)
  • views/index.js (index.htmlで呼ばれるエントリポイントとしてのJavaScript)
  • components/*.js (画面から呼ばれる部品達)

モジュール化

この一言でほぼ答えになるのですが、ちゃんとモジュール化をしましょうという話です。モジュール化と名前空間の適用がこの課題へのコスパの高い対応ではないでしょうか。自分の場合には昔々に名前空間を作れるライブラリを書いているので、これをよく使います。このサンプルでは、viewscomponents配下のJS達がモジュール化されています。

// ネームスペースを指定して、外に露出させない。
// 以下のように書くと、 MYAPP.COMPONENTS.Popupper が使えるようになる。
LIMO.namespace('MYAPP.COMPONENTS')(function(ns){

  function Popupper(el){
    this.$el = $(el)
  }

  Popupper.prototype.setup = function() {
    // 簡単のためalertだけにしているが、ボタンを押したら起きる動作を
    // ここでまとめるようなイメージ。
    this.$el.on('click', function(){
      alert('test');
      return false;
    });
  }

  // ns に付けたものはネームスペースに結合されて公開される
  ns.Popupper = Popupper;
});

エントリポイントを1つにする

一つの画面についてイベントハンドラを付けたりするような、最初の「仕掛け」をするコードの入り口を一つにします*2。index.htmlには下記の1行が書かれています。入り口は必ずこのような簡単な関数一つです。名前空間はプロジェクトで適切に決めれば良いと思いますが、Railsだと、 MYAPP.VIEWS.[Controller名].initShow() などのようにして、 initNew()initEdit() を同じ内容にすると便利だったりするかもしれません。

<script>MYAPP.VIEWS.INDEX.init()</script>

エントリポイントから各コンポーネントを呼ぶ

基本的には上記のエントリポイントの関数内には $.ready が書かれるイメージです。そして、その関数の中から各コンポーネントが呼ばれます。GitHubに載せたサンプルではもう少し複雑な内容も書いてみました。下記だと簡単すぎて恩恵がよく見えないかもしれませんので。

イメージとして複雑な処理はコンポーネントの中に封じ込めて、エントリポイントはなるべくそれを使うだけにするような形です。また、コンポーネントがDOMツリーへの情報を必要とする場合には、ルートのCSSセレクタを設定するなどします(動きが複雑だと複数のセレクタを設定するかもしれませんね)。

LIMO.namespace('MYAPP.VIEWS.INDEX')(function(ns){
  ns.init = function(){
    $(function(){
      // クラスっぽくしているが、簡単ならもちろん関数でも良い。
      // 大抵はコンポーネントのルートになるCSSセレクタを指定する。
      var popupper = new MYAPP.COMPONENTS.Popupper('.mytrigger');
      popupper.setup();
    });
  }
});

おしまいに

「各画面にちょっとした演出のJS書きたいんだけどなぁ」くらいならこの程度がわかっていると簡単ですよってことで。ガッツリやりこむのが見えている場合には今は色々便利な道具があると思うのでちゃんとやってくだされ。

PR

TECH DRIVE協賛企業のサークルアラウンド株式会社では、プログラマーの成長を加速させるためのトレーニングを行なっています。フロントエンド/バックエンド問わず各種バリエーションがございますので、ご興味がある方は是非以下のリンクより詳細をご覧ください。

JavaScript Climbing

JavaScriptに特化したトレーニング「JavaScript Climbing」を行なっています。
this、クロージャ、Class等、中〜大規模のフロントエンドの開発に臨にあたり、必須となるスキル習得を現役のWEBエンジニアが徹底してサポートします。
2週間の無料体験期間がございますので、ご興味がある方は是非以下のリンクより詳細をご覧ください。

circlearound.co.jp

個別トレーニング

短期間でぐっと成長したい方は弊社主催の個別トレーニングがおすすめです。 トレーニング内容は、受講者の方の課題/要望をお伺いした上で、フルオーダメイドで作成させていただきます。 詳細は以下のリンクよりご確認ください。(応募者多数の場合には時間を別途ご用意する予定です)。

WEBプログラミング個別トレーニング

*1:Rails使っている人ばかりだったので、ちょいちょいRailsの話ありますけど興味ない人は読み飛ばしてくだされ

*2:実は概念化されていれば一つの関数にまとめたりする必要も無いですが、簡単に強制するなら一つの関数ですね

TECH DRIVEについて

TECH DRIVEは「技術者の成長を加速させる」をキーワードに都内で活動をしているコミュニティです。
TwitterやFacebookにて技術ネタやイベント情報の発信を行っていますので、ご興味があれば、いいねやフォローをお願いいたします。