📑

AWS CDK x React でLIFFアプリを作る

2022/05/23に公開

最近create-react-appならぬcreate-liff-appというコマンドの存在を知ったので、試してみました。
以下のリポジトリにコードを公開しています。

https://github.com/tokku5552/liff-cdk-sample
この記事では LINE Developers 側の設定は記載しないので、公式サイトを御覧ください。

Create LIFF APP とは

公式によれば、

Create LIFF App は、LIFF アプリの開発環境がコマンド 1 つで構築できる CLI ツールです。React の Create React App (opens new window)や、Next.js の Create Next App (opens new window)のように、Create LIFF App からの質問に答えていくことで、用途に合わせた LIFF アプリのひな形を含む開発環境が生成され、すぐに開発が始められます。

とのこと。サクッと始めれて便利そうです。

そもそも LIFF って何?という人は公式ドキュメントを御覧ください。
一言で言えば LINE 上で動く専用の Web アプリのことです。

プロジェクトの雛形作成

  • 適当にディレクトリ作ってcdk initします。
    • cdk initは空ディレクトリじゃないと実行できないので先にやります。
    • 加えて cdk でアプリ自体もデプロイする場合に、cdk のディレクトリ以下にアプリケーションのディレクトリがあったほうが都合が良いので、今回もそのようにします。
mkdir liff-cdk-sample
npx cdk init app--language typescript

.gitignoreが作成されなかったので作ってnode_modulescdk.outを追加しておきます。

  • 続いて、プロジェクトルートでcreate-liff-appを実行。対話式で設定していきます。
% npx @line/create-liff-app
Welcome to the Create LIFF App
? Enter your project name:  liff-app
? Which template do you want to use? react
? JavaScript or TypeScript? TypeScript
? Please enter your LIFF ID:
 Don't you have LIFF ID? Check out https://developers.line.biz/ja/docs/liff/getting-started/ liffId
? Do you want to install it now with package manager? Yes
? Which package manager do you want to use? yarn
yarn install v1.22.18
warning package.json: No license field
warning ../package.json: No license field
info No lockfile found.
warning liff-app@0.0.0: No license field
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
✨  Done in 18.74s.


Done! Now run:

  cd liff-app
  yarn dev

この時点でローカルで起動してみます。(liff-id を設定しないとLIFF init failed.となります。)
image
あとから liff-id を追加する場合は.envに書けば OK です。

AWS CDK で S3+CloudFront にデプロイ

スタックを編集していきます。構成としては S3 にビルド後のコードをアップロードし、それを CloudFront のオリジンに指定するごく一般的なものです。
今回は検証のため、ドメインの設定等は行っていません。

lib/liff-cdk-sample-stack.ts
import { Stack, StackProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as s3 from 'aws-cdk-lib/aws-s3';
import * as cloudfront from 'aws-cdk-lib/aws-cloudfront';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3deploy from 'aws-cdk-lib/aws-s3-deployment';

export class LiffCdkSampleStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // S3バケット作成
    const liffAppBucket = new s3.Bucket(this, 'LiffAppBucket', {
      websiteIndexDocument: 'index.html',
      websiteErrorDocument: 'index.html'
    });

    const liffAppIdentity = new cloudfront.OriginAccessIdentity(this, 'LiffAppIdentity');

    const liffAppBucketPolicyStatement = new iam.PolicyStatement({
      actions: ['s3:GetObject'],
      effect: iam.Effect.ALLOW,
      principals: [liffAppIdentity.grantPrincipal],
      resources: [`${liffAppBucket.bucketArn}/*`]
    });

    liffAppBucket.addToResourcePolicy(liffAppBucketPolicyStatement);

    // CloudFrontの設定
    const liffAppDistribution = new cloudfront.CloudFrontWebDistribution(this, 'LiffAppDistribution', {
      errorConfigurations: [
        {
          errorCode: 403,
          errorCachingMinTtl: 300,
          responseCode: 200,
          responsePagePath: '/index.html',
        },
        {
          errorCode: 404,
          errorCachingMinTtl: 300,
          responseCode: 200,
          responsePagePath: '/index.html',
        }
      ],
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: liffAppBucket,
            originAccessIdentity: liffAppIdentity
          },
          behaviors: [
            {
              isDefaultBehavior: true,
            }
          ]
        }
      ],
      priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL
    })

    // S3へデプロイ
    new s3deploy.BucketDeployment(this, 'LiffAppDeploy', {
      sources: [s3deploy.Source.asset('./liff-app/dist')],
      destinationBucket: liffAppBucket,
      distribution: liffAppDistribution,
      distributionPaths: ['/*']
    })
  }
}

デプロイの sources はプロジェクトに合わせて変更してください。今回 React 側の設定はデフォルトのまま(dist)なので、liff-app/distとしています。

  • デプロイは以下のコマンドで行います。
cd liff-app
yarn build
cd ..
npx cdk deploy
  • LINE Developers コンソールから LIFF アプリのエンドポイント URL を CloudFront のものに変更し、LIFF URL にアクセスすると無事 LIFF アプリが起動しました 🎉
    image

Discussion