Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Next.jsでIonic Reactを利用したWebサイトを開発した話とIonic / Ca...

Next.jsでIonic Reactを利用したWebサイトを開発した話とIonic / CapacitorでStripe /ionic-stripe

More Decks by Hidetaka Okamoto (Stripe)

Other Decks in Programming

Transcript

  1. 岡本 秀高 ( @hidetaka_dev ) • Stripe Developer Advocate (ex-developer

    in Digitalcube) • JavaScript / TypeScript developer • AWS / Next.js / WordPress / etc… • WordCamp Kyoto 2017 / JP_Stripes Connect 2019 / AWS Samurai 2017 / etc… • 🐈(猫フラご容赦󰢛) 2 Next.jsでIonic Reactを利用したWebサイトを開発した話 #ionic_jp
  2. https://wp-kyoto.net/ 4 Next.jsでIonic Reactを利用したWebサイトを開発した話 #ionic_jp • 忘備録 & 実験場 •

    もともとWordPressテーマ開発の実験場だったのを、 2017年ごろからSPA or Jamstack構成に • Backend: ◦ WordPress / WP API: Content API ◦ AWS: Application infrastructure ◦ AWS CDK: Infrastructure management • Frontend: ◦ Next.js: Web application framework ◦ Ionic: UI library ◦ Algolia: search form AWS Amplify: Auth
  3. できそうな書き方: pages/_app.tsx 5 Next.jsでIonic Reactを利用したWebサイトを開発した話 import '../styles/globals.css' import type {

    AppProps } from 'next/app' import { IonApp } from '@ionic/react'; function MyApp({ Component, pageProps }: AppProps) { return( <IonApp> <Component {...pageProps} /> </IonApp> ) } export default MyApp #ionic_jp
  4. next/dynamicでSSRを止める • 動的にComponentなどを importするためのライブラリ • Suspense的な使い方も可能 • SSR: falseでSSRを止めれる •

    Ionic Componentすべて これを書くのはかなり手間 9 Next.jsでIonic Reactを利用したWebサイトを開発した話 import dynamic from 'next/dynamic'; const IonApp = dynamic( async () => { const mod = await import('@ionic/react'); return mod.IonApp; }, { ssr: false } // this is what makes it work ); function MyApp({ Component, pageProps }: AppProps) { return( <IonApp> <Component {...pageProps} /> </IonApp> ) } export default MyApp #ionic_jp
  5. 別案: @ionic/coreだけを使う • IonicのComponentは Web Component • StencilのWeb Componentとして Next.js内で利用する

    • useEffectで defineCustomElements • <ion-app>など、 Web componentとしてJSXで利用 10 Next.jsでIonic Reactを利用したWebサイトを開発した話 import React, { useEffect } from 'react' import { defineCustomElements as ionDefineCustomElements } from '@ionic/core/loader'; function MyApp({ Component, pageProps }) { useEffect(() => { ionDefineCustomElements(window) }) return <p>Hello</p> } export default MyApp #ionic_jp
  6. TSXでIonic componentを利用する • JSXの型定義を拡張する • 定義さえしておけば、 ion-xタグもtsxで書ける 11 Next.jsでIonic Reactを利用したWebサイトを開発した話

    import { JSX as LocalJSX} from '@ionic/core' import { HTMLAttributes, ReactText } from 'react' type ToReact<T> = { [P in keyof T]?: T[P] & Omit<HTMLAttributes<Element>, 'className'> & { class?: string; key?: ReactText; } } declare global { export namespace JSX { interface IntrinsicElements extends ToReact<LocalJSX.IntrinsicElements> {} } } #ionic_jp
  7. @ionic/core利用の注意点 • ioniconのパスがうまく動かない • Ion-infinite-scrollなど、 動かないものもいくつかある • @ionic/reactで サポートしてないものは諦める •

    @ionic/reactなら動くものだけ、 next/dynamicで定義しておく 12 Next.jsでIonic Reactを利用したWebサイトを開発した話 import dynamic from 'next/dynamic'; export const IonIcon = dynamic( async () => { const mod = await import('@ionic/react'); return mod.IonIcon; }, { ssr: false } // this is what makes it work ); #ionic_jp
  8. 別案その2: AppまるごとDynamic import • Pageに表示するComponentを まるごとdynamic import • https://github.com/mlynch/nextj s-tailwind-ionic-capacitor-starte

    r • TSの型情報もちゃんとわたる • pageファイルごとにimportが必要な のことに注意 13 Next.jsでIonic Reactを利用したWebサイトを開発した話 import dynamic from 'next/dynamic'; const App = dynamic(() => import('../components/AppShell'), { ssr: false, }); export default function Index() { return <App />; } #ionic_jp
  9. アプリ / Webでの決済方法 • 決済代行会社等が用意する決済ページにリダイレクトする • 決済代行会社等のAPIを利用し、 カード情報をtoken化した上で自社サーバーに送信する • カード情報は、自社サーバーを通過させてはいけない

    ◦ 「カード情報の非保持化」 ◦ 改正割賦販売法・クレジットカード取引におけるセキュリティ対策の強化に向けた実行計画 2018 16 Ionic / CapacitorでStripe #ionic_jp
  10. Checkout(リダイレクト型)はアプリ内ブラウザを利用 • サーバー側でCheckoutの セッションを作成 • セッションObjectに リダイレクト先URLがある • CapacitorのBrowser pluginで、

    決済ページを開く • 決済完了後もリダイレクトなので、 着地できるページなどが追加で必要 18 Ionic / CapacitorでStripe import { Browser } from '@capacitor/browser'; const openStripeCheckout = async () => { const res = await fetch('https://api.example.com/create_checkout_session') const session = await res.json() await Browser.open({ url: session.url }); }; #ionic_jp
  11. Elementsは、Capacitor pluginを利用する • Created by @rdlabo React hookだけ手伝った • Payment

    IntentやCustomerを サーバー側で作成 • createPaymentSheetと presentPaymentSheetで表示 • iOS / Androidでの対応を考えると、 自前実装はちょっと難易度高め 19 Ionic / CapacitorでStripe <IonItem button onClick={async e => { e.preventDefault() const { customer, paymentIntent, ephemeralKey } = await createPaymentIntent() await stripe.createPaymentSheet({ paymentIntentClientSecret: paymentIntent, customerId: customer, customerEphemeralKeySecret: ephemeralKey, merchantDisplayName: 'rdlabo' }) await stripe.presentPaymentSheet() }} > <IonLabel>Order</IonLabel> </IonItem> #ionic_jp
  12. まとめ • カード情報は、自前で処理しようとしない。 • tokenに変換するAPI / SDKか、リダイレクトさせよう • Stripe &

    Capacitorの場合、@capacitor-community/stripe • リダイレクト(Checkout)では、 「決済完了後の処理(リダイレクト・表示)」に注意 22 Next.jsでIonic Reactを利用したWebサイトを開発した話 #ionic_jp