Node.js 開発関連情報


Develop Environment

Nodeclipseを参照のこと


Source Code Comments

ファイルコメントの記述

ファイルの先頭に @file タグを付けてファイルの内容を記述する。

/**
 * @file 文字列操作のユーティリティ関数を提供する。
 * @copyright Michael Mathews 2011
 */

関数コメントの記述

関数の前にコメントを記述する。

/**
 * 日付けを書式文字列に従って文字列に変換する。
 * 
 * @param {<型>} <引数名1> <引数の説明>
 * @param {<型>} <引数名2> <引数の説明>
 * ...
 * @return {<型>} <戻り値の説明>
 */
exports.<関数名> = function (<引数名1>, <引数名2>, ...) {
    ...
}
参考文献

jsdoc によるAPIドキュメントの出力

  1. パッケージのインストール
    $ npm install [-g] --save-dev jsdoc
  2. APIドキュメント生成
    $ ./node_modules/.bin/jsdoc <srcdir-path> -d <outputdir-path>

Dependendies Management

作成したモジュールが依存するモジュールを管理する手順を説明する。

依存モジュールのインストール

依存モジュールをインストールする場合で、カレントディレクトリーの下に 「package.json」ファイルが存在しない場合は、以下の内容でファイルを作成 してからモジュールのインストールをすること。

{
}
  1. 開発・テスト用途ではないモジュールのインストール
    $ npm install [-g] <package-name> ...

    -g オプションを付けずにこのコマンドを実行すると、カレントディレクトリーの 下に「node_modules」ディレクトリーが作成され、その下に引数で指定された モジュールがインストールされる。

    -g オプションを指定すると、システム・ディレクトリー (/usr/lib/node_modules) の下にモジュールがインストールされる。この場合は管理者権限でコマンドを 実行すること。

    このコマンドの実行により、カレントディレクトリー配下の以下のファイルに インストールされたモジュールの情報が記録される。

    • package.json

      「dependencies」にインストールされたモジュールの名前とそのバージョンが 記録される。

    • package-lock.json

      引数で指定されたモジュール、及びそのモジュールに依存してインストールされた モジュールの名前で「dependencies」のキーが作成され、以下の項目が設定 される。

      • version - モジュールのバージョン
      • resolved - モジュールの取得元 URL
      • integrity - ファイルのハッシュ値
      • dev - npm install コマンドで「--save-dev」オプションを指定した場合に true が設定される
      • requires - 依存するモジュールの情報(モジュール名とバージョン)
  2. 開発・テスト用途のモジュールのインストール
    $ npm install [-g] --save-dev <package-name> ...

    -g オプションを指定した場合、指定しなかった場合のモジュールのインストール 先は、「開発・テスト用途ではないモジュールのインストール」と同様である。

    このコマンドの実行により、カレントディレクトリー配下の以下のファイルに インストールされたモジュールの情報が記録される。

    • package.json

      「devDependencies」にインストールされたモジュールの名前とそのバージョンが 記録される。

    • package-lock.json

      「開発・テスト用途ではないモジュールのインストール」と同様である。

依存モジュールのアンインストール

$ npm uninstall [-g] <package-name> ...

-g オプションを指定しなかった場合は、カレントディレクトリー配下の 「node_modules」ディレクトリーから、引数で指定されたモジュール、及びその モジュールの依存モジュールを削除する。-g オプションを指定した場合は、 システム・ディレクトリーからモジュールを削除する。

このコマンドを実行すると、カレントディレクトリー配下の以下のファイルから、 アンインストールされたモジュールの情報が削除される。

  • package.json
  • package-lock.json

依存モジュールの再配置

作成した Node.js のスクリプトを配備する場合など、別のホストやディレクトリーに スクリプトを配置して実行する場合は、以下のコマンドを実行して依存モジュールを 新たな配置先のディレクトリーで実行する。

  1. 依存モジュールのインストール

    package.json ファイルが存在するディレクトリーに移動して、以下のコマンドを 実行する。

    $ npm install [-g] [--production]

    このコマンドを実行すると、package.json ファイルに設定されているモジュールを 以下のディレクトリーにインストールする。

    • -g オプションが指定されていない場合

      カレントディレクトリー配下の「node_modules」ディレクトリー

    • -g オプションが指定されている場合

      システム・ディレクトリー

    --production オプションを指定した場合は、package.json の「devDependencies」 に設定されたモジュールはインストールされない。

  2. 依存モジュールのクリーンインストール

    package-lock.json ファイルが存在するディレクトリーに移動して、以下の コマンドを実行する。

    $ npm ci [--production]

    このコマンドを実行すろと、以下の処理が行われる。

    • package-lock.json に設定されているモジュールの全てをカレント ディレクトリー配下の「node_modules」ディレクトリの下にインストールする。 ただし、--production を指定した場合は、開発・テスト用のモジュール (package-lock.json び各モジュールの dev 項目に true が設定されている もの)はインストールされない。
    • カレントディレクトリー配下に「node_modules」ディレクトリーが存在する 場合は、そのディレクトリーを削除してからモジュールをインストールする。
    • インストールするモジュールが package.json の設定と異なる場合は、エラーを 表示して終了する。

依存関係の表示

license-checker を使用して、依存モジュールとそのライセンスを表示することが できる。

  1. モジュールのインストール
    $ npm install --save-dev license-checker
  2. 依存モジュールとそのライセンスの表示
    $ cd <module-dir>
    $ license-checker [--out <output-file-path>] [--production] \
          [--excludePackages <package-name>[@<version>][;...]]

    オプションの説明

    • --out output-file-path : 出力ファイルのパスを指定する
    • --production : production の依存関係を出力する
    • --excludePackages package-list : 「パッケージ名[@バージョン]」を セミコロンで区切った形式で除外するパッケージのリストを指定する

参考文献


Unit Test

Jest を使用したテストの実装と実行手順について説明する。

Jest のインストール

テスト対象のスクリプトを配置したディレクトリーに移動して、以下のコマンドを 実行し、jest モジュールをインストールする。

$ npm install --save-dev jest

テストスクリプトの作成

テスト対象のスクリプトを配置したディレクトリの下に、「__test__」ディレクトリー を作成して、そのディレクトリーにテストスクリプトを作成する。

テストスクリプトの例を以下に示す。

beforeAll(() => {
  initializeCityDatabaseFirst();
});

afterAll(() => {
  return clearCityDatabaseFinally();
});

beforeEach(() => {
  initializeCityDatabaseEatch();
});

afterEach(() => {
  clearCityDatabaseEach();
});

test('city database has Vienna', () => {
  expect(isCity('Vienna')).toBeTruthy();
});

test('city database has San Juan', () => {
  expect(isCity('San Juan')).toBeTruthy();
});

[city.test.js]

説明

  • テストスクリプトの名前は「.test.js」で終わるようにする。
  • テストを実装する関数の名前は、「test」にする。
  • テスト結果の判定は、以下のようにexpect と matcher を使用する。
    expect(<値>).<matcher>([<引数>]);
  • matcher の使用例
    // 厳密に一致する
    expect(2 + 2).toBe(4);
    // オブジェクトに一致する
    expect(data).toEqual({one: 1, two: 2});
    // 「真」である
    expect(n).toBeTruthy();
    // 「偽」である
    expect(n).toBeFalsy();
    // 数値が〜より大きい
    expect(value).toBeGreaterThan(3);
    // その他の数値の大小比較用のmatcherもある
    ...
    // 正規表現に一致する
    expect('Christoph').toMatch(/stop/);
    // 一致する配列要素が含まれる
    expect(shoppingList).toContain('milk');
    // 関数を呼び出すと例外が発生する
    expect(() => compileAndroidCode()).toThrow();
    // 関数を呼び出すと特定の例外が発生する
    expect(() => compileAndroidCode()).toThrow(Error);
    
    // matcherとは反対の結果
    except(value).not.<matcher>

Jest の実行

テスト対象のスクリプトを配置したディレクトリー(__test__ ディレクトリーの 親ディレクトリー)に移動して、以下の手順を実施 する。

  • package.json の編集
    {
      "scripts": {
        "test": "jest"
      }
    }
  • テストの実行
    $ npm test
  • 実行結果

    テストの実行結果は、以下のようにコンソールに表示される。

    • テストが合格の場合
       PASS  ./stringutil.test.js
        ✓ stringutil.formatDate test (12 ms)
      
      Test Suites: 1 passed, 1 total
      Tests:       1 passed, 1 total
      Snapshots:   0 total
      Time:        1.331 s, estimated 6 s
      Ran all test suites.
    • テストが不合格の場合場合
       FAIL  ./stringutil.test.js
        ✕ stringutil.formatDate test (12 ms)
      
        ● stringutil.formatDate test
      
          expect(received).toBe(expected) // Object.is equality
      
          Expected: "05"
          Received: "06"
      
            4 |       date = new Date(1234, 5, 6, 12, 34, 56);
            5 |     expect(stringutil.formatDate(date, 'yyyy')).toBe("1234");
          > 6 |     expect(stringutil.formatDate(date, 'MM')).toBe("05");
              |                                               ^
            7 |     expect(stringutil.formatDate(date, 'dd')).toBe("06");
            8 |     expect(stringutil.formatDate(date, 'HH')).toBe("12");
            9 |     expect(stringutil.formatDate(date, 'mm')).toBe("34");
      
            at Object.<anonymous> (stringutil.test.js:6:47)
      
      Test Suites: 1 failed, 1 total
      Tests:       1 failed, 1 total
      Snapshots:   0 total
      Time:        1.276 s
      Ran all test suites.
      npm ERR! Test failed.  See above for more details.

Jest のデバッグ実行

Jest は、以下の理由によりテストファイルからデバッグ実行を行うことができない。

  • テストの実行は jest コマンドにより行われる。
  • 規定の設定では、ファイル単位に非同期でテストが実行される(ファイル内の テストメソッドは順番に実施)。

そのため、Jest のテストスクリプトをデバッグ実行する場合は、「debugger;」宣言を テストスクリプトに記述して(その場所でデバッガーが接続されるまで停止する)、 以下のコマンドを実行する。

$ node --inspect-brk node_modules/.bin/jest --runInBand <script-file-path>

Nodeclipse から 上記のコマンドを実行するための JavaSscript の例を以下に示す。

// Node 1st option.
process.argv.splice(1, 0, '--inspect-brk');
// Node 2nd option is this script file.
// Node 3rd option.
process.argv.push('--runInBand');
// Node 4th option.
process.argv.push('<script-file-path>');
// Node options more...

// Run jest command.
debugger;
require('jest/bin/jest.js');

[debugJest.js]

参考文献

テスト結果のHTML形式でのレポート出力

テスト対象のスクリプトを配置したディレクトリー(__test__ ディレクトリーの 親ディレクトリー)に移動して、以下の手順を実行する。

  1. 準備
    • jest-html-reporter モジュールのインストール
      $ npm install --save-dev jest-html-reporter
    • jest.config.json の編集
      {
          "reporters": [
              "default",
              ["./node_modules/jest-html-reporter", {
                  "pageTitle": "Test Report",
                  "outputPath": "./__test__/test-reports/test-report.html"
              }]
          ],
          "testResultsProcessor": "./node_modules/jest-html-reporter"
      }
  2. テストの実行とレポートの出力

    以下のテスト実行用のコマンドを実行すると、テストとHTML形式のレポートが 出力される。

    $ npm test

    レポートの出力先は、jest.config.json ファイルの "outputPath"に設定された ディレクトリ、ファイル名となる。

babel-plugin-rewire

エクスポートされていない関数をテストするために、babel-plugin-rewire パッケージをインストール、設定する。

  1. パッケージのインストール

    package.json ファイルが存在するディレクトリに移動して以下のコマンドを 実行し、babel-plugin-rewire パッケージをインストールする。

    $ npm install --save-dev babel-plugin-rewire
  2. babel.config.json ファイルの編集

    __tests__ ディレクトリ(テストスクリプトが配置されたディレクトリ)に 移動して、babel.config.json ファイルを作成し、以下の内容を記述する。

    {
      "env": {
        "test": {
          "plugins": ["babel-plugin-rewire"]
        }
      }
    }
  3. テストの実行
    • テストモジュール

      テスト対象のモジュール「mymodule.js」が配置されたディレクトリ配下の __tests__ ディレクトリに配置された JavaScript ファイル。

      it('calculateWinner test', () => {
              // babel-plugin-rewire を使用して export されていない関数を読み込む
              no_exported_function = require('../mymodule').__get__('no_exported_function');
      
          // 関数の戻り値をテストする
          expect(fno_exported_function('hello')).toEqual('world');
          ...
      });

      [__tests__/mymodule.test.js]

    • テスト対象のモジュール

      テスト対象の関数「no_exported_function」を定義している JavaScript ファイル。

      function no_exported_function(arg) {
          ...
          return message;
      }

      [mymodule.js]

参考文献


Coverage Report

テスト対象のスクリプトを配置したディレクトリー(__test__ ディレクトリーの 親ディレクトリー)に移動して、以下の手順を実行する。

  1. 準備
    • jest.config.json の編集
      {
         ...
          "collectCoverage": true,
          "collectCoverageFrom": [
              "**/*.{js,jsx}",
              "!**/node_modules/**",
              "!**/__test__/**"
          ],
          "coverageDirectory": "./__test__/coverage"
      }
  2. カバレッジレポートの出力

    以下のテスト実行用のコマンドを実行すると、テストが実行され、HTML形式の カバレッジレポートが出力される。

    $ npm test

    HTML形式のレポートは、jest.config.json ファイルの "coverageDirectory" に設定されたディレクトリー配下の lcov-report/index.html に出力される。


Proxy settings

プロキシサーバーを通してインターネットにアクセスするときの設定について説 明する。


React

開発環境の作成

  • ブランクプロジェクトの作成
    1. プロジェクトの作成

      アプリケーション名 app-name を指定して、以下のコマンドを実行する。

      $ npx create-react-app <app-name>
    2. サンプルソースの削除
      $ cd <app-name>/src
      $ rm -rf *
参考文献

Create React App

アプリケーションのリリース

npm run buuild コマンド

Create React App で作成したアプリケーションのディレクトリ(package.jsonファイルのある ディレクトリ)に移動して、以下のコマンドを実行する。

$ npm run build

上記のコマンドを実行すると build ディレクトリが作成され、リリース用の アプリケーションのファイル一式(下記参照)が作成される。

build/
|-- asset-manifest.json
|-- favicon.ico
|-- index.html
|-- logo123.png
|-- logo456.png
|-- manifest.json
|-- robots.txt
`-- static
    |-- css
    |   |-- main.12345678.css
    |   `-- main.12345678.css.map
    `-- js
        |-- main.abcd1234.js
        |-- main.abcd1234.js.LICENSE.txt
        `-- main.abcd1234.js.map

index.html には、ReactのJSXから変換された JavaScriptファイル (main.abcd1234.js)と、CSSファイル(main.12345678.css)が以下のように 組み込まれている。

<html lang="en">
  <head>
    ...
    <script defer="defer" src="static/js/main.abcd1234.js"></script>
    <link href="static/css/main.12345678.css" rel="stylesheet">
  </head>
  <body>
    ...
    <div id="root"></div>
  </body>
</html>
備考

生成される index.html は、JSファイル、CSSファイルを絶対パス(/ で始まる パス)で参照しているが、ここではパスの先頭の「/」を除いて相対パスで参照 するように編集した。

手動でウェブサイトにReactを追加する

以下に示す手順は 既存のウェブサイトに React を追加する で示された手順で、、ツールチェーンを使用せずに、手動で React を HTML に 組み込む手順を示したものである。

  1. 作業の流れ
    1. JSX プリプロセッサを実行する

      JSX プリプロセッサを実行して、JSX形式の Reactコンポーネントのファイルを 通常の JavaScript 形式に変換する。

    2. JS ファイルのサイズを圧縮する

      JavaScript ファイルの改行や空白を除去してファイルのサイズを圧縮する。

    3. Reactコンポーネントの組み込み

      変換した Reactコンポーネントの JavaScript ファイルを静的なページ (HTMLなど)に組み込む。

  2. JSX プリプロセッサの実行
    1. JSX プロプロセッサのインストール

      作業ディレクトリにて、babel 関連のパッケージをインストールしていない 場合は、以下のコマンドを実行してパッケージをインストールする。

      $ npm init -y
      $ npm install babel-cli@6 babel-preset-react-app@3
    2. JSX プリプロセッサの実行

      作業ディレクトリで以下のコマンドを実行して、JSXファイルを 通常の JavaScript ファイルに変換する。

      $ npx babel <変換元JSXファイルのパス> --presets react-app/prod \
            [--out-file <変換後JSファイルのパス>]
      備考
      • 「--out-file 変換後JSファイルのパス」を省略すると標準出力に 変換結果が出力される
      • 変換元JSXファイルのパス が作業ディレクトリ、または作業ディレクトリ のサブディレクトリ配下のファイルでない場合は、エラーが発生する
  3. JavaScriptの圧縮
    1. JSファイル圧縮ツールのインストール

      作業ディレクトリにてJSファイル圧縮ツールのパッケージをインストールして いない場合は、以下のコマンドを実行して Node.js のパッケージをインストール する。

      $ npm install terser
    2. JSファイルの圧縮

      作業ディレクトリから以下のコマンドを実行して、JavaScriptファイルの圧縮 (空白、改行等を除去してファイルサイズを小さくする)をする。

      $ npx terser -c -m -o <変換先JSファイルのパス> [-- <変換元JSファイルのパス>]
      • 変換先のJSファイル名について

        変換先のJSファイルの名前は、変換元JSファイルの「.js」の前に「.min」を 付けたものにするとよい。

        例: my-class.js => my-class.min.js

      iii
      JSX プリプロセッサとJSファイルの圧縮を続けて行う場合の例

      src/my-class.jsx をJSファイルに変換し、続けてJSファイルの圧縮をして my-class.min.js に保存する場合のコマンドの例は以下のとおり。

      $ npx babel src/my-class.jsx --presets react-app/prod \
            | npx terser -c -m -o my-class.min.js
  4. Reactコンポーネントの組み込み
    • 組み込まれるWebサイトのHTMMLの編集
      <html>
      <head>
      <link rel="stylesheet" href="my-class.css"> <!-- ⓵ -->
      </head>
      <body>
        <!-- Reactコンポーネントの挿入位置 -->
        <div id="<<div-tag-id>>"></div>  <!-- ② -->
      
        <!-- ... 既存の HTML ... -->
        ...
      
        <!-- Load React. -->
        <!-- Note: when deploying, replace "development.js" with "production.min.js". -->
      <!--
        <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
        <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
      -->
        <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script> <!-- ⓷ -->
        <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script> <!-- ⓸ -->
      
        <!-- Load our React component. -->
        <script src="my-class.min.js"></script> <!-- ⑤ -->
      </body>
      </html>

      [組み込む側のHTMLファイル]

      備考

      組み込まれる Reactコンポーネントのファイル名は、後述の手順で圧縮した JSファイルを指定する。

    • 組み込むReactファイルの編集
      //import React from 'react'; //⓵
      //import ReactDOM from 'react-dom/client'; //⓵
      //import './my-class.css'; //⓵
      
      class MyClass extebds React.Component {
        ...
      }
      
      <!-- 指定されたIDのタグの内部にReactコンポーネントを表示する -->
      const root = ReactDOM.createRoot(document.getElementById("root")); //②
      root.render(<Game />); //⓷

      [my-class.jsx]

React topics

npm test command
  • --watchAll オプション

    npm test コマンドを実行すると、package.json の設定により 「react-scripts test」が実行される。しかしこのコマンドは対話モードで 動くため maven 実行時に止まってしまう。これを抑止するためには、--watchAll オプションに「false」を指定する。

  • --coverage オプション

    「react-scripts test」コマンドは、既定値では coverage レポートを出力しない。 coverage レポートを出力する場合は、「--coverage」オプションを設定する。

  • HTML形式のテスト・レポート出力
    1. jest-html-reporters パッケージのインストール

      package.json ファイルが配置されたディレクトリで以下のコマンドを実行し、 jest-html-reporters パッケージをインストールする。

      $ npm install --save-dev jest-html-reporters
    2. package.json の編集

      package.json に以下の内容を追加する。

      {
        ...
        "jest": {
          "reporters": [
            "default",
            [
              "jest-html-reporters",
              {
                "hideIcon": true,
                "pageTitle": "test report",
                "publicPath": "./src/__tests__/test-reports",
                "filename": "test-report.html",
                "expand": true
              }
            ]
          ]
        },
        ...
      }

これらの設定を package.json ファイルに反映すると、以下のようになる。

{
  ...
  "scripts": {
    ...
    "test": "react-scripts test --watchAll=false --coverage",
    ...
  },
  "jest": {
    "reporters": [
      "default",
      [
        "jest-html-reporters",
        {
          "hideIcon": true,
          "pageTitle": "test report",
          "publicPath": "./src/__tests__/test-reports",
          "filename": "test-report.html",
          "expand": true
        }
      ]
    ]
  },
  ...
}
Testing no exported functions
  • react-app-rewired、customize-cra パッケージのインストール
    1. react-app-rewired パッケージのインストール

      以下のコマンドを実行して、react-app-rewired パッケージをインストール する。

      $ npm install --save-dev react-app-rewired
    2. config-overrides.js ファイルの作成と編集

      package.json ファイルが配置されたディレクトリで以下のコマンドを実行し、 「config-overrides.js」ファイルを作成する。

      $ touch config-overrides.js

      なお、このファイルは後でカスタマイズ用のパッケージをインストールした際に その設定をするために編集し直す。

    3. package.json の編集

      package.json ファイルの 「{"scripts": {...}」の"start"、"build"、 "test"のそれぞれについて、「react-scripts」を「react-app-rewired」に 書き換える。

      • 変更前
        {
          "scripts": {
            "start": "react-scripts start",
            "build": "react-scripts build",
            "test": "react-scripts test --watchAll=false --coverage",
            "eject": "react-scripts eject"
          },
        }
      • 変更後
        {
          "scripts": {
            "start": "react-app-rewired start",
            "build": "react-app-rewired build",
            "test": "react-app-rewired test --watchAll=false --coverage",
            "eject": "react-scripts eject"
          },
        }
    4. customize-cra パッケージのインストール

      以下のコマンドを実行して customize-cra パッケージをインストールする。

      $ npm install --save-dev customize-cra
  • babel-plugin-rewire のインストール
    1. babel-plugin-rewire パッケージのインストール

      babel-plugin-rewire のインストール手順に従って、babel-plugin-rewire パッケージのインストールと babel.config.json ファイルの設定をする。

      $ npm install --save-dev babel-plugin-rewire
    2. config-overrides.js ファイルの編集

      package.json ファイルが配置されたディレクトリに存在する config-overrides.js に以下の内容を記述する。

      // Overrides create-react-app webpack configs without ejecting
      // https://github.com/timarney/react-app-rewired
      
      const { useBabelRc, override } = require("customize-cra");
      module.exports = override(useBabelRc());
  • 参考文献

Topics

node_modules ディレクトリーからのモジュールの読み込み

require 関数に渡されたモジュール名が、コアモジュールではなく、かつ 「/」、 「../」、「./」以外では今る場合(モジュール名そのものを渡した場合)は、 以下のアルゴリズムでもユールを検索する。

  1. カレント・ディレクトリー配下の「node_modules」ディレクトリーを探す
  2. 見つからない場合は、1つ上のディレクトリーの配下にある「node_modules」 ディレクトリーを探す。見つからない場合は最上位のディレクトリーに達するまで これを繰り返す。
参考文献

Maven Project

POM

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>ycookjp.myproject.nodejs.packages</groupId>
  <artifactId>mypackage</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>pom</packaging>
  <description>Node.js My Package</description>
  <name>Node.js My Package</name>
  <properties>
    <p.sep>${path.separator}</p.sep>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven-site.ver>3.12.1</maven-site.ver>
    <maven-project-info-reports.ver>3.4.1</maven-project-info-reports.ver>
    <maven-assembly.var>3.4.2</maven-assembly.var>
    <maven-resources.ver>3.3.0</maven-resources.ver>
    <maven-antrun.ver>3.1.0</maven-antrun.ver>
    <exec-maven-plugin.ver>3.1.0</exec-maven-plugin.ver>
    <maven-clean.ver>3.2.0</maven-clean.ver>
    <NPMEXE>npm</NPMEXE>
    <PROJECT_NAME>${project.artifactId}</PROJECT_NAME>
    <MAIN_PATH>${project.build.directory}/build-tmp/main</MAIN_PATH>
    <TEMP_PATH>${project.build.directory}/build-tmp/tests</TEMP_PATH>
  </properties>
  <!-- 
   - To generate test report, run "mvn clean test site"
   -->
  <build>
    <pluginManagement>
      <plugins>
        <!-- Basic report creation.  -->
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-site-plugin</artifactId>
          <version>${maven-site.ver}</version>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>${maven-project-info-reports.ver}</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>

      <!-- cleaning files -->
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>${maven-clean.ver}</version>
        <configuration>
          <filesets>
            <fileset>
              <directory>${basedir}/src/main</directory>
              <includes>
                <include>**/__tests__/coverage/</include>
                <include>**/__tests__/test-reports/</include>
                <include>**/node_modules/</include>
                <include>**/test-report.html</include>
              </includes>
              <followSymlinks>false</followSymlinks>
            </fileset>
          </filesets>
        </configuration>
      </plugin>

      <!-- copying scriptss -->
      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>${maven-resources.ver}</version>
        <executions>

          <!-- copying main files -->
          <execution>
            <id>copy-main-files</id>
            <phase>test</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${MAIN_PATH}</outputDirectory>
              <resources>
                <resource>
                  <directory>${basedir}/src/main/${PROJECT_NAME}</directory>
                  <excludes>
                    <exclude>**/node_modules/**</exclude>
                    <exclude>**/package-lock.json</exclude>
                    <exclude>**/__tests__/coverage/**</exclude>
                    <exclude>**/__tests__/test-reports/**</exclude>
                  </excludes>
                </resource>
              </resources>
            </configuration>
          </execution>

          <!-- copying test files for generting api docs -->
          <execution>
            <id>copy-test-files</id>
            <phase>test</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${TEMP_PATH}</outputDirectory>
              <resources>
                <resource>
                  <directory>${basedir}/src/main/${PROJECT_NAME}/__tests__</directory>
                  <excludes>
                    <exclude>coverage/**</exclude>
                    <exclude>test-reports/**</exclude>
                  </excludes>
                </resource>
              </resources>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- Generating test reports -->
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>${exec-maven-plugin.ver}</version>
        <executions>
          <!-- Installing main dependency modules -->
          <execution>
            <id>install-packages</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${NPMEXE}</executable>
              <workingDirectory>${MAIN_PATH}</workingDirectory>
              <commandlineArgs>install</commandlineArgs>
            </configuration>
          </execution>

          <!-- Installing jsdoc and license-checker package -->
          <execution>
            <id>install-jsdoc</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${NPMEXE}</executable>
              <workingDirectory>${MAIN_PATH}</workingDirectory>
              <commandlineArgs>install --save-dev jsdoc license-checker</commandlineArgs>
            </configuration>
          </execution>

          <!-- Generating API document -->
          <execution>
            <id>nodejs-apidocs</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${MAIN_PATH}/node_modules/.bin/jsdoc${cmd_suffix}</executable>
              <workingDirectory>${MAIN_PATH}</workingDirectory>
              <commandlineArgs>. -d ${project.build.directory}/site/apidocs</commandlineArgs>
            </configuration>
          </execution>

          <!-- Generating test spec document -->
          <execution>
            <id>nodejs-testspecs</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${MAIN_PATH}/node_modules/.bin/jsdoc${cmd_suffix}</executable>
              <workingDirectory>${TEMP_PATH}</workingDirectory>
              <commandlineArgs>. -d ${project.build.directory}/site/testspecs</commandlineArgs>
            </configuration>
          </execution>

          <!-- Generating licenses -->
          <execution>
            <id>nodejs-dependencies</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${MAIN_PATH}/node_modules/.bin/license-checker${cmd_suffix}</executable>
              <workingDirectory>${MAIN_PATH}</workingDirectory>
              <commandlineArgs>--production --out ${project.build.directory}/site/node-dependencies.txt</commandlineArgs>
            </configuration>
          </execution>

          <!-- Generating test result and coverage report -->
          <execution>
            <id>nodejs-test</id>
            <phase>test</phase>
            <goals>
              <goal>exec</goal>
            </goals>
            <configuration>
              <executable>${NPMEXE}</executable>
              <workingDirectory>${MAIN_PATH}</workingDirectory>
              <arguments>
                <argument>test</argument>
              </arguments>
              <successCodes>
                <!-- 
                  Continue generating reports even if unit test fails.
                 -->
                <successCode>0</successCode>
                <successCode>1</successCode>
              </successCodes>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <plugin>
        <artifactId>maven-resources-plugin</artifactId>
        <version>${maven-resources.ver}</version>
        <executions>

          <!-- copuing test reports to site directory -->
          <execution>
            <id>copy-reports</id>
            <phase>site</phase>
            <goals>
              <goal>copy-resources</goal>
            </goals>
            <configuration>
              <outputDirectory>${project.build.directory}/site</outputDirectory>
              <resources>
                <resource>
                  <directory>${MAIN_PATH}/__tests__</directory>
                  <includes>
                    <include>coverage/**</include>
                    <include>test-reports/**</include>
                  </includes>
                </resource>
              </resources>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- Replace file path in coverage report -->
      <plugin>
        <artifactId>maven-antrun-plugin</artifactId>
        <version>${maven-antrun.ver}</version>
        <executions>
          <execution>
            <phase>site</phase>
            <goals>
              <goal>run</goal>
            </goals>
            <configuration>
              <failOnError>false</failOnError>
              <target>
                <replaceregexp match='[-_#$%()+=@0-9a-zA-Z\^`\[\]{}\/\\]*[\/\\]*target[\/\\]*build-tmp[\/\\]*main[\/\\]*' replace="" encoding="UTF-8" byline="true" flags="g">
                  <fileset dir="${project.build.directory}/site/coverage" includes="**/*"/>
                  <fileset dir="${project.build.directory}/site/test-reports" includes="**/*"/>
                  <fileset file="${project.build.directory}/site/node-dependencies.txt"/>
                </replaceregexp>
              </target>
            </configuration>
          </execution>
        </executions>
      </plugin>

      <!-- Archiving source script files -->
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>${maven-assembly.var}</version>
        <configuration>
          <descriptors>
            <descriptor>src/assenbly/distribution.xml</descriptor>
          </descriptors>
          <finalName>${project.artifactId}-${project.version}</finalName>
          <outputDirectory>${project.build.directory}/site</outputDirectory>
          <appendAssemblyId>false</appendAssemblyId>
        </configuration>
        <executions>
          <execution>
            <id>distribution</id>
            <phase>site</phase>
            <goals>
              <goal>single</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-project-info-reports-plugin</artifactId>
        <version>${maven-project-info-reports.ver}</version>
      </plugin>
    </plugins>
  </reporting>
  <profiles>
    <profile>
      <id>profile-unix</id>
      <activation>
        <property>
          <name>file.separator</name>
          <value>/</value>
        </property>
      </activation>
      <properties>
        <cmd_suffix></cmd_suffix>
      </properties>
    </profile>
    <profile>
      <id>profile-win</id>
      <activation>
        <property>
          <name>file.separator</name>
          <value>!/</value>
        </property>
      </activation>
      <properties>
        <cmd_suffix>.cmd</cmd_suffix>
      </properties>
    </profile>
  </profiles>
</project>

[pom.xml]

ファイルの配置

<basedir>
  |- pom.xml
  `- src
      |- assembly
      |   `- distribution.xml
      |- main
      |   `- <module-name>
      |       |- __test__
      |       |    `- <test-scripts>
      |       |- <source-scripts>
      |       |- jest.config.json
      |       |- package.json
      |       `- package-lock.json
      `- site
          `- site.xml