Spring Boot + npm + Geb で入力フォームを作ってテストする ( その45 )( gradle の build タスク実行時に Javascript の build+テスト を実行する )
概要
記事一覧はこちらです。
Spring Boot + npm + Geb で入力フォームを作ってテストする ( 番外編 )( MobX を使用してみる2 ) の続きです。
- 今回の手順で確認できるのは以下の内容です。
- Flow を試してみようと思っていましたが、途中からちょっと入れて試すようなものではなさそうだったので、止めました。
- Gradle の build タスクを実行した時に、Jest のテストと webpack による build を一緒に実行できるようにする(エラーが出た場合には build タスクを中断する)方法を調べます。
参照したサイト・書籍
gradle-node-plugin 使って Sass をコンパイルしたりすればいいじゃない
https://qiita.com/macoshita/items/82aa006c75cdd2222abfsrs/gradle-node-plugin
https://github.com/srs/gradle-node-pluginjest-html-reporter
https://www.npmjs.com/package/jest-html-reporterHow can I set NODE_ENV=production on Windows?
https://stackoverflow.com/questions/9249830/how-can-i-set-node-env-production-on-windowscross-env
https://www.npmjs.com/package/cross-envwebpack-contrib/uglifyjs-webpack-plugin
https://github.com/webpack-contrib/uglifyjs-webpack-pluginGoogleChromeLabs/webpack-training-project
https://github.com/GoogleChromeLabs/webpack-training-projectGoogleChromeLabs/webpack-libs-optimizations
https://github.com/GoogleChromeLabs/webpack-libs-optimizations
目次
- 目標
- gradle から npm scripts を実行するのに gradle-node-plugin を使用する
- gradle から npm scripts を実行するのに
task ...(type: Exec) {...}
を使用する - jest-html-reporter をインストールする
- gradle-node-plugin にするか
task ...(type: Exec) {...}
にするか? - package.json に build 用の npm scripts を追加する
- build.gradle に npmBuild タスクを定義する
npm run build
を実行する時は webpack でソースマップを出力せず、uglify する- 次回は。。。
手順
目標
以下のことができるようにしてみたいと思います。
- build.gradle に npmTest, npmBuild というタスクを作成する。
- npmTest は
npm test
、npmBuild はnpm run build
(新規作成する)に関連させる。 - npmTest → npmBuild → processResources → ... の順に実行する。
npm run springboot
を実行する時は webpack でソースマップを出力し、かつ uglify しない。npm run build
を実行する時は webpack でソースマップを出力せず、uglify する。
gradle から npm scripts を実行するのに gradle-node-plugin を使用する
gradle から npm scripts を実行するのに srs/gradle-node-plugin というプラグインがあるとのことなので、このプラグインを使用して npm test
を実行してみます。
build.gradle を以下のように変更します。
buildscript { ext { springBootVersion = '1.5.9.RELEASE' } repositories { mavenCentral() maven { url "https://plugins.gradle.org/m2/" } } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") // for Error Prone ( http://errorprone.info/ ) classpath("net.ltgt.gradle:gradle-errorprone-plugin:0.0.13") classpath("com.moowork.gradle:gradle-node-plugin:1.2.0") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'idea' apply plugin: 'org.springframework.boot' apply plugin: 'groovy' apply plugin: 'net.ltgt.errorprone' apply plugin: 'checkstyle' apply plugin: 'findbugs' apply plugin: 'pmd' apply plugin: 'com.moowork.node' .......... task npmTest(type: NpmTask) { args = ["test"] } processResources.dependsOn npmTest ..........
- buildscript に
classpath("com.moowork.gradle:gradle-node-plugin:1.2.0")
を追加します。 apply plugin: 'com.moowork.node'
を追加します。task npmTest(type: NpmTask) { ... }
を追加します。processResources.dependsOn npmTest
を追加します。
clean タスク → build タスクの順に実行してみます。現在 Jest のテストは全て成功する状態です。
.....(長いので途中は省略します).....
npmTest タスクは正常終了し、"BUILD SUCCESSFUL" も出力されました。ただし、
- テストファイル1つに付き、
PASS
の文字が付いた行が出力されます。出来れば Java のテストのように成功時は何も出力されないようにしたいです。 - Jest のテストに
console.log(....);
を書いているものがあるのですが、コンソールにログが大量に出力されました。gradle-node-plugin や Gradle の Webサイトを見てみたのですが、ログを抑制する方法が分かりません。。。
gradle から npm scripts を実行するのに task ...(type: Exec) {...}
を使用する
cmd.exe で npm コマンドを実行して標準出力/エラー出力を NUL へ送ればコンソールにログが出力されないはずなので、task ...(type: Exec) {...}
でタスクを定義してみます。
build.gradle を以下のように変更します。
//task npmTest(type: NpmTask) { // args = ["test"] //} task npmTest(type: Exec) { commandLine "cmd", "/c", "npm test >NUL 2>&1" } processResources.dependsOn npmTest
task npmTest(type: NpmTask) { ... }
はコメントアウトします。task npmTest(type: Exec) { ... }
を追加します。>NUL 2>&1
を付けてnpm test
の標準出力、エラー出力を一切出ないようにします。
clean タスク → build タスクの順に実行してみます。
npmTest タスクは正常終了し、"BUILD SUCCESSFUL" も出力されました。余計なログも出力されません。個人的にはこの出力結果の方が理想です。
テストが途中で失敗した時にそこで止まって先のタスクに進まないのかが気になるので試してみます。
src/test/assets/tests/lib/util/ZipcloudApiHelper.test.js の以下の点を変更します。
// zipcloudApiHeler.search の dataType: "jsonp" を削除しないと下のテストは成功しないので // コメントアウトしておく describe("jquery-mockjax でサーバ側をモックにして $.ajax をテストする", () => { afterEach(() => { mockjax.clear(); });
describe("jquery-mockjax でサーバ側をモックにして $.ajax をテストする", () => { ... }
の前後の/*
、*/
を削除し、コメントアウトを解除します。これで Jest のテストで失敗するものが出ます。
clean タスク → build タスクの順に実行してみると、npmTest タスクでエラーが出て止まりました。
ただしエラーがどこで出たのかレポートファイルで確認しようと思ったのですが、coverage のレポートしか出ていませんでした。Jest のページを見ましたが、テスト結果のレポートを出力させる方法がよく分かりません。。。
jest-html-reporter をインストールして試してみる
レポートファイルを生成する方法を調べてみたところ、jest-html-reporter というモジュールを見つけました。インストールして試してみます。
npm install --save-dev jest-html-reporter
コマンドを実行してインストールします。
jest.config.json を以下のように変更します。
{ "coverageDirectory": "build/reports/jest", "moduleDirectories": [ "node_modules", "src/main/assets/js" ], "testResultsProcessor": "./node_modules/jest-html-reporter" }
"testResultsProcessor": "./node_modules/jest-html-reporter"
を追加します。
jest-html-reporter の設定は package.json に記述するようなので、package.json を以下のように変更します。
"license": "ISC", "jest-html-reporter": { "outputPath": "build/reports/jest/jest-html-reporter.html", "includeFailureMsg": true }, "dependencies": {
"jest-html-reporter": { ... }
を追加します。
clean タスク → build タスクの順に実行してみます。先程と同様のエラーが出た後、build/reports/jest の下に jest-html-reporter.html が生成されていました。
jest-html-reporter.html をブラウザで表示させると、失敗したテストとエラーメッセージが表示されていました。
必要な情報が出ていて申し分がないので、jest-html-reporter をこのまま使用することにします。
gradle-node-plugin にするか task ...(type: Exec) {...}
にするか?
環境依存しないと思われる gradle-node-plugin の方が良いとは思うのですが、task ...(type: Exec) {...}
の方が不要な出力が出ず動作が好みなので、今回はこちらの方法を使用することにします。
package.json に build 用の npm scripts を追加する
package.json に npm run build
で実行する npm scripts を定義します。
"scripts": { "test": "jest --config=jest.config.json --coverage", "postinstall": "run-s clean:static-dir copy:all", "clean:static-dir": "rimraf src/main/resources/static/*", "clean:cssjs-dir": "rimraf src/main/resources/static/{css,js}/*", "copy:all": "run-p copy:bootstrap copy:admin-lte copy:font-awesome copy:ionicons copy:jquery-ui-css", "copy:bootstrap": "cpx node_modules/bootstrap/dist/**/* src/main/resources/static/vendor/bootstrap", "copy:admin-lte": "cpx node_modules/admin-lte/dist/**/* src/main/resources/static/vendor/admin-lte", "copy:font-awesome": "cpx node_modules/font-awesome/{css,fonts}/**/* src/main/resources/static/vendor/font-awesome", "copy:ionicons": "cpx node_modules/ionicons/dist/{css,fonts}/**/* src/main/resources/static/vendor/ionicons", "copy:jquery-ui-css": "cpx node_modules/jquery-ui/themes/base/**/* src/main/resources/static/vendor/jquery-ui/css", "postcss:build": "postcss src/main/assets/css/**/* -d src/main/resources/static/css -x .min.css", "postcss:watch": "postcss src/main/assets/css/**/* -d src/main/resources/static/css -x .min.css -w --poll", "webpack:build": "webpack", "webpack:watch": "webpack --watch", "browser-sync:start": "browser-sync start --config bs-config.js", "browser-sync:springboot": "browser-sync start --config bs-springboot-config.js", "server": "run-p postcss:watch webpack:watch browser-sync:start", "springboot": "run-p postcss:watch webpack:watch browser-sync:springboot", "build": "run-s clean:cssjs-dir postcss:build webpack:build" },
- 以下の4行を追加します。
"clean:cssjs-dir": "rimraf src/main/resources/static/{css,js}/*"
"postcss:build": "postcss src/main/assets/css/**/* -d src/main/resources/static/css -x .min.css"
"webpack:build": "webpack"
"build": "run-s clean:cssjs-dir postcss:build webpack:build"
コマンドプロンプトから npm run build
を実行して正常に動作することを確認します。
build.gradle に npmBuild タスクを定義する
build.gradle を以下のように変更します。
.......... //task npmTest(type: NpmTask) { // args = ["test"] //} task npmTest(type: Exec) { commandLine "cmd", "/c", "npm test >NUL 2>&1" } task npmBuild(type: Exec) { commandLine "cmd", "/c", "npm run build >NUL 2>&1" } npmBuild.dependsOn npmTest processResources.dependsOn npmBuild repositories { mavenCentral() } ..........
task npmBuild(type: Exec) { ... }
を追加します。npmBuild.dependsOn npmTest
、processResources.dependsOn npmBuild
を追加します。
これで npmTest → npmBuild → processResources → ... の順にタスクが実行されるはずです。clean タスク → build タスクの順に実行してみます。
全てのタスクが正常終了し、"BUILD SUCCESSFUL" が出力されました。問題なさそうです。
npm run build
を実行する時は webpack でソースマップを出力せず、uglify する
Windows で NODE_ENV 環境変数で webpack の設定を切り替えられるようにするために cross-env モジュールをインストールする
Spring Boot の spring.profiles.active
のように webpack でも環境変数で設定を切り替えたい場合 NODE_ENV
を使用しますが、npm scripts を "build": "NODE_ENV=product run-s clean:cssjs-dir postcss:build webpack:build"
のように NODE_ENV=product
を付けても Windows 環境では以下の画像のようにエラーになります。
エラーにならない方法を調べたところ、How can I set NODE_ENV=production on Windows? に cross-env モジュールを使う方法が書かれていました。
npm install --save-dev cross-env
コマンドを実行してインストールします。
uglifyjs-webpack-plugin をインストールする
webpack で js ファイルを uglify するには uglifyjs-webpack-plugin を使えばいいようです。npm install --save-dev uglifyjs-webpack-plugin
コマンドを実行してインストールします。
webpack.config.js を変更する
GoogleChromeLabs/webpack-training-project を参考に、NODE_ENV=product が設定されている時だけ uglifyjs-webpack-plugin が適用されるようにします。ソースマップは uglifyjs-webpack-plugin が適用されると webpack.config.js に devtool: "inline-source-map"
が記述されていても出力されなくなります。
const webpack = require("webpack"); const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); const isProduct = process.env.NODE_ENV === "product"; module.exports = { .......... plugins: [ new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" }) ].concat( isProduct ? [ new UglifyJsPlugin() ] : [] ), devtool: "inline-source-map" };
- 以下の2行を追加します。
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
const isProduct = process.env.NODE_ENV === "product";
- plugins に
.concat(isProduct ? [new UglifyJsPlugin()] : [])
を追加します。
package.json を変更する
package.json を以下のように変更します。
"scripts": { .......... "springboot": "run-p postcss:watch webpack:watch browser-sync:springboot", "build": "cross-env NODE_ENV=product run-s clean:cssjs-dir postcss:build webpack:build" },
- npm scripts の
build
の先頭にcross-env NODE_ENV=product
を追加します。
動作確認
コマンドプロンプトから npm run build
コマンドを実行してみます。
エラーが出ずに終了し、webpack でバンドルした後の js ファイルが 100KB 前後とかなり小さくなりました(上にある画像キャプチャを見ると cross-env NODE_ENV=product
を指定していない npm run build
コマンドでは 750KB ~ 1MB 程度でした)。ただし uglify するためか処理時間が 18秒もかかりますね。
ちなみに webpack.config.js から devtool: "inline-source-map"
を削除して npm run build
コマンドを実行しても生成される js ファイルのサイズは変わりません。
clean タスク → build タスクを実行すると、こちらも問題なく終了しました。
webpack によりバンドルされた input01.js を開いてみると、確かに uglify されています。
次回は。。。
入力画面3以降の作成を進めます。
履歴
2018/02/21
初版発行。