webpackを利用するkintoneカスタマイズ開発の流れ

# はじめに
「[webpackを利用するkintoneプラグイン開発の流れ](https://qiita.com/yamaryu0508/items/fa68fb83dabd04fae3cc)」でも触れていますが、kintone界隈の開発手法・ツールの利用についても最近色々とツール拡充がなされ、いわゆるモダンな開発方法というのも取り込みやすくなってきました。

kintoneのカスタマイズ開発で既に webpack を利用されている方も多いと思いますが、今回は`webpack`と `@kintone/customize-uploader`を用いたカスタマイズ開発の流れを見ていきたいと思います。

## 修正点
- 2019.9.1 - Babel 7.4.0 における [@babel/polyfill 非推奨](https://babeljs.io/docs/en/next/babel-polyfill.html)を受けて、修正

# 大まかな流れ
1. `npm init -y`でプロジェクトを開始する
2. webpack関連で必要なモジュールをインストールする
3. `@kintone/customize-uploader`のインストールと設定を行う
4. webpackと`@kintone/customize-uploader`のwatchオプションを共存させる

詳しく見ていきましょう。

# プロジェクトを開始する

カスタマイズ対象アプリが１つの簡単なケースをnpmのプロジェクトとして新しく始める流れを考えたいと思います。

プロジェクトフォルダ（今回の例は`new-project`）を作成・移動して、npmプロジェクトを開始します。

```
mkdir new-project; cd new-project
npm init -y
```

# webpack関連のモジュールをインストールする

## webpack

まず、`webpack`と`webpack-cli`をインストールします。

```
npm install --save-dev webpack webpack-cli
```

## ES6

webpackを利用するカスタマイズではES6使いたい意図が含まれることが多いので、ES6関連のパッケージをインストールします。ES6で書いてもkintone対応ブラウザのIE11にも対応できるように、 `core-js`、 `regenerator-runtime` を利用します（`async/await`も利用できるようにしておきます）。

```
npm install --save-dev babel-loader @babel/core @babel/preset-env
npm install --save-dev core-js regenerator-runtime
```

## webpack.config.jsを準備する

```js:webpack.config.js
const path = require('path');

module.exports = {
  mode: "development",

  entry: {
    "customize": "./src/js/customize.js"
  },

  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist', 'js'),
  },

  resolve: {
    extensions: ['.js', '.json']
  },

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader', // https://webpack.js.org/loaders/babel-loader/#root
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
};
```

この設定によって、`src/js/customize.js`のエントリーから`dist/js/customize.js`のバンドルファイルが生成されるイメージで、次のようなフォルダ・ファイル構成になります。

```
new-project
├── dist/js/customize.js
├── package-lock.json
├── package.json
├── src/js/customize.js
└── webpack.config.js
```

また、この時点でのpackage.jsonはこのような感じになります。`scripts`に webpack の操作を追加しています。`npm run build`が`webpack`のショートカットになる、といった具合ですね。
また、webpackはwatchオプションでエントリの変更検知が走りますし、バンドルのリードタイムが都度ビルドより速いことが知られています。

```json:package.json
{
  "name": "new-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "develop": "npm run build -- --watch",
    "build": "webpack",
    "build:prod": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "babel-loader": "^8.0.6",
    "core-js": "^3.2.1",
    "regenerator-runtime": "^0.13.3",
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.7"
  }
}
```

# @kintone/customize-uploaderのインストールと設定を行う

バンドルファイルをkintoneに適用する方法としては、ローカルWebサーバーを立ち上げたり色々な方法が取られていると思いますが、今回は`@kintone/customize-uploader`を利用する方法を示していきます。

## @kintone/customize-uploaderのインストール

```
npm install --save-dev @kintone/customize-uploader
```

## @kintone/customize-uploaderの初期設定

```
$(npm bin)/kintone-customize-uploader init
# dest/cutomize-manifest.json が生成される
```

生成された`dest/cutomize-manifest.json`の`desktop.js`に、バンドルファイルである`dist/js/customize.js`を指定します。

```json:dest/cutomize-manifest.json
{
    "app": "599",
    "scope": "ALL",
    "desktop": {
        "js": [
            "dist/js/customize.js"
        ],
        "css": []
    },
    "mobile": {
        "js": []
    }
}
```

`@kintone/customize-uploader`も`watch`オプションを持っていますので、`package.json`の`scripts`に`upload`を足して使いやすくしておきます。これで、`dest/customize-manifest.json`で指定されたファイルの変更に合わせたアップロードがかかるようになります。

```json:package.json
{
  "name": "new-project",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "upload": "kintone-customize-uploader --watch dest/customize-manifest.json",
    "develop": "npm run build -- --watch",
    "build": "webpack",
    "build:prod": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "@kintone/customize-uploader": "^2.0.4",
    "babel-loader": "^8.0.6",
    "core-js": "^3.2.1",
    "npm-run-all": "^4.1.5",
    "regenerator-runtime": "^0.13.3",
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.7"
  }
}
```

# webpackと@kintone/customize-uploaderのwatchオプションを共存させる

ここまで来ると、watchによる処理がwebpackと@kintone/customize-uploaderによって2つ存在していることに気付きます。

1 webpackでエントリファイルの変更に応じてバンドル処理が走りバンドルファイルが生成される
2 バンドルファイルの変更に変更があった際にkintoneにアップロードする

更にこれらを共存できれば、エントリファイルを変更した際にバンドルが走ってkintoneにアップロードされるといった処理の一連化され、更に開発効率が上がってきます。

これは、`@kintone/create-plugin`で利用されている`npm-run-all`というパッケージを利用すれば、同じように対応することが可能です。

まず、パッケージをインストールします。

```
npm install --save-dev npm-run-all
```

そして、`@kintone/create-plugin`と同じく`scripts/npm-start.js`を準備します。

```js:scripts/npm-start.js
"use strict";
const runAll = require("npm-run-all");

runAll(["develop", "upload"], {
  parallel: true,
  stdout: process.stdout,
  stdin: process.stdin
}).catch(({results}) => {
  results
    .filter(({code}) => code)
    .forEach(({name}) => {
      console.log(`"npm run ${name}" was failed`);
    })
  ;
});
```

合わせて、これを実行しやすくするために`package.json`の`scripts`を追加します。`@kintone/create-plugin`と同じ体験にするために、`start`として追加します。

```json:package.json
{
  "name": "kintone-customize-boilerplate",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node scripts/npm-start.js",
    "upload": "kintone-customize-uploader --watch dest/customize-manifest.json",
    "develop": "npm run build -- --watch",
    "build": "webpack",
    "build:prod": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "@kintone/customize-uploader": "^2.0.4",
    "babel-loader": "^8.0.6",
    "core-js": "^3.2.1",
    "npm-run-all": "^4.1.5",
    "regenerator-runtime": "^0.13.3",
    "webpack": "^4.39.3",
    "webpack-cli": "^3.3.7"
  }
}
```

これで、`npm run start`でエントリファイルの変更時にバンドルとkintoneへのファイルアップロードが都度行われるようになり、開発も捗る状態かと思います。

ちなみに、この時点でのフォルダ構造を確認しておくと、次の通りです。

```
new-project
├── dest
├── dist
├── node_modules
├── package-lock.json
├── package.json
├── scripts
├── src/js/customize.js
└── webpack.config.js
```

今回のエントリファイルである`src/js/customize.js`を例えばこのような状態から、色々書き換えてみてください。

```js:src/js/customize.js
import "core-js/stable";
import "regenerator-runtime/runtime";


kintone.events.on('app.record.detail.show', event => {
    alert('Hello, webpack');
    return event;
});
```

変更すると、バンドルとアップロードが走るはずです。

# まとめ
webpackを利用するkintoneカスタマイズ開発の流れについて見てきました。全体に言えることは、フォルダ・ファイル構成についてのベストプラクティスは対象が複数のアプリになったり状況によって変わってきますので、今回の記事はいち例として参考になればと思います（自分も実際にはESLintが入っていたり、複数アプリを対象にするため、少々複雑な構成を扱っています）。

webpackの設定については、CSSを同時にバンドルしたい、Reactを使いたいといった内容に合わせて昇華してもらえれば良いかと思います。これもケースバイケースだと思います。

kintoneへのカスタマイズ適用については、`@kintone/customize-uploader`でファイルをアップロードするのか、Webサーバーを利用するのか等は自分は好みの領域かと思っています（ローカルサーバーを立てるのに慣れている人はそうすれば良いと思いますし、証明書発行等色々設定増やしたくない人は今回の方法でも良いでしょう）。

# 参考にしたサイト等
- [webpackを利用するkintoneプラグイン開発の流れ](https://qiita.com/yamaryu0508/items/fa68fb83dabd04fae3cc)
- [create-plugin - GitHub](https://github.com/kintone/create-plugin)
- [Babel公式サイト > Presets](https://babeljs.io/docs/en/presets)
- [babel-loader - GitHub](https://github.com/babel/babel-loader)
- [webpack公式サイト > Module](https://webpack.js.org/configuration/module/)