Skip to content
uupaa edited this page Jan 1, 2015 · 35 revisions

このエントリでは、WebModule を使ったモジュール開発のワークフローについて説明します。 ( English Version )

WebModule を使ったモジュール開発のワークフローについて

例として ~/workflow ディレクトリに GitHub 上で作成した MyExample.js リポジトリをクローンし、MyExample.js モジュールを作成する流れを説明します。

  1. WebModule が必要とするソフトウェアについて:

    • Mac OS X 10.9.5 以上
    • Homebrew
    • Node.js の最新版
    • Java runtime (Closure compiler の動作に必要です)
    • Google Chrome Browser
    • iOS Simulator (Xcode にバンドルされています)
  2. インストール手順:

    $ ruby -e "$(curl -fsSL https://raw.github.com/Homebrew/homebrew/go/install)"
    $ brew -v
    > Homebrew 0.9.5
    
    $ brew install node
    $ npm -v
    > 2.0.2
    • npm の検索パス(NODE_PATH)を シェルのリソースファイル(.zshrcなど)に追加します
    $ echo 'export NODE_PATH="/usr/local/lib/node_modules"' >> ${HOME}/.zshrc
    $ source ${HOME}/.zshrc
    $ env | grep NODE_PATH
    > NODE_PATH=/usr/local/lib/node_modules
    $ npm install -g plato
    $ npm install -g jshint
    $ npm install -g uupaa.compile.js
  3. WebModule を ~/workspace にクローンします:

    $ mkdir ~/workspace
    $ cd workspace
    $ git clone git@github.com:uupaa/WebModule.git
  4. MyExample.js リポジトリを GitHub に作成します:

    • Creating a new repository を参考にしてください

      • (1) ユーザアカウントを選択します
      • (2) WebModule 名を入力します
      • (3) Description を入力します(省略可能です)
      • (4) Initialize this repository with a README をチェックし、ライセンスを選択します。お勧めは MIT ライセンスです
      • (5) ボタンをクリックしてリポジトリを作成します
      Owner                    Repository name
      +-------------------+   +-------------------+
      | your account  (1) | / | MyExample.js  (2) |
      +-------------------+   +-------------------+
      
      Description (optional)
      +------------------------------------------------+
      | my first webmodule  (3)                        |
      +------------------------------------------------+
      
      [x] Public
      
      [x] Initialize this repository with a README  (4)
      +----------------------+  |  +---------------------------------+
      |                      |  |  | Add a license: MIT License  (4) |
      +----------------------+  |  +---------------------------------+
      
      +------------------------+
      | Create repository  (5) |
      +------------------------+
      
  5. 作成した WebModule (MyExample.js) リポジトリを ~/workspace にクローンします:

    • クローン後に、MyExample.js ディレクトリに移動してください
    > ~/workspace
    
    $ git clone git@github.com:YOUR-ACCOUNT/MyExample.js.git
    $ cd MyExample.js
  6. WebModule をセットアップします:

    $ pwd
    > ~/workspace/MyExample.js
    
    $ node ../WebModule/run/setup
    >   - repositoryFullName: MyExample.js
    >   - repositoryName:     MyExample
    >   - copy source dir:    ~/workspace/WebModule/
    >   - copy target dir:    ~/workspace/MyExample.js/
    >
    >   clone:     ~/workspace/MyExample.js/lint/plato/README.md
    >   clone:     ~/workspace/MyExample.js/release/README.md
    >   clone:     ~/workspace/MyExample.js/.gitignore
    >   clone:     ~/workspace/MyExample.js/.jshintrc
    >   clone:     ~/workspace/MyExample.js/.npmignore
    >   clone:     ~/workspace/MyExample.js/.travis.yml
    >   clone:     ~/workspace/MyExample.js/index.js
    >   clone:     ~/workspace/MyExample.js/lib/MyExample.js
    >   clone:     ~/workspace/MyExample.js/test/testcase.js
    >   clone:     ~/workspace/MyExample.js/package.json
    >   exists:    ~/workspace/MyExample.js/README.md - overwrite it? (y/n): y
    >   overwrite: ~/workspace/MyExample.js/README.md
    >
    >   done.
    >
    >   Available next actions,
    >   `$ npm run`        # list up npm run-script
    >   `$ npm start`      # start local httpd server
    >   `$ npm run sync`   # sync scripts, install/update node modules, create test pages and minify
  7. WebModule/MODULE_package.json と MyExample.js/package.json を同期させます:

    $ npm run sync
  8. 必要な外部モジュールがある場合は、package.json に追加します:

    • $npm run build のコンパイル対象とする WebModule は dependencies 追加します
    • テストで必要となるモジュールは devDependencies に追加します
    • package.json を変更した場合は、$ npm update; npm run page コマンドを実行し、変更内容を適用してください
  9. Edit tags

    • package.json の keywords に検索用のタグを追加できます
    • ユーザ名 と WebModule は検索で使います。消さないでください
    {
      "keywords": ["GITHUB_USER_NAME", "WebModule", "Unstable"],
    }

Directory entry

~/workspace/MyExample.js 以下のディレクトリ構成です

$ pwd
> ~/workspace/MyExample.js

$ tree
.
└── MyExample.js
    ├── bin/                     <- `$ node ../WebModule/run/setup --bin` コマンドで作成されるディレクトリです
    ├── lib/
    │  └── MyExample.js          <- モジュールのソースコードです
    ├── lint/
    │  └── plato/                <- npm run socre コマンドが生成するファイルを格納するディレクトリです
    ├── release/                 <- npm run minify や npm run build コマンドで生成したファイルを格納するディレクトリです
    │  └── MyExample.min.js      <- Minify した状態のソースコードです
    ├── test/                    <- npm test で実行するファイルを格納するディレクトリです
    │  ├── index.html            <- npm run page コマンドが生成するテストページです。Browser と WebWorkers のテストで使用します
    │  ├── node.js               <- npm run page コマンドが生成するテスト用のJavaScriptです。Node.js のテストで使用します
    │  ├── worker.js             <- npm run page コマンドが生成するテスト用のJavaScriptです。WebWorkers のテストで使用します
    │  └── testcase.js           <- テストロジックを記述するファイルです
    ├── .gitignore               <- git add, git push コマンドが参照する設定ファイルです
    ├── .npmignore               <- npm publish コマンドが参照する設定ファイルです
    ├── .jshintrc                <- npm run hint コマンドが参照する設定ファイルです
    ├── .travis.yml              <- Travis-Cl の設定ファイルです
    ├── index.js                 <- Node.js 用のエントリポイントです。require("MyExample.js") で読み込まれるファイルになります
    ├── package.json             <- npm の設定ファイルです
    ├── LICENSE
    └── README.md

Implement module

以下はモジュール設計の目安です

  • テストが可能なように実装してください。テストがされていないモジュールは使用しないでください
  • 1 モジュールに 1 クラスが基本ですが、 lib/Aaa.js, lib/Bbb.js のように複数のクラスを実装し Export することも可能です
  • 1 クラスは 200〜400行程度の適切なボリュームで実装してください
  • 1 クラスにメソッドを10個以上持たせないでください。複雑すぎます
  • repositories を参考にしてください

Add test code

テストコードは ~/workspace/MyExample.js/test/testcase.js に記述します。

  • テストは WebModule/lib/Test.js と WebModule/lib/Task.js 使用しています

  • テストコードの書き方は、 repositories などを参考にしてください

  • テストの設定を変更するには、testcase.js の new Test("MyExample", param) を修正してください

    var test = new Test("MyExample", {
            disable:    false,  // テストを無効化します
            browser:    true,   // Browser でテストします
            worker:     true,   // WebWorkers でテストします
            node:       true,   // Node.js でテストします
            button:     true,   // Browser のページに再テスト用のボタンを追加します
            both:       true,   // MyExample と MyExample_ の両方をテストします
                                // see https://github.com/uupaa/WebModule/wiki/SecondaryModulePattern
        }).add([
            testMyExample_value,
            testMyExample_isNumber,
            testMyExample_isInteger,
        ]);
    
    test.run().clone();
    

Change build target

package.json の webmodule 以下を修正することで、ビルド対象の変更や、一緒にビルドするモジュールを指定できます。


Improve cycle

コード修正後は、以下のコマンドによるビルドとテストを行ってください。

$ vi lib/MyExample.js   # edit

$ npm test              # tests
$ npm run sim           # test on iOS Simulator

$ npm run min           # minify
$ npm run build         # release build

$ npm run hint          # run jshint
$ npm run score         # run coverage tools

Build

npm run minnpm run build コマンドを実行すると release/MyExample.min.*.js を生成します。
* の部分には Browser なら b が、Worker なら w が、Node なら n が入ります。

  • ビルドに失敗した場合は、中間ファイル(release/.Minify.tmp.js) を確認してください
  "scripts": {
    "min":          "node ../WebModule/run/minify.js --verbose --strict --keep --pretty",
    "build":        "node ../WebModule/run/minify.js --verbose --strict --module"
  }

Do test

npm test コマンドでテストが走ります。

最初に test/node.js による Node.js のテストが走り、
次に test/index.htmltest/worker.js によるブラウザのテストが始まります。

  • テストは lib/MyExample.js に対して node → browser → worker の順番で行い、release/MyExample.min.*.js に対しても同様にテストを行います
  • テスト成功でブラウザの画面が緑に、失敗で赤くなります
  • Closure Compiler による MyExample.min.*.js のコンパイルに失敗している場合も赤くなります
  • Closure Compiler の ADVANCED_OPTIMIZATIONS MODE で、重要な識別子やプロパティがリネームされている可能性があります
    • MyExample.min.*.js を DevTools 上で開き、Minify されているコードを展開({ }をクリック)します
  • リネームされたくない名前やプロパティは global.MyExample.hoge = 1; ではなく global["MyExample"]["hoge"] = 1; として保護してください。

Coverage

モジュールを作成後に、モジュールの静的解析を行い、コードの品質を明確にします。

  • npm run lint コマンドを実行すると、JSHint によるテストが行われます。
  • npm run score コマンドを実行すると、Plato による静的解析が行われ、スコアをブラウザに表示します。

  • lint erros をゼロにし、Average Maintainability は65点以上を目指して下さい。60点以下は赤点です
  • JSHint のチェックを緩和するには、 .jshintrc を修正してください
  • 問題が発覚した場合は、コードを修正する → npm run hintnpm run minnpm test を繰り返し、動作をチェックしつつ修正します

Commit and publish

コードが公開可能なクオリティに達した事を確認できたら、GitHub への push と npm publish で世界にモジュールを公開しましょう。

  • Update patch version.

    • npm publish 後に ./lib/MyExample.js を修正した場合は、npm run patch コマンドで package.json のパッチバージョンをインクリメントしてください
      • version は、major.minor.patch バージョン(Semver)で構成されています。
      • API の動作変更など、下位互換性がなくなる修正の場合は、major を +1 します
      • bugfix など軽微な修正の場合は、patch を +1 します。
      • Semver については The semantic versioner for npm を参考にしてください
      • package.json の version を修正せずに、再度 npm publish するとエラーになります。
    $ npm run patch         # update patch version
    > update patch version. 0.0.0 -> 0.0.1
  • Commit と publish は以下のようにします

$ git add .
$ git status

> # On branch master
> # Changes to be committed:
> #   (use "git reset HEAD <file>..." to unstage)
> #
> #    new file:   .gitignore
> #    new file:   .jshintrc
> #    new file:   .npmignore
> #    new file:   LICENSE
> #    modified:   README.md
> #    new file:   index.js
> #    new file:   lib/MyExample.js
> #    new file:   package.json
> #    new file:   test/index.html
> #    new file:   test/node.js
> #    new file:   test/worker.js
> #    new file:   test/testcase.js

$ git commit -m "first commit"
$ git push
$ npm publish

Write Document

モジュールの作成が終わったら、GitHub/Wiki に Markdown でドキュメントを記述します。

open https://github.com/uupaa/MyExample.js/wiki/MyExample コマンドを実行するか、
open test/index.html でブラウザを開き DevTools のコンソールで MyExample.help ENTER とタイプします。

$ open https://github.com/uupaa/MyExample.js/wiki/MyExample

表示されたリンクから、 Reference: のリンクをクリックすると、GitHub の MyExample.js の wiki ページが生成されます。

新しく生成された wikiページに、API の説明を記述してください。

    # MyExample.js

    MyExample.js は、WebModule の機能を説明するためのダミーライブラリです。

    ## MyExample

    new MyExample(value:Number) は、MyExample クラスのインスタンスを生成します。  
    value には数値を指定します。

    ```js
    function MyExample(value) { // @arg Number: the valud.
        this._value = value;
    }
    ```


    ## MyExample.prototype.value

    MyExample#value():Number は、[MyExample](#MyExample) で渡された value を返します。

    ```js
    function MyExample_value() { // @ret Number:
        return this._value;
    }
    ```

    ## MyExample.prototype.isNumber

    MyExample#isNumber():Boolean は、[MyExample](#MyExample) で渡された value が Number 型なら true を返します。

    ```js
    function MyExample_isNumber() { // @ret Boolean:
        return typeof this._value === "number";
    }
    ```

    ## MyExample.prototype.isInteger

    MyExample#isInteger():Boolean は、[MyExample](#MyExample) で渡された value が Number 型で端数を持たない場合に true を返します。

    ```js
    function MyExample_isInteger() { // @ret Boolean:
        return typeof this._value === "number" &&
               Math.floor(this._value) === this._value;
    }
    ```

Clone this wiki locally