Workflow_ja
このエントリでは、開発環境の構築と、お試しモジュール(MyExample.js)を作成し、モジュールを npm に公開する方法について説明します。
-
package.json を編集します
- 他のモジュールを使いたい場合は依存関係を追記します
-
実装とテストを行います
- lib/MyExample.js を実装します
-
npm run lint
で MyExample.js/lib 以下の js ファイルの Syntax を検査できます - test/testcase.js にテストコードを記述しユニットテストを行います
-
十分にテストができたらコードの品質を測定しましょう
-
npm run score
でコードの複雑度や品質をチェックするツールが起動し結果がブラウザに表示されます
-
-
README.md を更新します
-
検索用のキーワード を package.json に埋め込みます。
-
作成したモジュールを GitHub と npm に登録します
-
以下のエントリも参照してください
npm t
, npm run lint
や npm run score
で十分に品質を確保できたら、いよいよ世界に向けて公開です。
公開は簡単です、いつもの git コマンドと npm publish
を実行するだけです。
$ git add .
$ git commit -m "first commit"
$ git push
$ npm publish
公開が終わったらドキュメントを書きましょう。
(むしろ最初にドキュメントを書いてからコードを書いても良いでしょう)
ブラウザで https://github.com/ユーザ名/MyExample.js/wiki
を開き、markdown で Spec や API spec, 動作例を記述してください。
お疲れ様でした! 😆 🍻
~/workspace/MyExample.js 以下のディレクトリ構成です
$ cd
> ~/workspace/MyExample.js
$ tree
.
└── MyExample.js
├── bin/ <- `$ node ../WebModule/run/setup --bin` コマンドで作成されるディレクトリです
├── lib/
│ ├── WebModuleGlobal.js <- GLOBAL, IN_XXXX といったグローバル変数や assert関数($valid や $keys など)が定義されています
│ └── MyExample.js <- モジュールのソースコードです
├── lint/
│ └── plato/ <- npm run socre コマンドが生成するファイルを格納するディレクトリです
├── release/ <- npm run min や npm run build コマンドで生成したファイルを格納するディレクトリです
│ ├── MyExample.b.min.js <- browser用にMinify したコードです
│ ├── MyExample.w.min.js <- worker用にMinify したコードです
│ ├── MyExample.n.min.js <- node用にMinify したコードです
│ └── MyExample.nw.min.js <- node-webkit用にMinify したコードです
├── test/ <- npm test で実行するファイルを格納するディレクトリです
│ ├── template/ <- test/*.js や test/*.html を生成する元となるテンプレートを格納するディレクトリです
│ │ ├── browser.html <- test/index.html の元となるテンプレートファイルです
│ │ ├── node.js <- test/node.js の元となるテンプレートファイルです
│ │ ├── nw.html <- test/nw.html の元となるテンプレートファイルです
│ │ ├── nw.package.json <- test/package.json の元となるテンプレートファイルです
│ │ └── worker.js <- test/worker.js を生成する元となるテンプレートを格納するディレクトリです
│ ├── index.html <- npm run page コマンドが生成するテストページです。Browser と WebWorkers のテストで使用します
│ ├── node.js <- npm run page コマンドが生成するテスト用のJavaScriptです。Node.js のテストで使用します
│ ├── worker.js <- npm run page コマンドが生成するテスト用のJavaScriptです。WebWorkers のテストで使用します
│ ├── nw.html <- npm run page コマンドが生成するテストページです。nw test による node-webkit のテストで使用します
│ ├── package.json <- npm run page コマンドが生成するテストページです。node-webkit がこのファイルを参照します
│ ├── wmtools.js <- テストで必要となる機能を集約したファイルです。
│ │ Reflection.js, Console.js, Valid.js, Help.js, Task.js, Test.js が同梱されています。
│ └── testcase.js <- テストケースを記述するファイルです
├── .eslintignore <- npm run hint コマンド用の設定ファイルです
├── .eslintrc <- npm run hint コマンド用の設定ファイルです
├── .gitignore <- gitコマンド用の設定ファイルです
├── .npmignore <- npmコマンド用の設定ファイルです
├── .travis.yml <- Travis-Cl の設定ファイルです
├── index.js <- Node.js 用のエントリポイントです。require("MyExample.js") で読み込まれるファイルになります
├── package.json <- npm の設定ファイルです
├── LICENSE
└── README.md
WebModule では、以下のようなモジュールの設計と実装の目安があります。
必ずしもこれらを守る必要はありませんが、善処してください。
- テストが可能なように実装してください。テストがされていないモジュールは使用しないでください
- 1 つのモジュールに 1 つのクラスが基本です。
- Codec.jsが行っているように lib/Class1.js, lib/Class2.js のように複数のクラスを実装し Export することもできます
- 1 つのクラスは 200〜400行程度の適切なボリュームで実装してください
- 1 つのクラスにメソッドを10個以上持たせないでください。恐らく複雑すぎます、分割してください
- [WebModuleList][] にあるモジュールも参考にしてください
//// 時間切れここから続行
package.json の webmodule プロパティ以下を修正することで、ビルドするソースコードの追加や設定の変更が可能です。
コード( lib/MyExample.js )を修正したら、品質の確認とテストを行います。
$ npm start
で簡易httpサーバを起動し、その後に npm run test
とタイプすることでビルドとテストが実行されます。
テスト用のページは http://localhost:8000/MyExample.js/test/index.html でアクセスできます
$ npm start # 簡易httpサーバをポート8000で起動します
$ npm stop # 簡易httpサーバを終了します
$ npm test # node.js + browser + worker でテストを行います
$ npm run browser # ブラウザで lib/MyExample.js をテストします
$ npm run node # node.js で lib/MyExample.js をテストします
$ npm run noded # --debug-brk オプション付きで node.js で lib/MyExample.js をテストします
$ npm run sim # iOS Simulator を起動し Simulator 上で browser + worker のテストを行います
$ npm run simx # iOS Simulator を終了します
$ nw test # node-webkit で lib/MyExample.js をテストを行います
$ npm run test # npm run min を実行後に npm run node, npm run browser を実行します
$ npm run min # lib/MyExample.js を minify し、release/MyExample.*.min.js を作成します。
$ npm run build # lib/MyExample.js と dependencies に記述された依存モジュールのソースコードを一緒にビルドし release/MyExample.*.min.js を作成します
$ npm run hint # jshint lib/*.js を実行し、ソースコードを静的に検査します
$ npm run score # plato によるカバレッジを実施し、スコアをブラウザに表示します。
npm run min
や npm run build
コマンドを実行すると release/MyExample.*.min.js
を生成します。
*
の部分には Browser なら b が、Worker なら w が、Node なら n が入ります。
ビルドに失敗した場合は、中間ファイル(release/.Minify.tmp.js
) を確認してください
package.json に修正を加える事で、ビルドセッティングを変更できます。
デフォルトの設定は以下のようになっています。minify.js に指定可能な引数を参照してください。
"scripts": {
"min": "node ../WebModule/run/minify.js --verbose --strict --keep --pretty",
"build": "node ../WebModule/run/minify.js --verbose --strict --module"
}
npm test
コマンドでテストが走ります。テスト対象は lib/MyExample.js と release/MyExample.*.min.js です。
最初に test/node.js
による Node.js のテストが走り、
次に test/index.html
と test/worker.js
によるブラウザ上でのテストが始まります。
- テストは最初
lib/MyExample.js
に対して node → browser → worker の順番で行い、次にrelease/MyExample.*.min.js
に対して行います - テスト成功でブラウザの画面が緑に、失敗で赤くなります
-
Closure Compiler による
MyExample.*.min.js
のコンパイルに失敗している場合も赤くなります - Closure Compiler の ADVANCED_OPTIMIZATIONS MODE に対応したコードを記述していない場合もコンパイルに失敗します。
-
function SomeAPI() { return { foo: 123 }; }
のように記述している場合は、識別子 foo がコンパイラによりリネームされ解決できなくなっている可能性があります - 解決するには、minify されているコードを展開し、コンパイル前のコードと照らし合わせを行います
-
MyExample.*.min.js
を DevTools 上で開き、Minify されているコードを展開({ }
をクリック)します
-
- リネームされたくない名前やプロパティは
global.MyExample.hoge = 1;
ではなくglobal["MyExample"]["hoge"] = 1;
のように保護してください。
-
モジュールの作成がひと通り終わったら、モジュールの静的解析を行いコードの品質を明確にします。
-
npm run lint
コマンドを実行すると、JSHint によるテストが行われます。 -
npm run score
コマンドを実行すると、Plato による静的解析が行われ、スコアをブラウザに表示します。
- lint erros をゼロにし、Average Maintainability は65点以上を目指して下さい。60点以下は赤点です
- JSHint のチェックを緩和するには、 MyExample.js/.jshintrc を修正してください
- 問題が発覚した場合は、コードを修正 →
npm run hint
→npm test
を繰り返し、動作をチェックしつつ修正していきます
モジュールの作成と品質向上作業が終わったら、MyExample.js の README.md を修正します。
コードが公開可能なクオリティに達した事を確認できたら、GitHub への push と npm publish で世界にモジュールを公開しましょう。
-
npm run patch
を行うと、package.json に記述されている version: "0.0.x" の x が 1 上がります。- このような version x.y.z のような3桁のバージョン表記は Semver と呼ばれています。
- x がメジャーバージョン, y がマイナーバージョン, z がパッチバージョンです。
- 大幅で破壊的な変更を行い、互換性がなくなる修正をしてしまった場合は、x を +1 します。
- それほどインパクトがない機能の追加や修正を行った場合は場合は、y を +1 します。
- バグフィックスなど軽微な修正を行った場合は、z を +1 します。
- package.json の version を上げずに npm publish を繰り返すと publish 時にエラーになります。
$ npm run patch # update patch version > update patch version. 0.0.0 -> 0.0.1
-
git へのコミットと npm への 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
npm publish が終わったら 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;
}
```
ドキュメントの記述が面倒だな… と感じたら、こちらのエントリを御覧ください。