Skip to content

Commit

Permalink
Merge pull request #16 from ryichk/deploy-frontend
Browse files Browse the repository at this point in the history
AWS CDKを使ってフロントエンドをS3+CloudFrontにデプロイできる
  • Loading branch information
ryichk authored Jan 4, 2025
2 parents 45121c5 + f5a1fd5 commit 0ee492d
Show file tree
Hide file tree
Showing 27 changed files with 5,682 additions and 11 deletions.
15 changes: 11 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# root
.env
.env.production
tmp

# client
node_modules

/.cache
/build
/public/build
/client/.cache
/client/build
/client/public/build

# api
## Binaries for programs and plugins
Expand All @@ -26,4 +28,9 @@ node_modules
go.work
go.work.sum

tmp
# infra-ts
infra-ts/*.js
!jest.config.js
*.d.ts

.cdk.staging
33 changes: 33 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,36 @@ test:

test_v:
$(DOCKER_RUN_API) go test -v -cover ./...

build_client:
$(DOCKER_RUN_CLIENT) npm run build

npm_infra-ts:
npm $(CMD) --prefix ./infra-ts

npm_i_infra-ts:
npm i --prefix ./infra-ts

cdk:
npm run cdk $(CMD) --prefix ./infra-ts

cdk_bootstrap:
npm run cdk:bootstrap --prefix ./infra-ts

cdk_deploy:
npm run cdk:deploy $(STACK) --prefix ./infra-ts

cdk_deploy_all:
npm run cdk:deploy:all --prefix ./infra-ts

cdk_rollback:
npm run cdk:rollback $(STACK) --prefix ./infra-ts

cdk_rollback_all:
npm run cdk:rollback:all --prefix ./infra-ts

cdk_destroy:
npm run cdk:destroy $(STACK) --prefix ./infra-ts

cdk_destroy_all:
npm run cdk:destroy:all --prefix ./infra-ts
40 changes: 40 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@

- PostgreSQL

### Infrastructure

#### Cloud Vendor

- AWS

#### Tools

- Node.js v22.11.0
- aws-cdk v2.173.4

## Environment Construction

### 1. Install Docker
Expand Down Expand Up @@ -151,3 +162,32 @@ The request handler implements request validation, etc.
### Implement Request Routing

Implement request routing in `api/internal/server/router.go`.

## Infrastructure Construction and Deployment Procedures

### Setup

```sh
make npm_i_infra-ts
make cdk_bootstrap
```

### Build Frontend Code

```sh
make build_client
```

### Deploy

#### Deploy All Stack

```sh
make cdk_deploy_all
```

#### Deploy Stacks individually

```sh
make cdk_deploy STACK=StackName
```
3 changes: 2 additions & 1 deletion client/app/components/todo-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Input } from "./ui/input";
import { Textarea } from "./ui/textarea";
import { Dispatch, SetStateAction } from "react";
import { Todo } from "~/types";
import { API_DOMAIN } from "~/constants";

const formSchema = z.object({
title: z.string().min(2, {
Expand All @@ -34,7 +35,7 @@ export default function TodoForm({ accessToken, setTodos }: Props) {

const createTodo = async (values: z.infer<typeof formSchema>) => {
try {
const res = await fetch('http://localhost:8080/todos', {
const res = await fetch(`${API_DOMAIN}/todos`, {
method: 'POST',
headers: {
"Content-Type": "application/json",
Expand Down
2 changes: 0 additions & 2 deletions client/app/components/ui/label.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client"

import * as React from "react"
import * as LabelPrimitive from "@radix-ui/react-label"
import { cva, type VariantProps } from "class-variance-authority"
Expand Down
1 change: 1 addition & 0 deletions client/app/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export const COGNITO_USER_POOL_ID = import.meta.env.VITE_COGNITO_USER_POOL_ID;
export const COGNITO_CLIENT_ID = import.meta.env.VITE_COGNITO_CLIENT_ID;
export const COGNITO_REDIRECT_URI = import.meta.env.VITE_COGNITO_REDIRECT_URI;
export const COGNITO_DOMAIN = import.meta.env.VITE_COGNITO_DOMAIN;
export const API_DOMAIN= import.meta.env.VITE_API_DOMAIN;
2 changes: 0 additions & 2 deletions client/app/hooks/use-toast.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
"use client"

// Inspired by react-hot-toast library
import * as React from "react"

Expand Down
2 changes: 1 addition & 1 deletion client/app/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ export default function App() {
}

export function HydrateFallback() {
return <p>Loading...</p>;
return <p>ローディング中...</p>;
}
3 changes: 2 additions & 1 deletion client/app/routes/_index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { useCallback, useEffect, useState } from "react";
import { useAuth } from "react-oidc-context";
import TodoForm from "~/components/todo-form";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { API_DOMAIN } from "~/constants";
import { useToast } from "~/hooks/use-toast";
import { Todo } from "~/types";

Expand All @@ -21,7 +22,7 @@ export default function Index() {
const token = auth.user?.access_token ?? '';
const fetchTodos = useCallback(async () => {
try {
const res = await fetch('http://localhost:8080/todos', {
const res = await fetch(`${API_DOMAIN}/todos`, {
headers: {
Authorization: `Bearer ${token}`,
},
Expand Down
6 changes: 6 additions & 0 deletions infra-ts/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.ts
!*.d.ts

# CDK asset staging directory
.cdk.staging
cdk.out
14 changes: 14 additions & 0 deletions infra-ts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Welcome to your CDK TypeScript project

This is a blank project for CDK development with TypeScript.

The `cdk.json` file tells the CDK Toolkit how to execute your app.

## Useful commands

* `npm run build` compile typescript to js
* `npm run watch` watch for changes and compile
* `npm run test` perform the jest unit tests
* `npm run cdk deploy` deploy this stack to your default AWS account/region
* `npm run cdk diff` compare deployed stack with current state
* `npm run cdk synth` emits the synthesized CloudFormation template
26 changes: 26 additions & 0 deletions infra-ts/bin/infra.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { FrontendStack, frontendStackProperties } from '../lib/frontend-stack';
import { CertificateStack, certificateStackProperties } from '../lib/certificate-stack';
import { Route53Stack, route53tackProperties } from '../lib/route53-stack';

const app = new cdk.App();
const route53Stack = new Route53Stack(app, "TodoListRoute53Stack", {
env: route53tackProperties.env,
crossRegionReferences: true,
...route53tackProperties.hostedZone,
});
const certificateStack = new CertificateStack(app, "TodoListCertificateStack", {
env: certificateStackProperties.env,
crossRegionReferences: true,
route53Stack,
...certificateStackProperties.certificate,
});
new FrontendStack(app, 'TodoListFrontendStack', {
env: frontendStackProperties.env,
crossRegionReferences: true,
route53Stack,
certificateStack,
...frontendStackProperties.props,
});
80 changes: 80 additions & 0 deletions infra-ts/cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
{
"app": "npx ts-node --prefer-ts-exts bin/infra.ts",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"**/*.d.ts",
"**/*.js",
"tsconfig.json",
"package*.json",
"yarn.lock",
"node_modules",
"test"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true,
"@aws-cdk/aws-eks:nodegroupNameAttribute": true,
"@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true,
"@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true,
"@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false,
"@aws-cdk/aws-s3:keepNotificationInImportedBucket": false,
"@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true,
"@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true,
"@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true,
"@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true,
"@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true,
"@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true,
"@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true,
"@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true
}
}
8 changes: 8 additions & 0 deletions infra-ts/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
testEnvironment: 'node',
roots: ['<rootDir>/test'],
testMatch: ['**/*.test.ts'],
transform: {
'^.+\\.tsx?$': 'ts-jest'
}
};
49 changes: 49 additions & 0 deletions infra-ts/lib/certificate-stack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import { ICertificateStack, StackProperties } from "./types";
import { Route53Stack } from "./route53-stack";

export interface ICertificateStackProps extends cdk.StackProps, ICertificateStack {
route53Stack?: Route53Stack
}

export class CertificateStack extends cdk.Stack {
readonly certificate: cdk.aws_certificatemanager.ICertificate

constructor(scope: Construct, id: string, props: ICertificateStackProps) {
super(scope, id, props)

const { certificateArn, certificateDomainName, route53Stack } = props;

if (certificateArn) {
this.certificate = cdk.aws_certificatemanager.Certificate.fromCertificateArn(
this,
"Default",
certificateArn,
);
} else if (certificateDomainName && route53Stack?.publicHostedZone) {
this.certificate = new cdk.aws_certificatemanager.Certificate(
this,
"TodoCertificate",
{
domainName: certificateDomainName,
validation: cdk.aws_certificatemanager.CertificateValidation.fromDns(
route53Stack.publicHostedZone
),
}
);
}
}
}

export const certificateStackProperties: StackProperties & {
certificate: ICertificateStack
} = {
env: {
account: process.env.CDK_DEFAULT_ACCOUNT,
region: "us-east-1",
},
certificate: {
certificateDomainName: "todolist.ryichk.com",
},
}
Loading

0 comments on commit 0ee492d

Please sign in to comment.