決済システムにWebComponentsを導入する

根岸未来氏(以下、根岸):こんにちは。株式会社サイバーエージェントでフロントエンドエンジニアとして働いています、根岸未来です。「私がWebComponentsオネーサンです」というタイトルで発表をさせていただきます。よろしくお願いします。

今日は、WebComponentsとPaymentRequestAPI(PRA)でAmeba Payをつくったお話をさせていただきます。まず、Ameba Payについて説明します。Ameba PayはAmebaの新しい共通決済システムです。セキュアでシンプルな決済体験を提供することを目的にしています。

Ameba Pay SDKで具体的になにを提供しているかというと、緑色のボタンです。

このボタンは決済基盤を利用するための機能を持っています。例えば、あるサービスで決済機能が必要になり、Ameba Payを導入するとしますと、次のようなフローで決済ができます。

PRA(PaymentRequestAPI)が実装されたブラウザの場合は、こんな感じで、ブラウザ側で用意された決済用のUIが使えて、サイトから離脱せずに、かつ、セキュアな決済ができます。

PRAが実装されていないブラウザの場合は、こんな感じで、決済代行会社のページに遷移するんですが、できるだけシンプルにわかりやすいページになるようにデザインし直して作らせていただいています。

Ameba Payのこれからの展望としては、いろんな決済方法を追加していこうと思っています。

採用した技術

次は、Ameba Pay SDKで採用した技術について説明させてください。CustomElementsとShadowDOMで、こんな感じでAmeba Payを実装しています。

これは一部なんですが、ライブラリを使わないでWebComponentsをそのまま使っているのが特徴です。これをいろいろな環境で動くようにするために試行錯誤があったんですが、それは最後のほうで話させていただきます。

次は、ESModulesを使っていて、ESModulesが使える環境ではこのままのJSで使ってもらって、非対応環境に向けてBabelでトランスパイルした、Rollupでバンドルしたbundle.jsを提供しています。

export・import構文そのままのsdk.jsとbundle.jsを、このような「type=”module”」と「no module」属性の仕組みを利用して読み込むファイルを振り分けています。

最後にPaymentRequestAPIなんですが、Ameba Payの説明で何回か出てきたと思います。

これは決済情報を入力するためのブラウザネイティブのUIを呼び出すためのAPIで。あまりうまく撮れませんでしたが、動画を撮ってきました。

MacのChromeだとこんな感じのUIが出てきて……ページ内で決済が完結できるというものです。

ブラウザでフォームが統一されているのでユーザーにとってもわかりやすいし、ブラウザに保存された情報が使えるのでカード情報非表示化の実現も可能です。ユーザーも、保存された情報を使うと、もうポチポチで決済が終わるので楽です。

WebComponentsをIE11・Edgeで動かすために

ここからは、今回のカンファレンスのテーマが「崖越え」とのことで、Ameba Payで大変だった、大変というか、試行錯誤したことについて話させてください。

WebComponentsをIE11・Edgeとかで動かすの大変だったという話です。IE11で、CustomElementsとShadowDOMを使っているので「-sd-ce」を使おうとしたら、IE11が「-lite」を使えという感じで「-lite」以外だとエラーを出すという感じでした。

じゃあしょうがないから全部入りの「-lite」を使おうと思って「-lite」を入れたら、Edgeさんが「-sd-ce」じゃないとエラー出すという状況で、「マジか……」って感じでした。そのため、出し分けをかきました。

IE11が、CustomElementで使っているHTMLElementがなぜかFunctionじゃなくてObjectを返してきて、コンストラクタとして使えないというエラーが出て「マジかぁ……」って感じだったんですけど、これに対しても、しょうがないので、パッチを当てることにしました。

1,025円以上では決済できない問題

次はiOS ChromeのPaymentRequest APIのバグとの戦いなんですけど。「1,025円バグ」というのと「しふ●やくバグ」というのがあって。これ私が名付けたんですけど。

「1,025円バグ」というのは、1,025円以上の決済だとPRAが動作しない事件が起きてて。

(会場笑)

これはまだ再現してて大変なんですけど、Chromiumのコードで、こんな感じで書いています。下のあの文字列の「1025」と「1024」の数字を比較すると、TRUEが入るんです。

「1024」はなにを意味しているかというと桁数を意味して作っているんですけど、「1025」は普通に数値として比較されちゃっているので、1,025円以上は決済できないという状況になっています。

一応issueを先輩が出してくれて、「status : Fixed」になっているので修正はもう行われたようなんですけど、私の端末が古いのか、ちょっとまだ昨日やった時点では「ああ、再現するな」と思いました。

次、「しふ●やくバグ」なんですけど、PRAの入力フォームで濁点が打てない事件があって。濁点の部分に顔文字が出てきて、「渋谷区」って打とうとすると「しふ●やく」ってなっちゃう感じです。

本当はあの顔のところに濁点が出るはずなんですけど、出てこなくて「しふ●やく」ってなる。

ちょっとかわいい感じなんですが、実際住所って濁点がめっちゃ多いので、世田谷区もそうだし目黒区もそうだし、住所が打てないのは致命的です。

これもまだ直っていなくて、Ameba PayではChromeはPRAは動くんですけど、対応しないことにしてリンクタイプに飛ばしています。

payment-shim.jsとの攻防

次はpayment-shim.jsとの攻防なんですけど、ChromeのプライベートモードでAmeba Payが突然動かなくなった事件があって、調査したら、このプルリクが怪しいということになりました。

これのPaymentRequestをnullにしちゃってるところがあるんですけど、Ameba Payの実装では「PaymentRequestAPIが実装されていない」というのはundefinedで判定していたので、nullだと抜け漏れて動かないとなっていました。

判定にnullをAmeba Payのほうで追加するか、shimを、nullって「nullって……」って感じだったので、直すかでGoogleのえーじさんとかと議論していたら、直してくださって、デプロイまでしてくれて、これは無事直っています。

これは直近で起きたことなんですが、iOS11.3でSafariがPRAに対応してくださったのですが、でも、payment-app、Apple Payのみに対応してて、Ameba Payはbasic-card、クレジットカード決済のみ今のところ実装しているので、PRAは動くけどAmeba Payは使えないという状況になっていて、早急にpayment-appも実装したいなって思いました。

最後に、Ameba Payというのは社内でしか使えないSDKなんですけど、社内外のいろんな人とご連携させていただいて作り上げているので、この場を借りてお礼を言いたいです。ありがとうございました。

(会場拍手)

強引にブラウザごとに分ける

司会者:根岸さん、ありがとうございました。それでは質疑応答の時間に移らせていただきます。質問のある方はいらっしゃいますでしょうか?

質問者1:お話ありがとうございます。もし話聞き逃してたら申し訳ないんですけど、IEとEdgeでpolyfillが違かったのでパッチを当てた、みたいなお話あったと思いますが、なにか具体的にどう対処するとか、そういうpolyfillが違うときにはどうしろ、みたいなことはありますか?

根岸:パッチを当てたのは別件なんですが、基本「-lite」を使って、Edgeのときだけ、基本「-lite」を使ってるんじゃないな。ええと、どうだったっけなぁ。

覚えているのは、Edgeの判定でEdge用のやつを使うのは覚えています。しかもそのスクリプトの読み込みのタイミングが、最初にやらなきゃいけなくて、document.writeでそのスクリプトを読むというちょっとしたハックがありました。本当はそれも紹介できればよかったんですが、間に合わず、すいません。

質問者1:けっこう無理やりな感じでブラウザによって分けてるって感じですか?

根岸:そうですね。

質問者1:ありがとうございます。

司会者:ありがとうございました。それではお時間なので、質疑応答の時間これで終わりにしたいと思います。それでは根岸さん、あらためまして、ありがとうございました。

(会場拍手)