AWS CDK и Amplify runtime-config

Здравствуйте,

Бесшовная интеграция приложений AWS CDK и Amplify раньше была очень громоздкой! С runtime-config для фронтенда React-приложения Amplify это стало намного проще. Здесь я хотел бы познакомить вас с идеей runtime-config.

В своих fullstack-проектах я регулярно использую AWS CDK в качестве бэкенда. AppSync как реализация GraphQL является интерфейсом между фронтендом и бэкендом. Фронтенд обычно представляет собой React SPA (одностраничное приложение), размещенное в ведре S3. Я использую AWS Cognito для управления и аутентификации пользователей и обычно настраиваю фронтенд React-приложения с помощью AWS Amplify.

Идея runtime-config

Runtime-config позволяет настраивать Amplify после фазы сборки во время выполнения. Папка dist SPA имеет файл runtime-config.json в папке public, который загружается во время выполнения приложения. Здесь приведен пример файла runtime-config.json:

{
  "region": "eu-central-1",
  "identityPoolId": "eu-central-1:cda9c404-0e74-439d-b40c-90204a0e1234",
  "userPoolId": "eu-central-1_Uv0E91234",
  "userPoolWebClientId": "1t6jbsr5b7utg6c9urhj51234",
  "appSyncGraphqlEndpoint": "https://wr2cf4zklfbt3pxw26bik12345.appsync-api.eu-central-1.amazonaws.com/graphql"
}
Войти в полноэкранный режим Выйти из полноэкранного режима

Затем runtime-config динамически загружается в приложение React через useEffect и fetch:

useEffect(() => {
    fetch('/runtime-config.json')
      .then((response) => response.json())
      .then((runtimeContext) => {
        runtimeContext.region &&
          runtimeContext.userPoolId &&
          runtimeContext.userPoolWebClientId &&
          runtimeContext.identityPoolId &&
          Amplify.configure({
            aws_project_region: runtimeContext.region,
            aws_cognito_identity_pool_id: runtimeContext.identityPoolId,
            aws_cognito_region: runtimeContext.region,
            aws_user_pools_id: runtimeContext.userPoolId,
            aws_user_pools_web_client_id: runtimeContext.userPoolWebClientId,
            aws_appsync_graphqlEndpoint: runtimeContext.appSyncGraphqlEndpoint,
            aws_appsync_region: runtimeContext.region,
            aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS',
            Auth: {
              region: runtimeContext.region,
              userPoolId: runtimeContext.userPoolId,
              userPoolWebClientId: runtimeContext.userPoolWebClientId,
              identityPoolId: runtimeContext.identityPoolId,
            },
          });
      })
      .catch((e) => console.log(e));
  }, []);
Войти в полноэкранный режим Выход из полноэкранного режима

Как вы можете видеть, сначала выполняется fetch для загрузки runtime-config.json. После этого Amplify настраивается с помощью извлеченных свойств.

Вы также можете использовать переменные окна HTML для установки параметров Amplify. Однако я предпочитаю представленное здесь решение fetch, поскольку оно потенциально более быстро реагирует на отсутствие runtime-config.json или отдельных отсутствующих свойств. Также следует избегать оконных переменных, поскольку они получают глобальный доступ к DOM.

Рабочие процессы

Типичный рабочий процесс без runtime-config для сборки и развертывания приложения React иногда выглядел следующим образом:

  • curl и сохранение текущих конечных точек, таких как идентификатор пула пользователя, конечная точка AppSynch и т.д.
  • создать конфигурационный файл Amplify
  • собрать приложение react
  • cdk deploy react dist folder to S3

Построить рабочий процесс конвейера с runtime-config:

  • build react app
  • cdk развернуть папку react dist и конфигурацию времени выполнения на S3

Пример CDK

Полный код доступен в моем проекте Senjuns на GitHub.

const userPool = new cognito.UserPool(...)
...
const identityPool = new cognito.CfnIdentityPool(...)
...

const dashboard = new StaticWebsite(this, 'dashboard', {
    build: '../dashboard/build',
    recordName: 'dashboard',
    domainName: props.domainName,
    runtimeOptions: {
        jsonPayload: {
            region: core.Stack.of(this).region,
            identityPoolId: identityPool.ref,
            userPoolId: userPool.userPoolId,
            userPoolWebClientId: userPoolWebClient.userPoolClientId,
            appSyncGraphqlEndpoint: graphqlUrl.stringValue,
        },
    },
});
Вход в полноэкранный режим Выход из полноэкранного режима

StaticWebsite — это простая конструкция L3 CDK с ведро S3 static website bucket в качестве основного ресурса. Более подробную информацию вы можете посмотреть здесь. Но самые интересные детали находятся в объекте runtimeOptions. Там хранятся конечные точки для конфигурации времени выполнения для Amplify. За этим стоит S3 Bucket Deployment Construct, который передает конечные точки через s3deploy.Source.jsonData(…) в JSON-файл runtime-config.json:

const DEFAULT_RUNTIME_CONFIG_FILENAME = 'runtime-config.json';

...

new s3deploy.BucketDeployment(this, 'BucketDeployment', {
    sources: [
    s3deploy.Source.asset(props.build),
    ...(props.runtimeOptions
        ? [
        s3deploy.Source.jsonData(
            props.runtimeOptions?.jsonFileName ||
                DEFAULT_RUNTIME_CONFIG_FILENAME,
            props.runtimeOptions?.jsonPayload,
        ),
        ]
        : []),
    ],
    distribution,
    destinationBucket: siteBucket,
});
Вход в полноэкранный режим Выход из полноэкранного режима

Это классная интеграция CDK 🙂 ! Просто передать BucketDeployment Construct два параметра, такие как React dist и runtime-config — довольно умная идея.

Обходной путь с вложенными стековыми выводами

Во время работы с runtime-config я столкнулся с проблемой. Невозможно использовать выходы CDK из вложенного стека для runtime-config. Но есть обходной путь с использованием параметров AWS Systems Manager:

const graphqlUrl = new ssm.StringParameter(this, 'GraphqlUrl', {
    parameterName: 'GraphqlUrl',
    stringValue: appSyncTransformer.appsyncAPI.graphqlUrl,
});

...

const dashboard = new StaticWebsite(this, 'dashboard', {
    build: '../dashboard/build',
    recordName: 'dashboard',
    domainName: props.domainName,
    runtimeOptions: {
    jsonPayload: {
        region: core.Stack.of(this).region,
        identityPoolId: identityPool.ref,
        userPoolId: userPool.userPoolId,
        userPoolWebClientId: userPoolWebClient.userPoolClientId,
        appSyncGraphqlEndpoint: graphqlUrl.stringValue,
    },
    },
});
Войти в полноэкранный режим Выйти из полноэкранного режима

Круто, правда? Вывод вложенного стека просто сохраняется в строковом параметре SSM и может быть прочитан позже. Спасибо Адриану Димеху за отличный обходной путь 🙏.

Заключение

AWS CDK и Amplify — это мощная комбинация. С представленным здесь runtime-config эта комбинация становится намного лучше! Я скопировал это решение из aws-prototyping-sdk. В этом репозитории разрабатываются некоторые интересные конструкции AWS CDK. Так что вам определенно стоит заглянуть туда!

Спасибо DeepL translater (бесплатная версия) за помощь в переводе на английский и экономию кучи времени :).

Я люблю работать над проектами с открытым исходным кодом. Многое из моего материала вы уже можете использовать на https://github.com/mmuller88 . Если вам нравится моя работа там и мои статьи в блоге, пожалуйста, поддержите меня на:

OR

И не забудьте посетить мой сайт

Оцените статью
devanswers.ru
Добавить комментарий