あらすじ
先日 react-paginators
という React components な module を publish しました。
その時に色々調べた事があるので備忘録として残します。
作成手順
create-react-app
と storybook
を使ってプロジェクトの雛形を作成します。create-react-app
を使うと webpack の事を考えなくて良いのでとても楽でよいです。
create-react-app react-xxxxx && cd $_ getstorybook
必要なディレクトリとファイルを作成します
mkdir test touch .envrc .babelrc .npmignore .travis.yml CHANGELOG.md test/xxxxx.test.js npm install --saave react react-dom npm install --save-dev babel babel-cli babel-preset-es2015 babel-preset-react babel-preset-stage-0 npm install --save-dev assert eslint eslint-plugin-react rimraf npm install --save-dev in-publish safe-publish-latest
create CHANGELOG.md
# Change Log ## v0.1.0 - Initial commit
そういえば $_
って何ですか?と聞かれる事があったのですがこれは前回使用したコマンドの最後の引数が格納される変数です。
上記のコマンドだと create-react-app react-xxxxx
の react-xxxxx
となります。
npm run test の環境を整える
雛形ができたら npm test
の環境を整えます
create test/xxxxx.test.js
import assert from 'assert' describe('XXX', function() { it('should ...', () => { assert.ok(true) }) })
動作確認します。雛形として生成された src/App.test.js と test/xxxxx.test.js が実行されるのを確認します。
ちなみに環境変数 CI=true
を忘れると launch mode で起動します
CI=true npm test > react-xxxxx@0.1.0 test /Users/okamuuu/react-xxxxx > react-scripts test --env=jsdom PASS src/App.test.js PASS test/xxxxx.test.js Test Suites: 2 passed, 2 total Tests: 2 passed, 2 total Snapshots: 0 total Time: 1.167s Ran all test suites.
src/App.test.js は不要となった時点で適宜 remove してください
npm run version の環境を整える
check-changelog と check-only-changelog-changed
airbnb が公開している react-dates
の真似をします。
https://github.com/airbnb/react-dates
彼らは version コマンドを実行する時は CHANGELOG.md
以外の差分が無い状態でしか実行できないようにしています。
npm-scripts に check-changelog
と check-only-changelog-changed
を追加します。
edit package.json:
--- a/package.json +++ b/package.json "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test --env=jsdom", - "eject": "react-scripts eject" + "eject": "react-scripts eject", + "check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)", + "check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0" } }
以下のような使い方を想定しいています。
CI=true npm run test && npm run check-changelog && npm run check-only-changelog-changed
上記のコマンドは以下の状態でないとエラーが発生するので version up の際に一貫性が生まれます。
git status modified: CHANGELOG.md
postversion, version, preversion を準備
npm version をそのまま使うと Git working directory not clean.
と怒られてしまうので --no-git-tag-version
オプションをつけて実行します。
package.json に npm run version:patch
, npm run version:minor
, npm run version:major
を用意します。
preversion
に先ほど準備した test の実行と CHNAGELOG.md のチェックを行います。
postversion
で package.json(verson が変更されている) と CHANGELOG.md をcommit します。コミットも自動的に行います。git tag でタグを切り、その tag も push します。
edit package.json
--- a/package.json +++ b/package.json "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)", - "check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0" + "check-only-changelog-changed": "(expr $(git status --porcelain 2>/dev/null| grep -v \"CHANGELOG.md\" | wc -l) >/dev/null && echo 'Only CHANGELOG.md may have uncommitted changes' && exit 1) || exit 0", + "tag": "git tag v$npm_package_version", + "version:patch": "npm --no-git-tag-version version patch", + "version:minor": "npm --no-git-tag-version version minor", + "version:major": "npm --no-git-tag-version version major", + "preversion": "CI=true npm run test && npm run check-changelog && npm run check-only-changelog-changed", + "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && git push && git push --tags" } }
後ほど postversion
の最後に npm publish
を追加しますす
gh-pages へのデプロイを準備する
react の component を公開するので実際に見た目がどのように表示されるのかを皆さんに伝える必要があります。
gh-pages に static page をデプロイする方法は色々ありますが、@kadira/storybook-deployer
を install するだけで実現できます。
npm install --save-dev @kadira/storybook-deployer
edit package.json
"version:major": "npm --no-git-tag-version version major", "preversion": "CI=true npm run test && npm run check-changelog && npm run check-only-changelog-changed", - "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag" + "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag", + "deploy-storybook": "storybook-to-ghpages" } }
npm run deploy-storybook
を実行して gh-pages を確認します。
npm run build
src/ 以下に ES6 で書かれた Javascript を lib/ 以下に ES5 に変換したものを配置します。 npm publish しないのであれば不要な作業ですが、現時点では node_modules/ 配下に install するモジュールは es5 が前提だと思いますのでその習慣に従います。
babel コマンドを実行します。もしかしたら react-scripts
が bundle しない 6to5 なコマンドを用意しているのかもしれないのですがよくわからないので自前で babelrc
を用意します。
create .babelrc
{ "presets": ["react", "es2015", "stage-0"] }
以下を実行し、lib 以下に es5 のコードが生成されることを確認します。
$(npm bin)/babel -d lib/ src/
lib 配下は git で管理する必要が無いので .gitignore に追加します
echo "/lib/" >> .gitignore
また lib 配下は npm publish
で使用されるので build 直前で clearn にするようにしておきます。
そして main, files も同様に npm publish される前提の修正を行います。
edit package.json
--- a/package.json +++ b/package.json - "private": true, + "license": "MIT", + "main": "lib/index.js", + "files": "lib", + "author": "okamuuu<okamuuu@gmail.com>", "devDependencies": { "@kadira/storybook": "^2.21.0", "@kadira/storybook-deployer": "^1.2.0", }, ... "scripts": { "start": "react-scripts start", - "build": "react-scripts build", + "build": "rimraf lib && babel -d lib/ src/", "test": "react-scripts test --env=jsdom", "eject": "react-scripts eject", "check-changelog": "expr $(git status --porcelain 2>/dev/null| grep \"^\\s*M.*CHANGELOG.md\" | wc -l) >/dev/null || (echo 'Please edit CHANGELOG.md' && exit 1)",
npm run publish
最後に publish の設定を行います。
postversion のタイミングで npm publish が実行されるようにします。
npm prepublish は、npm install 時に実行してしまいます。npm run build
を npm install
の時に実行しないようにします。
それから npm publish が成功した場合は gh-pages の更新を行うようにします
- "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag", + "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && git push && git push --tags && npm publish --registry=https://registry.npmjs.org/", ... + "build-storybook": "build-storybook -s public", + "prepublish": "in-publish && safe-publish-latest && npm run build || not-in-publish", + "postpublish": "npm run deploy-storybook" }
package されるファイルを確認する
npm publish --dryrun
のようなコマンドを実行したいのですが現時点では存在しないようです:(
代わりに npm pack
を利用します。
http://qiita.com/inuscript/items/5b3c1466a6ddb9ba6231
実際に package されるファイルを確認するコマンドは下記のとおりです。
npm pack -s
はこの記事の通りに設定していると react-xxxxx-0.1.X.tgz
という標準出力を一行だけ吐き出します。
npm build
と prebuild
, postbuild
の設定にもよると思うのでもし同じ状況にならなかったら各自修正をお願いします。
tar -tf $(npm pack -s) && $(npm bin)/rimraf $_
一連の作業をコマンド化します。npm run build
で lib 配下を最新版にし、$(npm pack -s) で packing とファイル名を取得し、それに含まれるファイル一覧を取得します。ついでに不要となった tgz ファイルも削除しましょう。
再び $_
が登場しますが、これは最後に実行したコマンドが tar -tf ARG
なので tgz ファイルを指しています。
+ "build:test": "npm run build >/dev/null && tar -tf $(npm pack -s) && rimraf $_",
このコマンドで視認しながら .npmignore
に不要なファイルを追加していきます。
.babelrc .envrc .storybook .travis.yml stories src test public
期待しているファイルが publish されることを確認します。
% npm run build:test > react-xxxxx@0.1.3 build:test /Users/okamuuu/react-xxxxx > tar -tf $(npm pack -s) && rimraf $_ package/package.json package/.npmignore package/README.md package/lib/App.js package/lib/App.test.js package/lib/index.js package/CHANGELOG.md
.travis.yml
手元の環境では動くのだけどもデプロイすると動かなかったりしますので CI 環境を用意します。 ここでは travis.yml を使っていますが CircleCI でも Wercker でも OK だと思います。
注意点として create-react-app で作成したプロジェクトの test は環境変数に CI=true をセットしていない場合は launch します。
create .travis.yml
language: node_js node_js: - "6" - "4" env: CI: true sudo: false
npm publish
最後に npm publish
を実行します。無事成功したら最後に package.json
を以下の通りに修正します。
- "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && gitpush && git push --tags", + "postversion": "git commit package.json CHANGELOG.md -m \"Version $npm_package_version\" && npm run tag && gitpush && git push --tags && npm publish",
おしまい