AWS x Figma API 連携で CSS 自動生成 & CDN 配信を実現する方法

2024-04-02
デベロッパーのためのクラウド活用方法

Author : 宮口 直樹

こんにちは。ソリューションアーキテクトの宮口です。

builders.flash を読まれているデザイナーや開発者の方には Web サイトやアプリケーションのデザインに Figma を使われている方も多いのではないでしょうか。

Figma では公式で提供されている機能や豊富なプラグインで React コンポーネントの自動生成が柔軟に行えます。しかし、まだ開発現場では Bootstrap などの CSS フレームワークが使われることがあります。また、Figma では作成したデザインの CSS 部分をコピー & ペーストはできますが、ライブラリのように全てのコンポーネントをまとめて抽出するような機能は標準ではありません。

そこで本記事では、Figma API を用いて取得したデザインのスタイル情報から CSS ファイルを自動生成し、コンテンツ配信ネットワーク (CDN) 経由で配信するフローを AWS サービスを活用して開発する手順を紹介します。Figma デザインをソースとした CSS アセット化と公開を自動化し、アプリケーション開発を効率的に進める環境を作ることを目的としています。

ご注意

本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。

*ハンズオン記事およびソースコードにおける免責事項 »

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. 今回開発するアプリケーションについて

本記事では、Figma のデザインを元に CSS ファイルを作成し、CDN で公開するアプリケーションを AWS Cloud Development Kit (AWS CDK) を用いて作成します。これを実現するために、以下の AWS サービスを利用しました。

Amazon S3

CSS ファイルを格納するストレージ。

Amazon CloudFront

S3 に保存されている CSS ファイルを配信するための CDN サービス。

AWS Lambda

Figma API を呼び出し CSS ファイルを作成、更に S3 に CSS ファイルをアップロードする関数。

Amazon EventBridge

Lambda 関数を毎日 0 時に定期実行して、CSS ファイルを更新するためのスケジューラー。

AWS CDK

上記の AWS サービスの設定をコード定義しデプロイ。

これらの AWS サービスを用いて、最終的に以下のアーキテクチャを設計します。なお、今回構築したアプリケーションでは、使用したサービスごとに料金が発生するので、料金に関する詳細は 公式ページ をご参考ください。

それでは早速開発の流れを解説していきます。


2. Figma API を用いた CSS ファイルの作成

2-1. Figma 側での前準備

まずは、Figma API を用いて CSS ファイルを作成する手順です。今回はサンプルとして図のような簡単なログインフォームのデザインを Figma で用意しました。こちらのデザインを Figma API の 公式ドキュメント を参照して取得していきます。

画像をクリックすると拡大します

まず API コールに必要なアクセストークンを 公式ドキュメント に従って取得します。続いてファイル ID が必要ですが、Figma のファイル URL に含まれています。具体的には、https://www.figma.com/file/xxx/ の文字列 xxx の部分です。

取得したアクセストークンとファイル ID は 3 章で AWS CDK の環境変数として利用するのでメモしておいてください。

2-2. CSS ファイル作成の実装

次に実際に API コールをしてみますが、利用するエンドポイントは GET file (GET https://www.figma.com/file/v1/files/<FILE_ID>) です。このエンドポイントのレスポンスは Figma ファイルに含まれるスタイル情報やメタデータを含んだほぼ全ての情報が JSON 形式で返されます。そのため、自力で取得したいノードのタイプやスタイルに応じて CSS コードに変換することが必要となります。

今回は簡易的に、ノードのタイプがコンポーネントのものだけを抽出して、スタイルや簡単なレイアウトを CSS コードとして生成しました。今回のケースですと、フォームとボタンの CSS コードを自動生成させます。

以下のコードが Python を用いて記述した例です。figma2css.py というファイル名で作成しました。

import os
import json
import urllib3


class FigmaComponentExporter:
    def __init__(self):
        # FigmaのアクセストークンとファイルIDを取得
        self.access_token = os.environ.get("FIGMA_ACCESS_TOKEN")
        # Figma APIのURL
        self.url = f"https://api.figma.com/v1/files/{os.environ.get('FIGMA_FILE_ID')}"
        # CSSを保持する辞書
        self.css_dict = {}
        # 出力ファイル名を設定
        self.output = "styles.css"

    def _find_components(self, data):
        # コンポーネントを探索する再帰関数
        components = []
        if isinstance(data, list):
            for item in data:
                components.extend(self._find_components(item))
        elif isinstance(data, dict):
            if data.get("type") == "COMPONENT" and data.get("children") is not None:
                components.append(data)
            for value in data.values():
                components.extend(self._find_components(value))
        return components

    def _generate_css(self, class_name, style_dict):
        # CSSを生成するメソッド
        css = f".{class_name} {{\n"
        for key, value in style_dict.items():
            if value is not None:
                css += f"  {key}: {value};\n"
        css += "}\n"
        return css

    def _rgba_to_hex(self, color):
        # RGBAを16進数の色コードに変換するメソッド
        hex_color = "#{:02X}{:02X}{:02X}".format(
            int(color["r"] * 255), int(color["g"] * 255), int(color["b"] * 255)
        )
        return hex_color

    def _generate_class_name(self, input_text):
        # クラス名を生成するメソッド
        class_name = "".join(c if c.isalnum() else "-" for c in input_text.lower())
        class_name = "-".join(filter(None, class_name.split("-")))
        return class_name

    def _write_css_file(self):
        # CSSファイルに書き込むメソッド
        with open(self.output, "a") as f:
            for class_name, style_dict in self.css_dict.items():
                f.write(self._generate_css(class_name, style_dict))

    def _output_component_css(self, component, parent_component_name=None):
        # コンポーネントのCSSを出力するメソッド
        class_name = (
            self._generate_class_name(f"{parent_component_name}-{component['name']}")
            if parent_component_name
            else self._generate_class_name(component["name"])
        )

        self.css_dict[class_name] = {
            "width": f"{int(component['absoluteBoundingBox']['width'])}px",
            "height": f"{int(component['absoluteBoundingBox']['height'])}px",
            "background": self._rgba_to_hex(component["background"][0]["color"])
            if component.get("background")
            else None,
            "border-radius": f"{int(component.get('cornerRadius', 0))}px",
            "border-width": f"{int(component.get('strokeWeight', 0))}px",
            "border": f"solid {self._rgba_to_hex(component.get('strokes')[0].get('color'))}"
            if component.get("strokes") and component.get("strokeWeight", 0) > 0
            else None,
        }

        if component.get("children") is None:
            return
        for child in component["children"]:
            if child["type"] == "TEXT":
                self._output_text_css(child, parent_component_name, component["name"])
            else:
                self._output_component_css(child, parent_component_name=class_name)

    def _output_text_css(self, child, parent_component_name, component_name):
        # テキストのCSSを出力するメソッド
        styles = child["style"]
        style_dict = {
            "font-family": f"'{styles['fontFamily']}'",
            "font-size": f"{int(styles['fontSize'])}px",
            "font-weight": styles["fontWeight"],
            "color": self._rgba_to_hex(child["fills"][0]["color"]),
            "line-height": f"{int(styles['lineHeightPercentFontSize'])}%",
            "letter-spacing": f"{int(styles['letterSpacing'] / styles['fontSize'])}em",
        }
        class_name = (
            self._generate_class_name(
                f"{parent_component_name}-{component_name}-{child['name']}"
            )
            if parent_component_name
            else self._generate_class_name(f"{component_name}-{child['name']}")
        )

        # CSSを辞書に追加
        self.css_dict[class_name] = style_dict

    def run(self):
        # 出力ファイルが存在する場合は削除
        if os.path.exists(self.output):
            os.remove(self.output)
        # Figma APIからデータを取得
        http = urllib3.PoolManager()
        response = http.request(
            "GET", self.url, headers={"X-FIGMA-TOKEN": self.access_token}
        )

        if response.status == 200:
            response = json.loads(response.data.decode("utf-8"))
        else:
            print(f"Failed to call API. Status code: {response.status}")

        # コンポーネントセットを探索し、CSSを生成
        components = self._find_components(response)
        for component in components:
            # コンポーネントごとにコメントを出力
            with open(self.output, "a") as f:
                f.write(f"/* {component['name']} */\n")

            self.css_dict = {}
            self._output_component_css(component)
            # CSSファイルに書き込む
            self._write_css_file()


if __name__ == "__main__":
    exporter = FigmaComponentExporter()
    exporter.run()

2-3. コードの動作確認

用意したコードをローカル環境で実行してみます。

python figma2css.py

すると、下記のような CSS ファイル (styles.css) が自動生成されます。簡単なスタイル情報が取得できていることが確認できますね。

/* Button */
.button {
  width: 100px;
  height: 42px;
  background: #0080DE;
  border-radius: 10px;
  border-width: 1px;
}
.button-label {
  font-family: 'Noto Sans JP';
  font-size: 18px;
  font-weight: 400;
  color: #FFFFFF;
  line-height: 100%;
  letter-spacing: 0em;
}
/* Form */
.form {
  width: 400px;
  height: 65px;
  border-radius: 0px;
  border-width: 1px;
}
.form-label {
  font-family: 'Noto Sans JP';
  font-size: 18px;
  font-weight: 400;
  color: #000000;
  line-height: 100%;
  letter-spacing: 0em;
}
.form-placeholder {
  width: 400px;
  height: 42px;
  background: #FFFFFF;
  border-radius: 8px;
  border-width: 1px;
  border: solid #000000;
}

3. AWS CDK を用いた自動生成・ファイル配信

3-1. AWS CDK プロジェクトの作成

CSS ファイルを自動生成するコードが完成したので、次は Amazon CloudFront + Amazon S3 を用いたファイル配信を行います。今回は利用する全ての AWS リソースの定義を AWS CDK (TypeScript) で記述していきたいと思います。

AWS CDK のツールキットがインストールされている前提で進めます。AWS CDK を利用できる環境をお持ちでない方は こちら のドキュメントに従って環境構築を行うことができます。

まずは、以下のコマンドを実行して CDK プロジェクトを作成します。

mkdir figma2css
cd figma2css
npx cdk init app --language typescript

3-2. AWS CDK の実装

CDK プロジェクトの作成が完了したら、AWS CDK の開発を進めていきます。Figma API のアクセストークンとファイル ID をパラメータを記述する parameter.ts の作成と lib/figma2css-stack.ts を編集していきます。

まずは、parameter.ts というファイルを作成し、パラメータとして Figma API のアクセストークンとファイル ID を設定します。

以下のように、「figmaAccessToken」と「figmaFileId」の情報を記述します。これにより、CDK コードからこれらの値を変数として参照することができるようになります。

export interface AppParameter {
  figmaAccessToken: string;
  figmaFileId: string;
}

export const appParameter: AppParameter = {
  figmaAccessToken: "FIGMA_ACCESS_TOKEN",
  figmaFileId: "FIGMA_FILE_ID",
};

続いて、lib/figma2css-stack.ts に下記の CDK のコードを記述していきます。コード内には主に以下のようなリソース定義が記述されています。

  • CSS ファイルを格納するための S3 バケット
  • CSS ファイルを作成して、S3 バケットにアップロードする Lambda 関数
  • Lambda 関数を毎日 0 時に定期的に発火させる EventBridge
  • S3 オブジェクトをオリジンとして配信する CloudFront
import * as s3 from "aws-cdk-lib/aws-s3";
import * as iam from "aws-cdk-lib/aws-iam";
import * as kms from "aws-cdk-lib/aws-kms";
import * as lambda from "aws-cdk-lib/aws-lambda";
import * as events from "aws-cdk-lib/aws-events";
import * as targets from "aws-cdk-lib/aws-events-targets";
import * as cloudfront from "aws-cdk-lib/aws-cloudfront";
import * as secretsmanager from "aws-cdk-lib/aws-secretsmanager";
import * as cloudfront_origins from "aws-cdk-lib/aws-cloudfront-origins";
import {
  CfnOutput,
  StackProps,
  RemovalPolicy,
  Stack,
  SecretValue,
  Duration,
} from "aws-cdk-lib";
import { Construct } from "constructs";
import { appParameter } from "../parameter";

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

    // parameter.tsより環境変数の読み込み
    const figmaAccessToken = appParameter.figmaAccessToken;
    const figmaFileId = appParameter.figmaFileId;

    const cloudfrontOAI = new cloudfront.OriginAccessIdentity(
      this,
      "cloudfront-OAI",
      {
        comment: `OAI for S3 buckect`,
      }
    );

    // CSSファイルを格納するS3バケット
    const bucket = new s3.Bucket(this, "Figma2CssBucket", {
      publicReadAccess: false,
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      removalPolicy: RemovalPolicy.DESTROY, // スタック削除時にバケットを削除
      autoDeleteObjects: true, // 本番環境では非推奨
      cors: [
        {
          allowedMethods: [s3.HttpMethods.GET],
          allowedOrigins: ["*"],
        },
      ],
    });

    bucket.addToResourcePolicy(
      new iam.PolicyStatement({
        actions: ["s3:GetObject"],
        resources: [bucket.arnForObjects("*")],
        principals: [
          new iam.CanonicalUserPrincipal(
            cloudfrontOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId
          ),
        ],
      })
    );

    new CfnOutput(this, "S3Bucket", { value: bucket.bucketName });

    // S3からコンテンツを配信するためのCloudFrontディストリビューション
    const distribution = new cloudfront.Distribution(
      this,
      "Figma2CssDistribution",
      {
        defaultRootObject: "styles.css", // デフォルトのルートオブジェクトを指定
        defaultBehavior: {
          origin: new cloudfront_origins.S3Origin(bucket, {
            originAccessIdentity: cloudfrontOAI,
          }),
          originRequestPolicy: cloudfront.OriginRequestPolicy.CORS_S3_ORIGIN,
          compress: true,
          allowedMethods: cloudfront.AllowedMethods.ALLOW_GET_HEAD,
          cachePolicy: cloudfront.CachePolicy.CACHING_OPTIMIZED,
          viewerProtocolPolicy:
            cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
        },
      }
    );

    new CfnOutput(this, "DistributionId", {
      value: distribution.distributionId,
    });
    new CfnOutput(this, "CloudFrontURL", {
      value: "https://" + distribution.distributionDomainName + "/styles.css",
    });

    // S3バケットにオブジェクトをアップロードするLambda関数
    const uploadFunction = new lambda.Function(this, "UploadFunction", {
      runtime: lambda.Runtime.PYTHON_3_12,
      handler: "figma2css.lambda_handler", // ハンドラーがfigma2css.pyファイルにあると仮定
      code: lambda.Code.fromAsset("src"), // Lambda関数のコードへのパス
      timeout: Duration.seconds(15), // タイムアウトを15秒に設定
    });

    // AWS Secrets Managerを用いた環境変数の秘匿化
    const tokenEncryptionKey = new kms.Key(this, "TokenEncryptionKey");
    const figmaAccessTokenSecret = new secretsmanager.Secret(
      this,
      "FigmaAccessToken",
      {
        secretStringValue: SecretValue.unsafePlainText(figmaAccessToken.toString()),
        encryptionKey: tokenEncryptionKey,
      }
    );

    // Lambda関数の環境変数を設定
    uploadFunction.addEnvironment("SECRET_NAME", figmaAccessTokenSecret.secretName);
    uploadFunction.addEnvironment("FIGMA_FILE_ID", figmaFileId);
    uploadFunction.addEnvironment("S3_BUCKET_NAME", bucket.bucketName);

    // Lambda関数に対し、Secretの暗号鍵への権限付与
    tokenEncryptionKey.grantDecrypt(uploadFunction);
    figmaAccessTokenSecret.grantRead(uploadFunction);

    // Lambda関数がS3バケットにオブジェクトをアップロードするための権限を付与
    bucket.grantWrite(uploadFunction);

    // EventBridgeルールを作成し、Lambda関数を毎日0時(JST)に発火
    const rule = new events.Rule(this, "Figma2CssRule", {
      schedule: events.Schedule.cron({ minute: "0", hour: "15" }),
    });

    // Lambda関数をEventBridgeルールのターゲットとして追加
    rule.addTarget(new targets.LambdaFunction(uploadFunction));
  }
}

3-3. Lambda 関数の実装

次に 2 章で作成した Python コードを Lambda 関数として実行できる形式に変更した上で、S3 バケットにアップロードするように編集します。

Figma API の呼び出しに必要な情報や S3 バケット名は Lambda の環境変数から読み取るように修正を加えています。CDK のデプロイ時にコードとしてそのまま Lambda 関数にアップロードするために、src/figma2css.py に保存しておきます。以下が修正後のコードです。

import os
import json
import boto3
import urllib3
import botocore


class FigmaComponentExporter:
    def __init__(self):
        # Figmaのアクセストークンを取得
        self.access_token = self._get_secret()
        # Figma APIのURL
        self.url = f"https://api.figma.com/v1/files/{os.environ.get('FIGMA_FILE_ID')}"
        # CSSを保持する辞書
        self.css_dict = {}
        # 出力ファイル名を設定
        self.tmp_output = "/tmp/styles.css"

    def _get_secret(self):
        # FigmaのアクセストークンをSecrets Managerから取得
        boto3_session = boto3.session.Session()
        boto3_client = boto3_session.client(service_name="secretsmanager")
        secret_dict = boto3_client.get_secret_value(
            SecretId=os.environ.get("SECRET_NAME")
        )
        access_token = secret_dict["SecretString"]
        return access_token

    def _find_components(self, data):
        # コンポーネントを探索する再帰関数
        components = []
        if isinstance(data, list):
            for item in data:
                components.extend(self._find_components(item))
        elif isinstance(data, dict):
            if data.get("type") == "COMPONENT" and data.get("children") is not None:
                components.append(data)
            for value in data.values():
                components.extend(self._find_components(value))
        return components

    def _generate_css(self, class_name, style_dict):
        # CSSを生成するメソッド
        css = f".{class_name} {{\n"
        for key, value in style_dict.items():
            if value is not None:
                css += f"  {key}: {value};\n"
        css += "}\n"
        return css

    def _rgba_to_hex(self, color):
        # RGBAを16進数の色コードに変換するメソッド
        hex_color = "#{:02X}{:02X}{:02X}".format(
            int(color["r"] * 255), int(color["g"] * 255), int(color["b"] * 255)
        )
        return hex_color

    def _generate_class_name(self, input_text):
        # クラス名を生成するメソッド
        class_name = "".join(c if c.isalnum() else "-" for c in input_text.lower())
        class_name = "-".join(filter(None, class_name.split("-")))
        return class_name

    def _write_css_file(self):
        # CSSファイルに書き込むメソッド
        with open(self.tmp_output, "a") as f:
            for class_name, style_dict in self.css_dict.items():
                f.write(self._generate_css(class_name, style_dict))

    def _upload_s3_bucket(self):
        # S3バケットにstyles.cssをアップロード
        s3_bucket_name = os.environ.get("S3_BUCKET_NAME")
        s3 = boto3.resource("s3")
        try:
            s3.Object(s3_bucket_name, "styles.css").put(
                Body=open(self.tmp_output, "rb"), ContentType="text/css"
            )
            os.remove(self.tmp_output)
            print("styles.css uploaded to S3 bucket")
        except botocore.exceptions.ClientError as e:
            print(f"Error uploading styles.css to S3 bucket: {e}")

    def _output_component_css(self, component, parent_component_name=None):
        # コンポーネントのCSSを出力するメソッド
        class_name = (
            self._generate_class_name(f"{parent_component_name}-{component['name']}")
            if parent_component_name
            else self._generate_class_name(component["name"])
        )

        self.css_dict[class_name] = {
            "width": f"{int(component['absoluteBoundingBox']['width'])}px",
            "height": f"{int(component['absoluteBoundingBox']['height'])}px",
            "background": self._rgba_to_hex(component["background"][0]["color"])
            if component.get("background")
            else None,
            "border-radius": f"{int(component.get('cornerRadius', 0))}px",
            "border-width": f"{int(component.get('strokeWeight', 0))}px",
            "border": f"solid {self._rgba_to_hex(component.get('strokes')[0].get('color'))}"
            if component.get("strokes") and component.get("strokeWeight", 0) > 0
            else None,
        }

        if component.get("children") is None:
            return
        for child in component["children"]:
            if child["type"] == "TEXT":
                self._output_text_css(child, parent_component_name, component["name"])
            else:
                self._output_component_css(child, parent_component_name=class_name)

    def _output_text_css(self, child, parent_component_name, component_name):
        # テキストのCSSを出力するメソッド
        styles = child["style"]
        style_dict = {
            "font-family": f"'{styles['fontFamily']}'",
            "font-size": f"{int(styles['fontSize'])}px",
            "font-weight": styles["fontWeight"],
            "color": self._rgba_to_hex(child["fills"][0]["color"]),
            "line-height": f"{int(styles['lineHeightPercentFontSize'])}%",
            "letter-spacing": f"{int(styles['letterSpacing'] / styles['fontSize'])}em",
        }
        class_name = (
            self._generate_class_name(
                f"{parent_component_name}-{component_name}-{child['name']}"
            )
            if parent_component_name
            else self._generate_class_name(f"{component_name}-{child['name']}")
        )

        # CSSを辞書に追加
        self.css_dict[class_name] = style_dict

    def run(self):
        # 出力ファイルが存在する場合は削除
        if os.path.exists(self.tmp_output):
            os.remove(self.tmp_output)
        # Figma APIからデータを取得
        http = urllib3.PoolManager()
        response = http.request(
            "GET", self.url, headers={"X-FIGMA-TOKEN": self.access_token}
        )

        if response.status == 200:
            response = json.loads(response.data.decode("utf-8"))
        else:
            print(f"Failed to call API. Status code: {response.status}")

        # コンポーネントセットを探索し、CSSを生成
        components = self._find_components(response)
        for component in components:
            # コンポーネントごとにコメントを出力
            with open(self.tmp_output, "a") as f:
                f.write(f"/* {component['name']} */\n")

            self.css_dict = {}
            self._output_component_css(component)
            # CSSファイルに書き込む
            self._write_css_file()
        self._upload_s3_bucket()

        return {
            "statusCode": 200,
            "body": json.dumps("Figma component export completed successfully!"),
        }


def lambda_handler(event, context):
    exporter = FigmaComponentExporter()
    result = exporter.run()
    return result

3-4. アプリケーションのデプロイ

ここまで準備できると、あとは以下の CDK コマンドでデプロイするだけです。

npx cdk deploy

数分程度待つとデプロイが完了するので、作成したリソースを確認します。

AWS マネジメントコンソール から CloudFormation にアクセスします。作成された Figma2CssStack を選択し、出力タブを見ると CloudFrontURL という出力が確認できます。こちらの URL から CSS ファイルにアクセスすることができるので、コピーしておきます。

画像をクリックすると拡大します

これで Figma API から取得したスタイル情報を CSS ファイルとして配信するためのフローを定義することができました。


4. サンプルの Web サイトを用いた動作確認

実際にうまく CSS ファイルを利用できるか確認してみましょう。CloudFront 経由で配信されている CSS ファイルを用いて簡単な HTML コードを記述したので、そちらを試しに確認してみます。5 行目に先ほどコピーした CloudFrontURL を記入します。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <title>Sample</title>
    <link rel="stylesheet" href="https://xxx.cloudfront.net/styles.css" />
    <style>
      body {
        display: flex;
        justify-content: center;
        align-items: center;
        flex-direction: column;
      }
      div {
        margin-bottom: 35px;
      }
    </style>
  </head>
  <body>
    <h1>ログイン</h1>
    <div class="form">
      <label class="form-label">メールアドレス</label>
      <input class="form-placeholder" />
    </div>
    <div class="form">
      <label class="form-label">パスワード</label>
      <input class="form-placeholder" />
    </div>
    <button class="button">
      <span class="button-label">送信</span>
    </button>
  </body>
</html>

正常に CSS スタイルが適用されていることが確認できました。左画像が CSS スタイル適用前、右画像が CSS スタイル適用後の Web サイトです。

余談ですが、今回のように CSS ファイルを利用するのではなく、React コンポーネントを利用される場合は AWS Amplify Studio の活用が有効です。先ほどと同じ Figma ファイルを AWS Amplify Studio に与えると、React コンポーネントを得ることができます。これを使い、以下のようなコードを記述することで、先程作成した Web サイトと同じデザインのものを作ることができます。

import React from "react";
import ReactDOM from "react-dom";
import { ThemeProvider } from "@aws-amplify/ui-react";
import { Amplify } from "aws-amplify";
import awsconfig from "./aws-exports";
import "@aws-amplify/ui-react/styles.css";
import { studioTheme, Button, Form } from "./ui-components";

Amplify.configure(awsconfig);

const appStyle = {
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
  flexDirection: "column",
};

const centeredStyle = {
  display: "flex",
  justifyContent: "center",
};

const verticalMargin = {
  marginBottom: "35px",
};

const App = () => (
  <div style={appStyle}>
    <ThemeProvider theme={studioTheme}>
      <h1 style={centeredStyle}>ログイン</h1>
      <div style={verticalMargin} />
      <Form />
      <div style={verticalMargin} />
      <Form />
      <div style={verticalMargin} />
      <div style={centeredStyle}>
        <Button />
      </div>
    </ThemeProvider>
  </div>
);

ReactDOM.render(<App />, document.getElementById("root"));

AWS Amplify Studio を用いた実装の詳細は AWS ブログ「AWS Amplify Studio – 最小限のプログラミングでFigmaからフルスタックのReactアプリを実現」をご参考ください。


5. まとめ

最後まで閲覧いただきありがとうございました。今回は Figma ファイルを CSS ファイルに書き出し、アセットとして活用するための開発手順をお伝えました。

複雑な Figma コンポーネントやより詳細なスタイル・レイアウト情報を取得するには、Python コードを工夫する必要がありますが、Figma ファイルを CSS ファイルとしてアセット化する一連の流れをご理解いただけたのではないでしょうか。

ぜひ本記事の知見をご活用いただき、開発プロセスの効率化にお役立ていただけますと幸いです。


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

宮口 直樹 (Naoki Miyaguchi)
アマゾン ウェブ サービス ジャパン合同会社 ソリューションアーキテクト

公共部門のお客様をご支援するソリューションアーキテクトとして活動しています。
プライベートでは、スペインや南米で人気スポーツのパデルにはまっています。

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する