webpack 入門 ~ Babel, Polyfill を使って快適 ES6 ライフ ~

目次

はじめに

kintoneのJavaScriptカスタマイズを開発しているときに、誰しも "Internet Explorer 11で動かない!" ことを体験したことがあると思います。
こういった特定のブラウザーでプログラムが動作しない問題を解決するためにBabel, Polyfill, webpackというツールを利用するのがスタンダードな解決策になっています。
本記事ではこの3つのツールをkintoneカスタマイズで利用する方法を紹介します。

チュートリアルで扱うnode, npm, npxコマンドは https://nodejs.org/ (External link) でインストーラーをダウンロードしてnode.jsをインストールすると自動的にインストールされます。
インストール方法、node, npm, npxコマンドが何を意味しているかは本記事では取り扱いません。

Babel と Polyfill について

JavaScriptは日々進化しており、ES5, ES6(ES2015), ES2016といったバージョンがあることはご存じでしょうか?
JavaScriptの進化には2つの側面があります。
ひとつはプログラミング言語の拡張で、もうひとつは標準ライブラリの拡張です。
しかし、各ブラウザー間でサポートされる機能が異なってしまいます。
参考: ES6 のブラウザ間の実装状況 (External link)

プログラミング言語の拡張

たとえばES6のJavaScriptではテンプレート文字列という文法を利用できます。
文字列の中で変数を展開できるだけでなく、文字列中に改行が含まれても大丈夫になります。

1
2
3
4
5
6
const es6Name = 'john';
console.log(`hello ${es6Name} . nice to meet you`);

// ES5
const name = 'john';
console.log('hello ' + name + ' . nice to meet you');

プログラムが簡潔にかけて気持ちいいですね!
しかし、このテンプレート文字列はInternet Explorer 11では動作せず、JavaScriptを解釈する時点でエラーになってしまいます。

こういった問題を解決するのが Babel (External link) です。
ES6のコードをES5で動作するようにコードを変換してくれます。
コード変換の動作はBabelの公式サイトで確認できます。

標準ライブラリの拡張

文法の進化だけでなく、JavaScriptのビルトインオブジェクトライブラリも進化しています。

たとえばES6にはObject.valuesという便利メソッドが追加されています。

1
2
const object = {a: 'sample', b: 42, c: false};
console.log(Object.values(object)); // output: ["sample", 42, false];

ですがこれもInternet Explorer 11では未実装のため動作しません。
こういったブラウザーごとの実装・未実装を埋めてくれるのがPolyfillです。

Polyfillは未実装のメソッドを見つけると、Polyfillライブラリが読み込まれた時点で実装を追加してくれます。
そのため、Internet Explorer 11などの環境でもObject.valuesを利用できます。
BabelでPolyfillを利用するには、 @babel/preset-env (External link) core-js (External link) を使います。

webpack について

webpack (External link) はJavaScriptのビルドツールです。
JavaScriptをブラウザーで動かすために必要なライブラリをバンドルしたり、プログラミング言語の変換をします。

webpackはES6で導入された import (External link) , export (External link) を解釈して、必要なライブラリやモジュールをバンドルしてくれます。

本記事ではwebpackの中にBabelとPolyfillを組み込んで動作する例を解説します。
これで最低限のツールの知識は説明し終えたのでチュートリアルにトライしてみましょう。

チュートリアル

ES6の文法を使ってkintoneカスタマイズの実装をしてみましょう。

Step1 : npm を使ってプロジェクトを初期化する

1
npm init

以後の作業はプロジェクト・ディレクトリーで作業するものとします。

Step2 : webpack, Babel などのツールをインストールする

1
2
npm install -D webpack webpack-cli webpack-dev-server \
                        babel-loader @babel/core @babel/preset-env core-js@3
  • webpack ... webpackの本体
  • webpack-cli ... コマンドラインからwebpackを利用するためのツール
  • webpack-dev-server ... 開発中プログラムをローカルホスト上でホスティングしてくれる開発ツール
  • babel-loader ... Babelのwebpackプラグイン
  • @babel/core ... Babelの本体
  • @babel/preset-env ... BabelのJavaScriptの変換ツール
  • core-js ... JavaScriptの標準ライブラリが定義されておりPolyfillを組み込んで利用できる。

Step3 : webpack.config.js を配置する

npm initしたのと同じディレクトリーにwebpack.config.jsを配置します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const path = require('path');

module.exports = {
  entry: {
    'kintone-create-edit-show': './src/kintone-create-edit-show.js'
  },
  // webpack 5 を利用していて、IE 対応する場合は以下のコメントを外す
  // target: ['web', 'es5'],
  module: {
    rules: [
      {
        test: /\.m?js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: 'usage',
                  corejs: 3
                }
              ]
            ]
          }
        }
      }
    ]
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  },
  externals: {
    jquery: 'jQuery'
  }
};
webpack.config.js の設定項目

kintoneカスタマイズする上で最低限知っておくと良さそうな設定項目を紹介します。
もっと複雑なこともできますが、詳細は webpack のドキュメント (External link) を参照してください。

entry

JavaScriptのエントリーポイントを指定します。
kintoneカスタマイズの場合、kintone.events.onメソッドが書いてあるプログラムになります。
オブジェクトを設定し、サンプルプログラムだと、kintone-create-edit-showのエントリーポイントを作っています。

target

ビルド後のファイルがどの環境に向けたファイルかを指定します。
指定しない場合、デフォルトで ['web']が設定されています(参照: target (External link)
ただし、webpack 5でビルドした場合、Internet Explorerに対応していない構文が出力されます。
webpack 5でInternet Explorerに対応する場合には、['web', 'es5']を指定します(上記サンプルのコメントを外してください)。

module

JavaScriptの変換ルールを書きます。
testの中で指定されている正規表現にマッチした場合、Babelの変換プログラムが動作します。
今回の場合は、.js, mjsにマッチするファイルが読み込まれた場合、Babelによる自動変換の対象として設定しています。

output

ビルドしたJavaScriptを出力するディレクトリーを設定します。
pathは出力先のディレクトリー、filenameはファイル名です。
pathがわかりにくいですが、package.jsonが配置されているのと同じディレクトリーにdistというディレクトリーが作られて、その下にビルドしたJavaScriptが配置されます。
filenameの [name]ですが、entryで指定したキー名をファイル名として文字列を自動的に設定してくれます。

externals

kintoneのJSカスタマイズではアップロードできるファイルの大きさに制限があります。
一方で、webpackは利用しているライブラリをひとつのファイルにまとめます。
このため、webpackでビルドしたファイルは大きくなりやすい特徴があるため注意してください。
jQueryなどグローバル変数を定義するタイプのライブラリなどをexternalsに設定しておくと、webpackはjQueryがソースコードでimportされていても無視してくれます。

Step4 : ES6 を使って JS カスタマイズを書いてみよう!

サンプルプログラムではES6で導入された文法やライブラリを使った簡単なプログラムを書いています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
import jQuery from 'jquery';
const events = [
  'app.record.create.show',
  'app.record.edit.show',
];
kintone.events.on(events, (ev) => {
  const el = kintone.app.record.getHeaderMenuSpaceElement();
  const hello = 'hello';
  const world = 'world!';
  const message = {
    hello,
    world,
  };
  const copied = Object.assign({}, message);
  jQuery(el).append(`<div>${copied.hello} ${copied.world}!</div>`);
});

作業フォルダー内に「src」フォルダーを用意し、「kintone-create-edit-show.js」というファイル名で保存してください。
webpack.config.jsのentryポイントと合わせてください。

Step5 : ビルドしてみよう!

次のコマンドを実行するとwebpackがJavaScriptをビルドしてくれます。

1
2
3
npx webpack --mode development # 開発
# リリース時は次のコマンドで圧縮なども実施してくれる
# npx webpack --mode production  

--mode developmentproductionが指定可能です。開発中はdevelopmentを指定します。
ビルドが完了するとdistディレクトリーにkintone-create-edit-show.jsが作成されているので、アップロードして動作確認してみましょう。

webpack-dev-serverというツールもあります。これは別記事で解説させていただきます。

Step6 : アップロードしてみよう

ビルドしたプログラムをkintoneにアップロードしてみましょう。
kintone-create-edit-show.jsをアップロードします。
jQueryを別途カスタマイズとして登録するのを忘れないようにしてください。

Internet Explorerでも動作するのがわかると思います。

Chromeブラウザーのコンソールから、webpackでビルドしたプログラムを確認してみましょう。
テンプレート文字列が変換されているのを確認できると思います。

Step7 : import、export を体験してみよう

全角半角を変換するオープンソースライブラリをnpm installでインストールしてimport, exportを使って実装してみます。

1
npm install moji

全角半角を変換する実装を作成、exportしてみます。(src/hankaku.js)

1
2
import moji from 'moji';
export const zenkakuToHankaku = (value) => moji(value).convert('ZE', 'HE').toString();

kintone.events.onを書くファイルでimportします。(src/kintone-create-edit-submit.js)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import {zenkakuToHankaku} from './hankaku';

const events = [
  'app.record.create.submit',
  'app.record.edit.submit'
];
kintone.events.on(events, (ev) => {
  if (ev.record.文字列__1行_.value) {
    ev.record.文字列__1行_.value = zenkakuToHankaku(ev.record.文字列__1行_.value);
  }
  return ev;
});

webpack.config.jsを修正する必要があります。サンプルコードのリポジトリ(後述)にあるので割愛します。

再度ビルドすると2つのファイルが作成されます。

  • 新規レコード、レコード修正画面を開いたときのファイル
  • 追加・更新時のイベント処理用ファイル

全角を半角に変換するメソッドは利用しているライブラリと一緒にイベント処理用のファイルの中にバンドルされています。

チュートリアルは以上です。お疲れさまでした。

参考: サンプルコード (External link)

注意点: Proxy だけには注意しましょう

Babelの制限事項として次のようなものがあります。

Due to the limitations of ES5, Proxies cannot be transpiled or polyfilled. See support in various JavaScript engines (External link) .( Babel の公式サイトから引用 (External link)

ES5から使えるProxyだけは制限事項になっています。
このためInternet Explorer 11ではProxyを利用していると原因でエラーになってしまいます。
webpackを使うことでオープンソースのライブラリを使いやすくなりますが、ライブラリを利用する際は、念のためサポートブラウザーを一度確認してから使うようにしましょう。

おまけ:最近はこんな書き方ができるようになってます!

モダンなJavaScriptからお気に入り機能を紹介して終わりたいと思います。

const, let

  • ブロックスコープ内でconstを使って宣言された変数は、書き換えるとエラーになります。
  • ブロックスコープ内でletを使って宣言された変数は、書き換えできます。

ブロックスコープを外れるとその変数は参照できなくなります。

参考: const (External link) , let (External link)

テンプレート文字列

改行や変数の埋め込みをしやすい文法が使えるようになっています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
const message = 'hello world';
`
This is string template.
${message}.
`;
// output:
//
// This is string template.
// hello world.
//

参考: テンプレートリテラル (テンプレート文字列) (External link)

export, import

モジュール機能を実現するために導入された文法です。JavaScriptでモジュール機能が使えます。
グローバルにメソッド定義するのを避けつつモジュール機能を利用できます
kintoneカスタマイズの場合はwebpackを使ってビルドするようにしましょう。

export
1
2
3
4
// functions.js
export function sum(a, b) {
  return a + b;
}
import
1
import {sum} from './functions';

参考: export (External link) , import (External link)

分割代入

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
{
    const [a, b] = [10, 20];
    console.log(a); // 10
    console.log(b); // 20
}
{
    const [a, b, ...rest] = [10, 20, 30, 40, 50];
    console.log(a); // 10
    console.log(b); // 20
    console.log(rest); // [30, 40, 50]
}
{
    const ({ a, b } = { a: 10, b: 20 });
    console.log(a); // 10
    console.log(b); // 20
}

配列もしくはオブジェクトのプロパティの一部の値を簡単に取り出せるようになりました。

参考: 分割代入 (External link)

オブジェクト初期化子

今まではオブジェクトのキー名を必ず渡す必要がありましたが、変数をそのままオブジェクトのリテラルの中にわたすと、そのままオブジェクトのプロパティとして適用してくれます。

1
2
3
4
5
6
7
8
9
const a = 1;
const b = 2;
const c = 3;
const d = {
  a,
  b,
  c,
  e: 'hello!'
};

参考: オブジェクト初期化子 (External link)

アロー関数

関数を簡潔に書けるようになりました。

1
const sum = (a, b) => a + b;

参考: アロー関数式 (External link)

おわりに

お疲れさまでした。
webpack, Babel, Polyfillを活用してJavaScript開発の面倒なところを避けつつ、快適なJavaScriptライフをお過ごしください!

このチュートリアルでは毎回ビルドしていますが更新されたJavaScriptを検知して自動的に再ビルドしてくれるしくみもあります。
開発中はこちらを使うとJavaScript更新の手間が省けます。
こちらの記事も執筆予定です。次回作にご期待ください!

information

このTipsは、2019年2月版kintoneで動作を確認しています。