エンターテイメント!!

遊戯王好きのJavaエンジニアのブログ。バーニングソウルを会得する特訓中。

browserifyの動きについての学習と依存関係の分断で悩んだことのメモ

きっかけ

brosifyの動きがよく分からなかったので、学習した内容を晒す。

browsify

browsifyとは

分かりやすそうなサイトから抜粋

このツールはNode.jsのコアモジュールやnpmのモジュールをブラウザでも利用できるようにするというのが元々の目的でしたが、モジュール間の依存解決やファイルの結合を行うためのビルドツールとして使われることが多くなってきているようです。

賢く使うBrowserify - Browserifyとは | CodeGrid

仕組み

簡単にいうと、reqwireから使うファイルをたどって言ってくれるってことですかね?

現場でも使っているみたいだけど、ここらへんの仕組みが微妙に分かってない気がする。。。
なので、実験

実験

準備

自分、JS使えないので、Typescriptで実験。
準備は下記の通り。
やるときは、任意のフォルダ内でやることを推奨。

# プロジェクト初期化
npm init -y

# globalにtypescriptを入れる
npm install -g typescript

# ビルドに必要なモジュールを入れる
npm install gulp --save-dev
npm install browserify --save-dev
npm install vinyl-source-stream --save-dev
npm install tsify --save-dev

# typescript 初期化
tsc --init

実験コード

とりあえず、下記のようなクラスを作った。
app.tsが、TestImportA.tsだけを使っている。
TestImportB.ts は、作っただけでどこからも参照していない。

期待値としては、ビルドした結果のファイルにTestImportB.tsの内容が入っていないで欲しい。

実コード
ディレクトリ構成

まずは、ディレクトリ構成から。

|--apps
|  |--js
|  |  |--app.js
|--gulpfile.js
|--package.json
|--src
|  |--ts
|  |  |--app.ts
|  |  |--TestImportA.ts
|  |  |--TestImportB.ts
|--tsconfig.json
各ファイルの実装
# app.ts
"use strict";

import TestImportA from './TestImportA';

new TestImportA().execute();
# TestImportA.ts
export default class TestImportA {
  execute() {
    console.log('call A');
  }
}
# TestImportB.ts
export default class TestImportB {
  execute() {
    console.log('call B');
  }
}
結果確認のためのビルドプロセス作成

gulpでファイル出力のタスクを書く。

// gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var source = require('vinyl-source-stream');

gulp.task('build', function () {
  return browserify({
      entries: './src/ts/app.ts'
    }).plugin('tsify')
    .bundle()
    .pipe(source('app.js'))
    .pipe(gulp.dest('./apps/js'));
});

apps/js/app.js にビルドした内容が吐かれるので、そいつを確認すればOK

結果確認
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var TestImportA = /** @class */ (function () {
    function TestImportA() {
    }
    TestImportA.prototype.execute = function () {
        console.log('call A');
    };
    return TestImportA;
}());
exports.default = TestImportA;

},{}],2:[function(require,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var TestImportA_1 = require("./TestImportA");
new TestImportA_1.default().execute();

},{"./TestImportA":1}]},{},[2]);

うむ、ちゃんとTestImportB.tsの内容が含まれていない。

なにが嬉しいのか

エントリーポイントに依存を集中させれば、切り替えができて、かつ必要なクラスのみが入ったファイルが生成できる点が嬉しいのだろうと思う。
例えば、TestImportB.tsだけを使いたい場合は、app.ts とは別のエントリーポイントのtsファイルを作成して、ビルドタスクを書けば、資産の流用ができると思う。
もちろん、使われる側が、ちゃんと依存がエントリーポイントに寄るように作ってある必要があるけどね。。。

これの考え方を覚えるのにだいぶ苦労した。。。

学んだこと

依存はエントリーポイントに向けて集める。そうすれば、あるファイルを切り替えるだけで資産を流用することができる。

参考サイト

gulp + browserify + tsifyを利用してTypeScriptコンパイル環境を作る - $shibayu36->blog;

賢く使うBrowserify - Browserifyとは | CodeGrid

賢く使うBrowserify - Browserifyとは | CodeGrid