LoginSignup
20
20

More than 5 years have passed since last update.

Browserifyの共通モジュール部分だけ分離したいならfactor-bundleが便利

Last updated at Posted at 2015-08-30

Brwoserifyを使うにあたって、普通にbuildしていると1ファイル1ファイルがモリモリ肥大化してしまう。であれば共通部分の切り出しだ!
というところでfactor-bundleというのがあるのだけど日本語記事とか無いのでサンプルを記載しつつまとめたい。

factor-bundleとは?

browserifyの対象ファイルを解析して 共通部分になるmoduleだけを自動的に切り出してくれる pluginである。

立ち位置としてはbrowserifyのpluginである。
また、browserify作者であるsubstack氏によるプロジェクトであるので、挙動してそんなに不安を感じる必要もないだろう。
コードも実質index.js一つなのでそう複雑なことをやっているわけでもない。

使い方

公式にはコマンドラインを利用したこんなサンプルが添えられている

browserify x.js y.js -p [ factor-bundle -o bundle/x.js -o bundle/y.js ] \
  -o bundle/common.js

x、yというファイルをentryにして、それ以外がcommonに流れていく。
どれが共通になるのかは自動決定される。

gulpによるサンプル

私感だが、分割したい要件って中規模ぐらいなはずで、gulpの一つぐらい必要になりそうだなーと思った。
が、gulp使ったサンプルがなかったので作ってみる。
コマンドラインでの詳しい使い方は本家READMEなどを参照されたい。

npm install

必要なパッケージをどしどしと入れる。
二行目のものたちは、今回に必須というわけでもないけどあると便利系なのであとはお好みで。

$ npm i -D gulp browserify babelify factor-bundle vinyl-source-stream
$ npm i -D mkdirp glob del

ディレクトリ構成

だいたいこんな感じ。

.
├── output
│   ├── client
│   └── entry
├── src
│   ├── entry
│   └── lib
└── vendor

gulpfile

要点を小うるさく注釈していく。

gulpfile.js
var gulp = require('gulp')
var path = require("path")
var browserify = require('browserify')
var babelify = require('babelify')
var source = require('vinyl-source-stream')
var glob = require("glob")
var del = require("del")
var mkdirp = require("mkdirp")
var factor = require('factor-bundle')

var dest = './output/'

gulp.task('clean', function() {
  del(dest)
})

gulp.task('browserify', function() {
  // entry対象が結構あるような状態を想定
  var entries = "./src/entry/**/*"

  // 出力先をこのあたりに・・・
  var outputDir = "./output/entry"

  // factor-bundleの出力先を決める。
  // ちゃんとディレクトリ出力先を変更しておかないと元ファイル書き換えられちゃうので注意!
  var files = glob.sync(entries, {nodir: true})
  var outputs = files.map(function(file){
    return file.replace("./src/entry", outputDir)
  })

  // factor-bundleの出力先のディレクトリが無かったりすると面倒見てくれないので作っとく。
  mkdirp.sync(outputDir)

  // browserify部分開始
  browserify({
    entries: files,
    extensions: ['js', 'jsx'],
  })
  // transformしたいならこんな具合。最近鉄板なのでbabelっとく。
  // babelのtransformに際して、何らかの理由でnpm入りしないなーみたいなのがあれば対象外にしておく。
  // ignoreオプションではなくonlyオプションを使うのもよい
  .transform(babelify.configure({
    ignore: /vendor/
  }))
  // factor-bundleの登場。先ほど用意したoutputを追加
  .plugin(factor, {
    output: outputs
  })
  // 共通部分を出力してやる。
  .bundle()
  .pipe(source("common.js")) 
  .pipe(gulp.dest(path.join(dest, "client")))
})

gulp.task('watch', function() {
  gulp.watch('src/**/*', ['browserify'])
})

gulp.task('default', ['browserify', 'watch'])

これでoutputにはsrc/entryにあったファイルが変換されたものと、common.jsが出力される。

あとはこんな感じで呼び出せば完成

<script type="text/javascript" src="./output/client/common.js"></script>
<script type="text/javascript" src="./output/entry/foo.js"></script>

感想とか

  • 共通部分を作りたい要件あるならこのpluginはおすすめ。
    • requireとかexternal駆使してやるの、最初やってみたけど割りと辛かった。
    • 「このプロジェクトはjqueryぐらいしか共通部分無い」とかだったらrequireとexternalぐらいでも十分だろうとは思う
    • が、たとえば「コアライブラリ」「お手製lib部分」「お手製entry部分」ぐらいな粒度で分割しだすとちょっともう辛い。factor-bundle使う方が圧倒的に良い。
    • 逆に大規模開発になってきて更新の度に本番環境への負荷がヤバイ、とかなったら再検討してもよいだろうと思う。
      • common部分が作りによってゴリゴリ変わっちゃうので、キャッシュの仕組みによってはcommon部分がキャッシュ効かない〜というのはありそう。
      • あんまり考えたくない。
  • ちなみにpartition-bundleというのも紹介されていたけどよくわかんなかった。

参考文献

20
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
20