kintoneプラグインの開発手法・ツールの利用については、最近色々とツール拡充がなされ、2015年の3月にサードパーティ開発が可能になって以来のちょっとした転換期がきているように思います。あくまでも開発手法・ツールについての話ですが・・・。
話が逸れましたが、例えばプラグインのパッケージング方法が package.sh
から @kintone/create-plugin
を用いた方法が今後メーカー推奨になるとの噂も出てきていますし、いわゆるモダンな開発方法というのも必要に応じて取り込んでいきたいものです。
kintoneのカスタマイズやプラグイン開発で webpack を利用されている方も多いと思いますが、プラグイン開発ツールとして webpack を適用するものがwebpackプラグインとして登場してきたので、今回はそれらを使った開発の流れを見ていきたいと思います。
大まかな流れ
-
@kintone/create-plugin
でプラグインの開発に必要な雛形を展開する -
@kintone/webpack-plugin-kintone-plugin
等webpack経由でのプラグインパッケージングに必要なモジュールをインストールする -
webpack.config.js
を準備する -
manifest.json
を修正する - プラグインをパッケージングする
詳しく見ていきたいと思います。
@kintone/create-plugin
で雛形を展開する
まずは、プラグイン開発に必要なフォルダ構成・ファイルの雛形を @kintone/create-plugin
で展開します。後に利用する @kintone/webpack-plugin-kintone-plugin
にはない部分(ファイル群の雛形が生成されるのも便利ですが鍵の生成が大きい)を補うために最初に実行します。
npx @kintone/create-plugin hello-webpack-plugin
設定のための対話を進め終えると、ここでは hello-webpack-plugin
というフォルダが展開されますが、この時点での構成は次の通りです。
├── node_modules/
├── package-lock.json
├── package.json
├── private.ppk
├── scripts/
└── src/
@kintone/create-plugin
によるwebpackは用いない従来のプラグイン開発が可能という状態です。
webpack関連のモジュールの追加
次にwebpackを使ったパッケージングを行うために、@kintone/webpack-plugin-kintone-plugin
とwebpackのバンドルに必要な webpack
、 webpack-cli
をインストールします。@kintone/webpack-plugin-kintone-plugin
はwebpackのpluginとして提供されています。
npm install --save-dev webpack webpack-cli @kintone/webpack-plugin-kintone-plugin
この時点で、package.json
は次のようになります。
{
"name": "hello-webpack-plugin",
"version": "0.1.0",
"scripts": {
"start": "node scripts/npm-start.js",
"upload": "kintone-plugin-uploader dist/plugin.zip --watch --waiting-dialog-ms 3000",
"develop": "npm run build -- --watch",
"build": "kintone-plugin-packer --ppk private.ppk --out dist/plugin.zip src",
"lint": "eslint src"
},
"devDependencies": {
"@kintone/plugin-packer": "^1.0.1",
"@kintone/plugin-uploader": "^2.2.0",
"@kintone/webpack-plugin-kintone-plugin": "^1.0.7",
"eslint": "^4.19.1",
"eslint-config-kintone": "^1.3.0",
"npm-run-all": "^4.1.3",
"webpack": "^4.28.2",
"webpack-cli": "^3.1.2"
}
}
webpack.config.js
を準備する
次に、webpackの設定ファイルであるwebpack.config.js
を準備します。
-
entry
は@kintone/create-plugin
で生成されたファイルを利用することにします。 -
output
は./src/js
配下にdist
フォルダを設けて、そこに出力するようにします(これがプラグインのパッケージング対象になります)。 -
plugins
では@kintone/webpack-plugin-kintone-plugin
に必要なパラメータをセットしますが、manifestJSONPath
、privateKeyPath
は@kintone/create-plugin
で生成されたファイルパスを指定します。
const path = require("path");
const KintonePlugin = require("@kintone/webpack-plugin-kintone-plugin");
module.exports = {
mode: 'development',
entry: {
desktop: './src/js/desktop.js',
config: './src/js/config.js'
},
output: {
path: path.resolve(__dirname, 'src', 'js', 'dist'),
filename: '[name].js'
},
plugins: [
new KintonePlugin({
manifestJSONPath: './src/manifest.json',
privateKeyPath: './private.ppk',
pluginZipPath: './dist/plugin.zip'
})
]
};
manifest.json
を修正する
最後のステップです。webpackでバンドルされたJSファイルをプラグインのパッケージングの設定ファイルであるmanifest.json
に指定します。今回だとjs/dist/desktop.js
といったパスになります。
{
"manifest_version": 1,
"version": 1,
"type": "APP",
"desktop": {
"js": [
"https://js.cybozu.com/jquery/3.3.1/jquery.min.js",
"js/dist/desktop.js"
],
"css": [
"css/51-modern-default.css",
"css/desktop.css"
]
},
"icon": "image/icon.png",
"config": {
"html": "html/config.html",
"js": [
"https://js.cybozu.com/jquery/3.3.1/jquery.min.js",
"js/dist/config.js"
],
"css": [
"css/51-modern-default.css",
"css/config.css"
],
"required_params": [
"message"
]
},
"name": {
"en": "hello-webpack-plugin"
},
"description": {
"en": "hello-webpack-plugin"
}
}
パッケージング
ここまでの準備が大変なのですが、これでやっとwebpackのバンドル経由でプラグインのパッケージングが可能になります。webpack.config.js
を配置した階層でwebpack
を実行すれば、webpack.config.js
で指定したpluginZipPath
の階層にプラグインのZIPファイルが生成されます。production用のコマンドは次の通りです。
$(npm bin)/webpack --mode production
package.json
のscripts
は@kintone/create-plugin
に適した形のままですので、次のようにwebpack利用が簡単になるよう自分で修正するといいと思います。
{
"name": "hello-webpack-plugin",
"version": "0.1.0",
"scripts": {
"upload": "kintone-plugin-uploader dist/plugin.zip --watch --waiting-dialog-ms 3000",
"watch": "webpack --mode development --watch",
"build:dev": "webpack --mode development",
"build:prod": "webpack --mode production",
"lint": "eslint src"
},
"devDependencies": {
"@kintone/plugin-packer": "^1.0.1",
"@kintone/plugin-uploader": "^2.2.0",
"@kintone/webpack-plugin-kintone-plugin": "^1.0.7",
"eslint": "^4.19.1",
"eslint-config-kintone": "^1.3.0",
"npm-run-all": "^4.1.3",
"webpack": "^4.28.2",
"webpack-cli": "^3.1.2"
}
}
これで、例えば$(npm bin)/webpack --mode production
はnpm run build:prod
で実行できるようになります。
ちなみに、プラグインファイルは、webpack.config.js
で指定した通り./dist/plugin.zip
として生成されています。
おまけ - ES6やReactを使いたい時
kintoneは業務システムとして利用されることが多い訳で、ES6やReactを利用したい場合にはwebpack時にBabelによるトランスパイルも実行されるようにして、IE11等モダンでないブラウザでも利用できるようにしておくのがいいでしょう。
ES6
まずは、ES6への対応を見てみましょう。まずはbabel-loader
のGitHubページを参考に、トランスパイルに必要なモジュールをインストールしましょう。webpackもそうですが、Babelも結構アップデート頻度ありそうなので、バージョンへの意識が必要そうです。執筆時点では、webpack 4.x | babel-loader 8.x | babel 7.x
です。
npm install --save-dev babel-loader @babel/core @babel/preset-env
これに伴い、webpack.config.js
のmodule.rules
に次のようにルールの追加を行います。
また、resolve.extensions
も追加しておきます。これによって、別ファイルをimport
する際に拡張子を省略できます。
const path = require("path");
const KintonePlugin = require("@kintone/webpack-plugin-kintone-plugin");
module.exports = {
mode: 'development',
entry: {
desktop: './src/js/desktop.js',
config: './src/js/config.js'
},
output: {
path: path.resolve(__dirname, 'src', 'js', 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
resolve: {
extensions: ['.js']
},
plugins: [
new KintonePlugin({
manifestJSONPath: './src/manifest.json',
privateKeyPath: './private.ppk',
pluginZipPath: './dist/plugin.zip'
})
]
};
React
まず、Reactの利用に必要なモジュールをインストールします。
npm install --save react react-dom
また、ES6の時と同じようにBabelはじめトランスパイルに必要なモジュールをインストールします。React用の@babel/preset-react
も今回必要になります。
npm install --save-dev babel-loader @babel/core @babel/preset-react
webpack.config.js
のmodule.rules
に次のようにルールの追加を行います。
const path = require("path");
const KintonePlugin = require("@kintone/webpack-plugin-kintone-plugin");
module.exports = {
mode: 'development',
entry: {
desktop: './src/js/desktop.js',
config: './src/js/config.js'
},
output: {
path: path.resolve(__dirname, 'src', 'js', 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react']
}
}
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new KintonePlugin({
manifestJSONPath: './src/manifest.json',
privateKeyPath: './private.ppk',
pluginZipPath: './dist/plugin.zip'
})
]
};
ただし、npm run build:dev
はファイルサイズが512kBを超えてエラーを吐きました。
[追記] 2019年6月のアップデートで20MBまで拡張され、React等のライブラリも導入しやすくなりました(512kB制限で出ていた下記のエラーメッセージはそのまま残しておきます)。
Error: ".desktop.js[1]" should match format "https-url", ".desktop.js[1]" file size should be <= 512KB, ".desktop.js[1]" should match some schema in anyOf
at validateManifest (/home/vagrant/workspace/hello-webpack-plugin/node_modules/@kintone/plugin-packer/src/zip.js:142:15)
at preprocessToRezip.then (/home/vagrant/workspace/hello-webpack-plugin/node_modules/@kintone/plugin-packer/src/zip.js:36:7)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
npm run build:prod
であれば収まりましたが、Reactまでを入れて1ファイルにバンドルするのはちょっと無理があるようです("まとめ"で考察します)。
ES6とReactを併用する場合
ここまでの合わせ技になりますが、慣れてないとwebpack.config.js
の書き方に迷う可能性があるので、一通り流していきましょう。
まずはモジュールのインストールです。
npm install --save react react-dom
npm install --save-dev babel-loader @babel/core @babel/preset-env @babel/preset-react
webpack.config.js
のmodule.rules
への追記は次のようになります。
const path = require("path");
const KintonePlugin = require("@kintone/webpack-plugin-kintone-plugin");
module.exports = {
mode: 'development',
entry: {
desktop: './src/js/desktop.js',
config: './src/js/config.js'
},
output: {
path: path.resolve(__dirname, 'src', 'js', 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env', '@babel/preset-react']
}
}
}
]
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: [
new KintonePlugin({
manifestJSONPath: './src/manifest.json',
privateKeyPath: './private.ppk',
pluginZipPath: './dist/plugin.zip'
})
]
};
以上がES6とReactの併用時の準備になります。
まとめ
webpackプラグインである@kintone/webpack-plugin-kintone-plugin
を用いて、webpackを利用したkintoneプラグインの開発の流れについて見てきました。
恐らくplugin-packer
の機能だと思いますが、プラグインのパッケージング時にmanifest.json
に記述がないファイルはプラグインファイルから除外されるようです(package.sh
は関係ないファイルもフォルダ中のファイルが内包されていた)。
プラグイン構成ファイルの上限である 512kB 20MB制限を満たしているかもこの時チェックしているようです。
Reactのセクションでバンドルファイルが512kB超える可能性が高いお話をしましたが、ファイル容量の超過に対する方策は主に3つかと思います。
[追記] 2019年6月のアップデートで20MBまで拡張され、React等のライブラリも導入しやすくなりましたので、バシバシ活用すると良いかと思います。
プラグインファイルに内包するのではなくてCDNから配信するwebpackのファイル分割(optimization.splitChunks
)を行う(試してません)externals
を利用して依存モジュールを外だし分割する
いずれの方法もこの開発の流れの延長で取れる方策だと思いますので、必要に応じて検討することになりそうです。
いずれにせよ、全体的な結論としてwebpackを利用するkintoneプラグインの開発は今回の流れが現状最適と言えそうです。