npmからインストールしてbroserify/webpack経由だけでなく、ファイルを直接ダウンロードしても使って欲しいブラウザ用ライブラリを作る環境を整える。
前提条件
- babelにてES2015(ES6)を利用する
- npm経由でインストールできる
- ファイルを直接ダウンロードしても利用できる
- githubに公開する
- テストはkarma
- TravisCIを利用する
- saucelabsでマルチブラウザのテストをする
以下で時々「saiji」という文字がでてくるが、これは自作のライブラリの名前である。適宜ご自分のライブラリ名に読み替えていただきたい。
ディレクトリ構成概要
ES2015のコードをsrc
ディレクトリに書いてbabelでlib
に出力。lib
に出力されたものをtop直下にbrowserifyで出力する。そのファイルをダウンロードすればnpmなしでも利用できるようになる。
テストはbrowserifyされたファイルのみが対象。
git
gitではlib
、node_module
は管理対象から外す。
/lib
node_module
npm
pachake.jsonのfiles
を指定して、npmにはbabelでトランスパイルされたlib
のみ公開するようにする。
mainはlib以下を指定。
"main": "lib/saiji.js",
"files": [
"lib"
]
babel
ES2015のためにbabel-cli
、 babel-preset-es2015
をインストールして、.babelrc
ファイル作成。
npm i -D babel-cli babel-preset-es2015
echo '{ "presets": ["es2015"] }' > .babelrc
npmのscriptsにbabel
でsrc以下をlibに出力。、watch:babel
でwatchする。
"scripts": {
"babel": "babel src -d lib",
"watch:babel": "babel src -d lib -w"
}
browserify
browserifyを利用して、ファイル直接読み込みでも利用できるようにする。
browserify
、差分ビルドのためにwatchify
をインストール。
npm i -D browserify watchify
build
でlib/saiji.js(endpoint)をTOPディレクトリ以下に出力する。
build
でbrowserify、watch:build
でwatchifyを利用する。-s
オプションをつけてグローバルを生やしておく。
"scripts": {
"build": "browserify lib/saiji.js -o saiji.js -s saiji",
"watch:build": "watchify lib/saiji.js -o saiji.js -s saiji -v",
}
babel&browserify
実際に開発しているときは、babel => browserify をwatchしておきたい。そのためのwatch
をpackage.jsonのscriptsに登録しておく。
"scripts": {
"babel": "babel src -d lib",
"build": "browserify src/saiji.js -o saiji.js -s saiji",
"watch:babel": "babel src -d lib -w",
"watch:build": "watchify lib/saiji.js -o saiji.js -s saiji -v",
"watch": "npm run watch:babel & npm run watch:build"
}
karma
window
やdocument
を含むDOMをカジュアルにつかえるため、テストはkarmaを利用する。
フレームワークはmocha
、assertはchai.assert
を使う。
karmaをインストールしたらkarma init
でkarma.conf.js
を作成する。
npm i -D karma mocha chai karma-chai
./node_modules/.bin/karma init
karma.conf.jsのframeworksにchaiを追加する。
karmaのpreprocessorsでbabel,browserifyすると、パフォーマンス的にストレスがたまる‥‥ そのため、babel,browserify済みのTOPディレクトリのファイルをテスト対象にしてpreprocessorsは使わない。 (本当はpowerassert使いたいんだけど )
frameworks: ['mocha', 'chai'],
files: [
'saiji.js',
'test/*.js'
],
preprocessors: {}
npm test
でkarmaが起動するようにしておく。
"scripts": {
"test": "karma start",
...
},
TravisCI
TravisCIを使いたい、というかバッジが欲しい
LTSの4系と最新の5系を使い、karmaでChrome(chromium)を使う設定をbefore_install
に書く。
language: node_js
node_js:
- "4"
- "5"
before_install:
- export CHROME_BIN=chromium-browser
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
TravisCIでkarmaを使う場合は、singleRunをtrueにしなければならなかったりするので、karma.conf.jsを変更。
var customLaunchers = {};
var browsers = ["Chrome"];
var singleRun = false;
if (process.env.TRAVIS) {
customLaunchers = {
Chrome_travis_ci: {
base: 'Chrome',
flags: ['--no-sandbox']
}
};
browsers = ["Chrome_travis_ci"];
singleRun = true;
}
module.exports = function(config) {
config.set({
//関係ない部分は省略
browsers: browsers,
singleRun: singleRun,
})
};
SauceLabs
マルチブラウザのテストのためにSauceLabsを使う。
karmaからSauceLabsを使うには、karma-sauce-launcher
を使うので、まずはインストール。
npm i -D karma-sauce-launcher
karma側にテストするブラウザ情報を渡してやることになるのだけれど、karma.conf.jsにずらずら書くと可読性が落ちるので、ブラウザ管理部分を別ファイルにする。
customlaunchers.js
というファイルをつくり、そこにテストするブラウザを羅列。
var version = require("./package.json").version;
// Check out https://saucelabs.com/platforms
module.exports = {
"sl_win10_chrome": {
"base": 'SauceLabs',
"browserName": "chrome",
"platform": "Windows 10",
"version": "48",
"build": version,
"passed": true
},
"sl_win10_firefox": {
"base": 'SauceLabs',
"browserName": "firefox",
"platform": "Windows 10",
"version": "44",
"build": version,
"passed": true
},
/// こんな感じで羅列
};
npm run sauce
とすればSauceLabsのテストをできるようにする。
"scripts": {
"sauce": "Sauce=true karma start"
}
karma.conf.js側で環境変数をみて作成したcustomlaunchers.jsを読み込む。
OpenSource版のSauceLabsは同時接続が5接続までなので、concurrencyの設定をする。
var customLaunchers = {};
var browsers = ["Chrome"];
var reporters = ['progress'];
var singleRun = false;
var concurrency = Infinity;
if(process.env.Sauce) {
customLaunchers = require("./customlaunchers");
browsers = Object.keys(customLaunchers);
reporters = ['dots', 'saucelabs'];
singleRun = true;
concurrency = 5;
}
module.exports = function(config) {
config.set({
//関係ない部分は省略
sauceLabs: {
testName: "test name",
username: "SauceLabs username",
accessKey: "SauceLabs accessKey",
public: "public"
},
customLaunchers: customLaunchers,
browsers: browsers,
reporters: reporters,
singleRun: singleRun,
concurrency: concurrency
})
};
karma.conf.js
karma.conf.jsの最終形はこんな感じ
var customLaunchers = {};
var browsers = ["Chrome"];
var reporters = ['progress'];
var singleRun = false;
var concurrency = Infinity;
if (process.env.TRAVIS) {
customLaunchers = {
Chrome_travis_ci: {
base: 'Chrome',
flags: ['--no-sandbox']
}
};
browsers = ["Chrome_travis_ci"];
singleRun = true;
} else if(process.env.Sauce) {
customLaunchers = require("./customlaunchers");
browsers = Object.keys(customLaunchers);
reporters = ['dots', 'saucelabs'];
singleRun = true;
concurrency = 5;
}
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['mocha', 'chai'],
files: [
'saiji.js',
'test/*.js'
],
exclude: [],
preprocessors: {
},
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
sauceLabs: {
testName: "test name",
username: "sauce username",
accessKey: "sauce accessKey",
public: "public"
},
customLaunchers: customLaunchers,
browsers: browsers,
reporters: reporters,
singleRun: singleRun,
concurrency: concurrency
})
};
というわけで、npmでもファイル直接でも利用できるブラウザ用JavaScriptライブラリをつくる環境ができあがったというわけです‥‥
が、これ、大変すぎやしないですかね。
牧歌的な;(function(){}())
で囲まれたJavaScriptをQUnitでテストしていたころが懐かしい