2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue CLI と kintone CLI の共存を探る(TypeScript 編)

Last updated at Posted at 2020-06-23

Vue CLI でセットアップしたプロジェクトで kintone CLI を利用したカスタマイズ環境を作る目論見です。
どうにかこうにか形になりました。
ざっくり書いていますので読みづらいかも知れません。

こちらは TypeScript 編です。
JavaScript 編は以下をご覧ください。

Vue CLI と kintone CLI の共存を探る(JavaScript 編)

目的

Vue CLI で作られるプロジェクトの整然さと kintone CLI で行えるカスタマイズの開発やデプロイの簡易性を両立させる。
TypeScript での開発を可能とし、@kintone/rest-api-client を利用する。
kintone UI Component は諦める。(React でしか動かないので)
場合により Vuetify の利用を検討する。

フォーマッティング・lint に関しては以下の方針。
Vetur はフォーマットを実行させず、シンタックスハイライトなどの役割に専念。
eslint は静的解析のみ担当。コードフォーマットはしない。
コードフォーマットは Prettier が実行。

前提

Vue CLI および kintone CLI がグローバルインストールされている事。

npm install -g @vue/cli
npm install -g git://github.com/kintone/kintone-cli.git

プロジェクト作成手順

Vue.js プロジェクトをセットアップする

Vue CLI でプロジェクトを開始する。

vue create vue-cli-kintone-cli-ts

以下の選択肢で進める。

? Check the features needed for your project:

  • Babel
  • TypeScript
  • Vuex
  • CSS Pre-processors
  • Linter / Formatter
  • Unit Testing

? Use class-style component synytax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Sass/SCSS (with dart-sass)
? Pick a linter / formatter config: ESLint + Prettier
? Pick additional lint features: Lint on save
? Pick a unit testing solution: Jest
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files

kintone CLI でアプリを作成する

作成されたプロジェクトを VS Code で開き、ターミナルを起動する。
kintone CLI でアプリをセットアップする。

kintone-cli create-template

? What type of app you want to create ? Customization
? Do you want to set authentication credentials ? Yes
? What is your kintone domain ? (サブドメイン).cybozu.com
? What is your kintone username ? (ユーザー名)
? What is your kintone password ? (パスワード)
? Do you use proxy ? No
? Do you want to use React ? No
? Do you want to use TypeScript ? Yes
? Do you want to use webpack ? Yes
? What is the entry for webpack ? main.ts
? What is the app name ? app
? Do you want to use @cybozu/eslint-config for syntax checking ? No
? What is the app ID ? (アプリ ID)
? What is the scope of customization ? ALL

app ディレクトリの下にソースが作成される。

開発サーバーをインストールする

この手順だとローカルプレビュー用の local-web-server がインストールされないため、手動で追加する。
現時点(2020 年 6 月)での最新版は 4.2 だが、このバージョンでは正しく動作しない模様。
kintone-cli でインストールされるものと同じバージョンの 2.6.1 をインストールする。

yarn add -D local-web-server@2.6.1

その他の関連ツールをインストールする

core-js が二重に入っている。
いったんアンインストールして最新版を追加。

yarn remove core-js
yarn add core-js

@kintone/rest-api-client, @kintone/dts-gen をインストールする。

yarn add @kintone/rest-api-client
yarn add -D @kintone/dts-gen

ESLint・Prettier の設定

以下を参考にする。
続・VSCode 上で vue ファイルに対して ESLint と Prettier が快適に動作する設定
VS Code で ESLint × Prettier のベストかも知れないプラクティス

yarn add -D eslint-config-prettier

プロジェクトルート直下の .eslintrc.js を修正

module.exports = {
  extends: [
    // --- 省略
    "prettier",
  ],
};

プロジェクトルート直下に .eslintignore ファイルを作成。
dist フォルダを追跡から除外する。

.eslintignore
**/dist

標準のフォーマッティングを無効化し、Prettier が全て担当するようにする。
.vscode/settings.json に設定を加える。

.vscode/settings.json
{
  "javascript.format.enable": false,
  "typescript.format.enable": false,
  "vetur.format.enable": false,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}

.prettierrc を作る。
設定はお好みで。

.prettierrc
{
  "semi": false,
  "singleQuote": true
}

ディレクトリ構成

プロジェクトルート直下の src 以下のファイルを app/source に移動。
app/tests/unit フォルダを作成。
残った srcpublictests は不要なので削除。

app/source/main.ts をとりあえず以下のようにする

app/source/main.ts
import Vue from "vue";
import App from "./App.vue";
import store from "./store";

Vue.config.productionTip = false;

kintone.events.on("app.record.index.show", (event) => {
  console.log("Hello from kintone CLI");

  const elem: Element = kintone.app.getHeaderSpaceElement() as Element;
  new Vue({
    store,
    render: (h) => h(App),
  }).$mount(elem);

  return event;
});

tsconfig.json の設定

プロジェクトルート直下と app の下に存在する。
プロジェクトルート直下の設定に寄せる。

app の下にある記述をプロジェクトルート直下の tsconfig.json にマージする。
この際 includepathstypeRoots のパスを調整する。
最終的には以下の通りとなる。

tsconfig.json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "experimentalDecorators": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "typeRoots": ["node_modules/@types", "**/source/*.d.ts"],
    "types": ["webpack-env", "jest"],
    "paths": {
      "@/*": ["~/*"]
    },
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  },
  "include": [
    "**/source/**/*.ts",
    "**/source/**/*.tsx",
    "**/source/**/*.vue",
    "**/tests/**/*.ts",
    "**/tests/**/*.tsx"
  ],
  "exclude": ["node_modules"]
}

app 下の tsconfig.json は削除ないしリネーム。

babel の設定

ビルドするために @babel/plugin-proposal-decorators のインストールが必要。

yarn add -D @babel/plugin-proposal-decorators

プロジェクトルート直下に babel.config.js が、 app の下に .babelrc が存在する。
プロジェクトルート直下の babel.config.jsapp/.babelrc の内容をマージする。
以下のようになる。

babel.config.js
module.exports = {
  plugins: [
    [
      "@babel/plugin-proposal-decorators",
      {
        legacy: true,
      },
    ],
    [
      "@babel/plugin-proposal-class-properties",
      {
        loose: true,
      },
    ],
    "@babel/plugin-syntax-dynamic-import",
  ],
  presets: [
    "@vue/cli-plugin-babel/preset",
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        corejs: {
          version: 3,
          proposals: true,
        },
      },
    ],
  ],
};

その後 app/.babelrc は削除ないしリネーム。

Webpack の設定

.vue ファイルをビルドするために vue-loader, vue-template-compiler, ts-loader, url-loader, file-loader をインストールする。
また webpack の設定は開発ビルドとプロダクションビルドで設定を変えたいので、webpack-merge もインストールする。
加えて、プロダクションビルドではミニファイも行うので、 terser-webpack-plugin もインストールする。

yarn add -D vue-loader vue-template-compiler ts-loader url-loader file-loader webpack-merge terser-webpack-plugin

webpack の設定は app 以下のものを使用する。
app/webpack.config.jsapp/webpack.common.js にリネームし、内容を以下のようにする。

app/webpack.common.js
const path = require("path");
const VueLoaderPlugin = require("vue-loader/lib/plugin");

module.exports = {
  entry: path.resolve(__dirname, "./source/main.ts"),
  resolve: {
    extensions: [".ts", ".tsx", ".vue", ".js"],
  },
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: `${path.basename(__dirname)}.min.js`,
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: {
          loader: "vue-loader",
          options: {
            loaders: {
              js: {
                loader: "babel-loader",
              },
            },
          },
        },
      },
      {
        test: /.ts?$/,
        exclude: /node_modules/,
        use: {
          loader: "ts-loader",
          options: {
            transpileOnly: true,
            appendTsSuffixTo: ["\\.vue$"],
            happyPackMode: false,
          },
        },
      },
      {
        test: /.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.(jpe?g|png|gif|svg|ico)(\?.+)?$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10000,
            fallback: {
              loader: "file-loader",
              options: {
                name: "img/[name].[ext]",
              },
            },
          },
        },
      },
    ],
  },
  performance: {
    maxEntrypointSize: 10000000,
    maxAssetSize: 10000000,
  },
  plugins: [new VueLoaderPlugin()],
};

開発ビルドの設定 app/webpack.dev.js は以下の通りにする。

app/webpack.dev.js
const merge = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "development",
});

プロダクションビルドの設定 app/webpack.prod.js は以下の通りにする。

app/webpack.prod.js
const merge = require("webpack-merge");
const common = require("./webpack.common.js");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = merge(common, {
  mode: "production",
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: { compress: { drop_console: true } },
      }),
    ],
  },
});

新たに app/webpack.config.js を作り、以下のようにする。
このファイルでビルドターゲットを判定して、適切なファイルをロードするようにする。

app/webpack.config.js
module.exports = (env, argv) => {
  const mode = argv.mode.includes("development") ? "dev" : "prod";
  return require(`./webpack.${mode}.js`);
};

Jest の設定

特にない。
必要に応じてプロジェクトルート直下の jest.config.js を編集すればよい。

package.json の設定

コマンドの入力を簡略化するため scripts を以下のようにする。
webpack の設定ファイルもここでコントロールする。

package.json
  "scripts": {
    "dev": "ws --port ****",
    "serve-app": "kintone-cli dev --app-name app --watch --localhost",
    "devel-app": "webpack --mode development --config app/webpack.config.js",
    "build-app": "webpack --mode production --config app/webpack.config.js",
    "deploy-app": "kintone-cli deploy --app-name app",
    "test:unit": "jest"
  },

ws --port **** は任意のポート番号。
以下の記事で解説している。
kintone CLI をざっくり試す

.gitignore の設定

これまでの流れで app/auth.json は含まれているはず。
app/dist も弾くようにする。
その上で、今後仮に app が増えても大丈夫なようにする。

以下の通り修正。

.gitignre
*/auth.json
*/dist

.vscode/settings.json は共有したいので、.vscode の行は削除する。

ここまでで開発準備は終了。
あとはひたすらに開発に注力する。

開発フェーズ

開発・テスト

実際の開発は app/source/ 以下のファイルに対して行っていく事になる。

開発モード(ローカルサーバ)で起動

yarn serve-app

ローカルサーバへの参照が kintone アプリに適用され、テストが行えるようになる。

単体テストは以下のように実行。

yarn test:unit

テストファイルは app/tests/unit/ 以下に **.spec.ts のファイル名パターンで記述する。

ビルド

yarn build-app

app フォルダの下に dist フォルダが作成されファイルがビルドされる。
ビルドしたファイルを手動で運用環境に適用したい場合に使う。
webpack.prod.js では TerserPlugin によりミニファイと console の除去が行われる。

デプロイ

yarn deploy-app

ビルドとデプロイを同時に実行するコマンド。
ビルドが実行され、終了後に運用環境にデプロイされる。

2 つめ以降のアプリのカスタマイズを作る場合

プロジェクトが複数のアプリカスタマイズで構成される場合、いくつかアプローチがある。

kintone-cli create-template を使う

kintone CLI 的には王道パターンではある。

kintone-cli create-template --app-name (新しいアプリ名)

と実行し、カスタマイズを新規で作成する。

作成されたフォルダに、既存のアプリカスタマイズのファイルをかぶせてやる。(要微修正)

この方法だと改めて依存モジュール類を再取得しに行く動作をするため、時間が掛かる上にせっかく整えた package.json がまた汚れてしまう。
core-js が二重になってしまうなど)
従って、決して良いやり方ではないと思われるが、以下の方法の方が簡単。

既存のアプリをコピーする

既に作成済みのアプリカスタマイズの構成ファイルをコピーして整えていくパターン。
以下、作成済みのアプリカスタマイズを app、 新しいアプリカスタマイズを second-app として説明する。

フォルダ・ファイル構成

プロジェクトルート直下に新しいフォルダ second-app を作成する。
その下に、source フォルダ、 tests フォルダを作成する。
second-app/source/ 以下に必要に応じて下記フォルダを作る。

  • assets
  • components
  • css
  • js
  • store

app/ の以下のファイルを second-app/ フォルダにコピーする。

  • auth.json
  • config.json
  • webpack.common.js
  • webpack.config.js
  • webpack.dev.js
  • webpack.prod.js

app/source/ の以下のファイルを second-app/source/ フォルダにコピーする。

  • global.d.ts
  • shims-vue.d.ts
  • shims-tsx.d.ts

認証情報

新しいアプリカスタマイズの認証情報が異なる場合は second-app/auth.json を編集する。

アプリカスタマイズ情報

second-app/config.json を開き、以下の部分を編集する。

second-app/config.json
{
  "appID": **, // カスタマイズを適用するアプリID
  "appName": "second-app",
  "type": "Customization",
  "scope": "ALL",
  "uploadConfig": {
    "desktop": {
      "js": ["second-app/dist/second-app.min.js"],
      "css": []
    },
    "mobile": {
      "js": ["second-app/dist/second-app.min.js"]
    }
  }
}

基本的には編集前に app となっていたものを second-app に置き換えれば良い。

package.json の修正

package.jsonscripts にコマンドを追加する。

作成済みの serve-app, devel-app,build-app,deploy-app をコピーし、app の部分を second-app に変えてやる。
合わせると以下の通りになる。

package.json
  "scripts": {
    "dev": "ws --port 8800",
    "serve-app": "kintone-cli dev --app-name app --watch --localhost",
    "devel-app": "webpack --mode development --config app/webpack.config.js",
    "build-app": "webpack --mode production --config app/webpack.config.js",
    "deploy-app": "kintone-cli deploy --app-name app",
    "serve-second-app": "kintone-cli dev --app-name second-app --watch --localhost",
    "devel-second-app": "webpack --mode development --config second-app/webpack.config.js",
    "build-second-app": "webpack --mode production --config second-app/webpack.config.js",
    "deploy-second-app": "kintone-cli deploy --app-name second-app",
    "test:unit": "jest"
  },

あとは元のアプリカスタマイズを参考に main.tsApp.vuecomponents/**.vue 等を作り込んでいく。

それなりに作業が多くオペミスが起こりやすいので注意が必要。

Vuetify を利用する場合

Vue CLI でインストールし、その成果を app 以下に移してやると言う流れ。
※この流れでは IE11 で正しく動作しない。IE11 が要件に入らない場合のみ採用できる。

vue add vuetify

インストールが始まる。
道中でプリセットの選択を求められる。
デフォルトで良い。

? Choose a preset: Deafult (recommended)

public/index.html が存在していないと最後にエラーが出るが、インストール自体は正常に行われているので問題ない。

プロジェクトルート直下の src 以下にファイルが作成される。
src/App.vueapp/source/App.vue に上書き。
src/components/HelloWorld.vueapp/source/components/HelloWorld.vue に上書き。
src/assets/Logo.svgapp/source/assets/ に移動。
src/plugins フォルダを app/source/ に移動。
src フォルダは不要なので削除。

app/plugins/vuetify.ts を以下のように修正。

app/plugins/vuetify.ts
import "@mdi/font/css/materialdesignicons.css";
import Vue from "vue";
import Vuetify from "vuetify/lib";

Vue.use(Vuetify);

export default new Vuetify({
  icons: {
    iconfont: "mdi",
  },
});

app/source/main.ts を以下のように修正する。

app/source/main.ts
import Vue from "vue";
import App from "./App.vue";
import store from "./store";
import vuetify from "./plugins/vuetify";

Vue.config.productionTip = false;

kintone.events.on("app.record.index.show", (event) => {
  console.log("Hello from kintone CLI");

  const elem: Element = kintone.app.getHeaderSpaceElement() as Element;
  new Vue({
    store,
    vuetify,
    render: (h) => h(App),
  }).$mount(elem);

  return event;
});

app/webpack.coomon.js に以下の記述を追加。

app/source/webpack.common.js
const VuetifyLoaderPlugin = require("vuetify-loader/lib/plugin");

module.exports = {
  // 省略
  module: {
    rules: [
      // 省略
      // CSS に対するルールの次に記述する
      {
        test: /\.s(c|a)ss$/,
        use: [
          'vue-style-loader',
          'css-loader',
          {
            loader: 'sass-loader',
            options: {
              implementation: require('sass'),
              sassOptions: {
                fiber: require('fibers'),
                indentedSyntax: true // optional
              }
            }
          }
        ]
      },
      // 省略
      // いちばん下に追加する
      {
        test: /\.(woff|woff2|eot|ttf)(\?.+)?$/,
        use: {
          loader: 'url-loader',
          options: {
            esModule: false,
            limit: 1000000
          }
        }
      }
    ]
  }
  plugins: [
    new VueLoaderPlugin(), // 既に記述済み
    new VuetifyLoaderPlugin(),
  ],
};

追加のライブラリをインストールする。

yarn add -D vue-style-loader fibers deepmerge @mdi/font

これで Vuetify が表示できるようになる。

雑感

Vue CLIkintone CLI を良い感じに共存させようと言う考えから始めたが、あとでライブラリを追加したり多くの設定ファイルに手を入れたりファイルを移動させたりと、結局のところ両者の良さを良い感じに活かすと言うよりはどうにかこうにか妥協点を見出したと言う形になったように思う。
とは言え、Vue.js の環境をゼロから(Vue CLI を使わずに)作成するのは今となってはもう面倒この上ないし、kintone CLI のコマンド一発でデプロイできる便利さは開発工数の削減に効果があるのは間違いなく、無理っくり感が否めない構成とは言えテンプレート化できたのは十分なメリットをもたらすのではなかろうか。

※今回の成果は近日中に GitHub にアップする予定です。

参考

VS Code に Prettier・ESLint・Stylelint を導入してファイル保存時にコードを自動整形させる方法
続・VSCode 上で vue ファイルに対して ESLint と Prettier が快適に動作する設定
VS Code で ESLint × Prettier のベストかも知れないプラクティス
kintone CLI をざっくり試す

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?