Compare commits
4 Commits
215c0d72fd
...
4847424d9b
Author | SHA1 | Date | |
---|---|---|---|
4847424d9b | |||
48d86e4479 | |||
fab8c22e0c | |||
890087a572 |
@ -9,17 +9,13 @@ export const main: APIGatewayProxyHandlerV2 = async (event) => {
|
|||||||
endpoint: `https://${domainName}/${stage}`,
|
endpoint: `https://${domainName}/${stage}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Received event: ", JSON.stringify(event, null, 2));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (routeKey) {
|
switch (routeKey) {
|
||||||
case '$connect':
|
case '$connect':
|
||||||
console.log(`New connection: ${connectionId}`);
|
return { statusCode: 200, body: 'Connected' };
|
||||||
return { statusCode: 200, body: 'Connected' };
|
|
||||||
|
|
||||||
case '$disconnect':
|
case '$disconnect':
|
||||||
console.log(`Disconnected: ${connectionId}`);
|
return { statusCode: 200, body: 'Disconnected' };
|
||||||
return { statusCode: 200, body: 'Disconnected' };
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
console.log(`Received message: ${body}`);
|
console.log(`Received message: ${body}`);
|
||||||
|
29
buildspec.yml
Normal file
29
buildspec.yml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
version: 0.2
|
||||||
|
|
||||||
|
phases:
|
||||||
|
install:
|
||||||
|
runtime-versions:
|
||||||
|
nodejs: 18
|
||||||
|
commands:
|
||||||
|
- echo cloning repository...
|
||||||
|
- git clone https://git.falsy.cat/falsycat/imbusy/ .
|
||||||
|
- find
|
||||||
|
|
||||||
|
- echo installing dependencies...
|
||||||
|
- cd frontend && npm ci && cd ..
|
||||||
|
- cd backend && npm ci && cd ..
|
||||||
|
build:
|
||||||
|
commands:
|
||||||
|
- echo building frontend...
|
||||||
|
- cd frontend && npm run build && cd ..
|
||||||
|
|
||||||
|
- echo building backend...
|
||||||
|
- cd backend && npm run build && cd ..
|
||||||
|
post_build:
|
||||||
|
commands:
|
||||||
|
- echo deploying frontend...
|
||||||
|
- aws s3 sync frontend/dist/ s3://$IMBUSY_FE_BUCKET --delete
|
||||||
|
|
||||||
|
- echo deploying backend...
|
||||||
|
- cd backend/dist && zip -r ../../backend.zip . && cd ../..
|
||||||
|
- aws s3 cp backend.zip s3://$IMBUSY_BE_BUCKET
|
@ -1,15 +1,54 @@
|
|||||||
imbusy-fe
|
# React + TypeScript + Vite
|
||||||
====
|
|
||||||
|
|
||||||
imbusy frontend webui
|
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
||||||
|
|
||||||
|
Currently, two official plugins are available:
|
||||||
|
|
||||||
## Commands
|
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) for Fast Refresh
|
||||||
|
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
|
||||||
|
|
||||||
```bash
|
## Expanding the ESLint configuration
|
||||||
# starting dev server
|
|
||||||
npm run dev
|
|
||||||
|
|
||||||
# building
|
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||||
npm run build
|
|
||||||
|
```js
|
||||||
|
export default tseslint.config({
|
||||||
|
extends: [
|
||||||
|
// Remove ...tseslint.configs.recommended and replace with this
|
||||||
|
...tseslint.configs.recommendedTypeChecked,
|
||||||
|
// Alternatively, use this for stricter rules
|
||||||
|
...tseslint.configs.strictTypeChecked,
|
||||||
|
// Optionally, add this for stylistic rules
|
||||||
|
...tseslint.configs.stylisticTypeChecked,
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
// other options...
|
||||||
|
parserOptions: {
|
||||||
|
project: ['./tsconfig.node.json', './tsconfig.app.json'],
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||||
|
|
||||||
|
```js
|
||||||
|
// eslint.config.js
|
||||||
|
import reactX from 'eslint-plugin-react-x'
|
||||||
|
import reactDom from 'eslint-plugin-react-dom'
|
||||||
|
|
||||||
|
export default tseslint.config({
|
||||||
|
plugins: {
|
||||||
|
// Add the react-x and react-dom plugins
|
||||||
|
'react-x': reactX,
|
||||||
|
'react-dom': reactDom,
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
// other rules...
|
||||||
|
// Enable its recommended typescript rules
|
||||||
|
...reactX.configs['recommended-typescript'].rules,
|
||||||
|
...reactDom.configs.recommended.rules,
|
||||||
|
},
|
||||||
|
})
|
||||||
```
|
```
|
||||||
|
@ -2,32 +2,27 @@ import js from '@eslint/js'
|
|||||||
import globals from 'globals'
|
import globals from 'globals'
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
import reactHooks from 'eslint-plugin-react-hooks'
|
||||||
import reactRefresh from 'eslint-plugin-react-refresh'
|
import reactRefresh from 'eslint-plugin-react-refresh'
|
||||||
|
import tseslint from 'typescript-eslint'
|
||||||
|
|
||||||
export default [
|
export default tseslint.config(
|
||||||
{ ignores: ['dist'] },
|
{ ignores: ['dist'] },
|
||||||
{
|
{
|
||||||
files: ['**/*.{js,jsx}'],
|
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
||||||
|
files: ['**/*.{ts,tsx}'],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
globals: globals.browser,
|
globals: globals.browser,
|
||||||
parserOptions: {
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
ecmaFeatures: { jsx: true },
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
'react-hooks': reactHooks,
|
'react-hooks': reactHooks,
|
||||||
'react-refresh': reactRefresh,
|
'react-refresh': reactRefresh,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
...js.configs.recommended.rules,
|
|
||||||
...reactHooks.configs.recommended.rules,
|
...reactHooks.configs.recommended.rules,
|
||||||
'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
|
|
||||||
'react-refresh/only-export-components': [
|
'react-refresh/only-export-components': [
|
||||||
'warn',
|
'warn',
|
||||||
{ allowConstantExport: true },
|
{ allowConstantExport: true },
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
)
|
||||||
|
@ -4,10 +4,10 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Vite + React</title>
|
<title>Vite + React + TS</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
<script type="module" src="/src/main.jsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
796
frontend/package-lock.json
generated
796
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -5,7 +5,7 @@
|
|||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "tsc -b && vite build",
|
||||||
"lint": "eslint .",
|
"lint": "eslint .",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
@ -22,6 +22,8 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
|
"typescript": "~5.8.3",
|
||||||
|
"typescript-eslint": "^8.30.1",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ function App() {
|
|||||||
count is {count}
|
count is {count}
|
||||||
</button>
|
</button>
|
||||||
<p>
|
<p>
|
||||||
Edit <code>src/App.jsx</code> and save to test HMR
|
Edit <code>src/App.tsx</code> and save to test HMR
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p className="read-the-docs">
|
<p className="read-the-docs">
|
@ -1,9 +1,9 @@
|
|||||||
import { StrictMode } from 'react'
|
import { StrictMode } from 'react'
|
||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import './index.css'
|
import './index.css'
|
||||||
import App from './App.jsx'
|
import App from './App.tsx'
|
||||||
|
|
||||||
createRoot(document.getElementById('root')).render(
|
createRoot(document.getElementById('root')!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<App />
|
<App />
|
||||||
</StrictMode>,
|
</StrictMode>,
|
1
frontend/src/vite-env.d.ts
vendored
Normal file
1
frontend/src/vite-env.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/// <reference types="vite/client" />
|
27
frontend/tsconfig.app.json
Normal file
27
frontend/tsconfig.app.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||||
|
"target": "ES2020",
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
7
frontend/tsconfig.json
Normal file
7
frontend/tsconfig.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{ "path": "./tsconfig.app.json" },
|
||||||
|
{ "path": "./tsconfig.node.json" }
|
||||||
|
]
|
||||||
|
}
|
25
frontend/tsconfig.node.json
Normal file
25
frontend/tsconfig.node.json
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||||
|
"target": "ES2022",
|
||||||
|
"lib": ["ES2023"],
|
||||||
|
"module": "ESNext",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
/* Bundler mode */
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
/* Linting */
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"erasableSyntaxOnly": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noUncheckedSideEffectImports": true
|
||||||
|
},
|
||||||
|
"include": ["vite.config.ts"]
|
||||||
|
}
|
@ -7,18 +7,11 @@ import * as common from "./common";
|
|||||||
const tags = common.tags;
|
const tags = common.tags;
|
||||||
const prefix = `${common.prefix}-backend`;
|
const prefix = `${common.prefix}-backend`;
|
||||||
|
|
||||||
console.log("building backend...");
|
|
||||||
esbuild.buildSync({
|
|
||||||
entryPoints: ["../backend/src/index.ts"],
|
|
||||||
outfile: "../backend/dist/index.js",
|
|
||||||
bundle: true,
|
|
||||||
platform: "node",
|
|
||||||
target: "node18",
|
|
||||||
minify: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// ---- program bucket ----
|
||||||
|
export const bucket = new aws.s3.Bucket(`${prefix}-bucket`);
|
||||||
|
|
||||||
// ---- Lambda ----
|
// ---- api lambda ----
|
||||||
const lambdaRole = new aws.iam.Role(`${prefix}-lambda-role`, {
|
const lambdaRole = new aws.iam.Role(`${prefix}-lambda-role`, {
|
||||||
tags,
|
tags,
|
||||||
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
|
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({
|
||||||
@ -35,9 +28,8 @@ const lambda = new aws.lambda.Function(`${prefix}-lambda`, {
|
|||||||
runtime: "nodejs18.x",
|
runtime: "nodejs18.x",
|
||||||
handler: "index.main",
|
handler: "index.main",
|
||||||
role: lambdaRole.arn,
|
role: lambdaRole.arn,
|
||||||
code: new pulumi.asset.AssetArchive({
|
s3Bucket: bucket.arn,
|
||||||
".": new pulumi.asset.FileArchive("../backend/dist/"),
|
s3Key: "lambda.zip",
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
new aws.cloudwatch.LogGroup(`${prefix}-lambda-log-group`, {
|
new aws.cloudwatch.LogGroup(`${prefix}-lambda-log-group`, {
|
||||||
name: pulumi.interpolate`/aws/lambda/${lambda.name}`,
|
name: pulumi.interpolate`/aws/lambda/${lambda.name}`,
|
||||||
@ -45,8 +37,22 @@ new aws.cloudwatch.LogGroup(`${prefix}-lambda-log-group`, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ---- database ----
|
||||||
|
new aws.dynamodb.Table(`${prefix}-db`, {
|
||||||
|
tags,
|
||||||
|
name: "objects",
|
||||||
|
attributes: [
|
||||||
|
{ name: "userId", type: "S", },
|
||||||
|
{ name: "sortKey", type: "S", },
|
||||||
|
],
|
||||||
|
hashKey: "userId",
|
||||||
|
rangeKey: "sortKey",
|
||||||
|
billingMode: "PAY_PER_REQUEST",
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// ---- API Gateway ----
|
// ---- API Gateway ----
|
||||||
const api = new aws.apigatewayv2.Api(`${prefix}-api`, {
|
export const api = new aws.apigatewayv2.Api(`${prefix}-api`, {
|
||||||
tags,
|
tags,
|
||||||
protocolType: "WEBSOCKET",
|
protocolType: "WEBSOCKET",
|
||||||
routeSelectionExpression: "$request.body.action",
|
routeSelectionExpression: "$request.body.action",
|
||||||
@ -91,4 +97,19 @@ new aws.iam.RolePolicy(`${prefix}-api-role-policy`, {
|
|||||||
}`,
|
}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const endpoint = pulumi.interpolate`${api.apiEndpoint}`;
|
|
||||||
|
// ---- cognito ----
|
||||||
|
const userPool = new aws.cognito.UserPool(`${prefix}-cognito-userpool`, {
|
||||||
|
tags,
|
||||||
|
autoVerifiedAttributes: ["email"],
|
||||||
|
usernameAttributes: ["email"],
|
||||||
|
passwordPolicy: {
|
||||||
|
minimumLength: 8,
|
||||||
|
requireSymbols: true,
|
||||||
|
requireNumbers: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
new aws.cognito.UserPoolClient(`${prefix}-cognito-userpool-cli`, {
|
||||||
|
userPoolId: userPool.id,
|
||||||
|
generateSecret: false,
|
||||||
|
});
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as pulumi from "@pulumi/pulumi";
|
import * as pulumi from "@pulumi/pulumi";
|
||||||
|
import * as aws from "@pulumi/aws";
|
||||||
|
|
||||||
export const tags = {
|
export const tags = {
|
||||||
project: pulumi.getProject(),
|
project: pulumi.getProject(),
|
||||||
@ -6,3 +7,5 @@ export const tags = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const prefix = `${tags.project}-${tags.env}`;
|
export const prefix = `${tags.project}-${tags.env}`;
|
||||||
|
|
||||||
|
export const logGroupPrefix = `/falsycat/${tags.project}/${tags.env}/`;
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
import * as aws from "@pulumi/aws";
|
|
||||||
import * as pulumi from "@pulumi/pulumi";
|
|
||||||
|
|
||||||
import * as common from "./common";
|
|
||||||
|
|
||||||
const tags = common.tags;
|
|
||||||
const prefix = `${common.prefix}-database`;
|
|
||||||
|
|
||||||
new aws.dynamodb.Table(`${prefix}-users`, {
|
|
||||||
tags,
|
|
||||||
name: "Users", // これがDynamoDBのTableNameになる
|
|
||||||
attributes: [
|
|
||||||
{ name: "id", type: "S", },
|
|
||||||
],
|
|
||||||
hashKey: "id",
|
|
||||||
billingMode: "PAY_PER_REQUEST",
|
|
||||||
});
|
|
79
infra/deployment.ts
Normal file
79
infra/deployment.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import * as pulumi from "@pulumi/pulumi";
|
||||||
|
import * as aws from "@pulumi/aws";
|
||||||
|
|
||||||
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
import * as common from "./common";
|
||||||
|
|
||||||
|
import * as backend from "./backend";
|
||||||
|
import * as frontend from "./frontend";
|
||||||
|
|
||||||
|
const tags = common.tags;
|
||||||
|
const prefix = `${common.prefix}-deployment`;
|
||||||
|
|
||||||
|
|
||||||
|
// ---- role ----
|
||||||
|
const role = new aws.iam.Role(`${prefix}-role`, {
|
||||||
|
tags,
|
||||||
|
assumeRolePolicy: aws.iam.assumeRolePolicyForPrincipal({ Service: "codebuild.amazonaws.com" }),
|
||||||
|
});
|
||||||
|
new aws.iam.RolePolicyAttachment(`${prefix}-policy-codebuild`, {
|
||||||
|
role: role.name,
|
||||||
|
policyArn: aws.iam.ManagedPolicies.AWSCodeBuildDeveloperAccess,
|
||||||
|
});
|
||||||
|
new aws.iam.RolePolicy(`${prefix}-role-policy`, {
|
||||||
|
role: role.name,
|
||||||
|
policy: pulumi.all([backend.bucket.arn, frontend.bucket.arn]).apply(([be, fe]) => JSON.stringify({
|
||||||
|
Version: "2012-10-17",
|
||||||
|
Statement: [
|
||||||
|
{
|
||||||
|
Effect: "Allow",
|
||||||
|
Action: [
|
||||||
|
"s3:GetObject",
|
||||||
|
"s3:PutObject",
|
||||||
|
"s3:DeleteObject"
|
||||||
|
],
|
||||||
|
Resource: [ `${be}/*`, `${fe}/*`, ],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Effect: "Allow",
|
||||||
|
Action: [
|
||||||
|
"s3:ListBucket",
|
||||||
|
],
|
||||||
|
Resource: [ be, fe, ],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Effect: "Allow",
|
||||||
|
Action: [
|
||||||
|
"logs:CreateLogGroup",
|
||||||
|
"logs:CreateLogStream",
|
||||||
|
"logs:PutLogEvents",
|
||||||
|
],
|
||||||
|
Resource: "*",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// ---- codebuild ----
|
||||||
|
const codebuild = new aws.codebuild.Project(`${prefix}-codebuild`, {
|
||||||
|
tags,
|
||||||
|
source: {
|
||||||
|
type: "NO_SOURCE",
|
||||||
|
buildspec: fs.readFileSync("../buildspec.yml", "utf-8"),
|
||||||
|
},
|
||||||
|
environment: {
|
||||||
|
computeType: "BUILD_GENERAL1_SMALL",
|
||||||
|
image: "aws/codebuild/standard:7.0",
|
||||||
|
type: "LINUX_CONTAINER",
|
||||||
|
environmentVariables: [
|
||||||
|
{ name: "IMBUSY_BE_BUCKET", value: backend.bucket.bucket, },
|
||||||
|
{ name: "IMBUSY_FE_BUCKET", value: frontend.bucket.bucket, },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
serviceRole: role.arn,
|
||||||
|
artifacts: {
|
||||||
|
type: "NO_ARTIFACTS",
|
||||||
|
},
|
||||||
|
});
|
@ -10,33 +10,18 @@ import * as common from "./common";
|
|||||||
const tags = common.tags;
|
const tags = common.tags;
|
||||||
const prefix = `${common.prefix}-frontend`;
|
const prefix = `${common.prefix}-frontend`;
|
||||||
|
|
||||||
// ---- infra resouces ----
|
// ---- bucket ----
|
||||||
const bucket = new aws.s3.Bucket(`${prefix}-bucket`, {tags});
|
export const bucket = new aws.s3.Bucket(`${prefix}-bucket`, {tags});
|
||||||
|
const bucketOai = new aws.cloudfront.OriginAccessIdentity(`${prefix}-oai`);
|
||||||
const oai = new aws.cloudfront.OriginAccessIdentity(`${prefix}-oai`);
|
|
||||||
|
|
||||||
const bucketPolicy = new aws.s3.BucketPolicy(`${prefix}-bucket-policy`, {
|
|
||||||
bucket: bucket.bucket,
|
|
||||||
policy: pulumi.all([oai.iamArn, bucket.bucket]).apply(([a, b]) => JSON.stringify({
|
|
||||||
Version: "2012-10-17",
|
|
||||||
Statement: [{
|
|
||||||
Effect: "Allow",
|
|
||||||
Principal: {
|
|
||||||
AWS: a,
|
|
||||||
},
|
|
||||||
Action: ["s3:GetObject"],
|
|
||||||
Resource: [`arn:aws:s3:::${b}/*`],
|
|
||||||
}],
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// ---- cloudfront ----
|
||||||
export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`, {
|
export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`, {
|
||||||
tags,
|
tags,
|
||||||
origins: [{
|
origins: [{
|
||||||
domainName: bucket.bucketRegionalDomainName,
|
domainName: bucket.bucketRegionalDomainName,
|
||||||
originId: bucket.arn,
|
originId: bucket.arn,
|
||||||
s3OriginConfig: {
|
s3OriginConfig: {
|
||||||
originAccessIdentity: oai.cloudfrontAccessIdentityPath,
|
originAccessIdentity: bucketOai.cloudfrontAccessIdentityPath,
|
||||||
},
|
},
|
||||||
}],
|
}],
|
||||||
enabled: true,
|
enabled: true,
|
||||||
@ -51,6 +36,18 @@ export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`
|
|||||||
cookies: { forward: "none" },
|
cookies: { forward: "none" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
customErrorResponses: [
|
||||||
|
{
|
||||||
|
errorCode: 403,
|
||||||
|
responseCode: 200,
|
||||||
|
responsePagePath: "/index.html",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
errorCode: 404,
|
||||||
|
responseCode: 200,
|
||||||
|
responsePagePath: "/index.html",
|
||||||
|
},
|
||||||
|
],
|
||||||
priceClass: "PriceClass_100",
|
priceClass: "PriceClass_100",
|
||||||
restrictions: {
|
restrictions: {
|
||||||
geoRestriction: {
|
geoRestriction: {
|
||||||
@ -61,23 +58,3 @@ export const cloudfront = new aws.cloudfront.Distribution(`${prefix}-cloudfront`
|
|||||||
cloudfrontDefaultCertificate: true,
|
cloudfrontDefaultCertificate: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---- file uploads ----
|
|
||||||
(async () => {
|
|
||||||
const cwd = "../frontend/dist/";
|
|
||||||
|
|
||||||
const stats = await fs.stat(cwd);
|
|
||||||
if (!stats.isDirectory()) {
|
|
||||||
throw new Error("build the frontend firstly");
|
|
||||||
}
|
|
||||||
|
|
||||||
const files = await fg("**/*", {cwd, dot: true});
|
|
||||||
for (const file of files) {
|
|
||||||
new aws.s3.BucketObject(file, {
|
|
||||||
bucket: bucket,
|
|
||||||
source: new pulumi.asset.FileAsset(cwd+file),
|
|
||||||
contentType: mime.getType(file) || "application/octet-stream",
|
|
||||||
key: file,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
|
@ -4,7 +4,7 @@ import * as aws from "@pulumi/aws";
|
|||||||
import * as backend from "./backend";
|
import * as backend from "./backend";
|
||||||
import * as frontend from "./frontend";
|
import * as frontend from "./frontend";
|
||||||
|
|
||||||
import "./database";
|
import "./deployment";
|
||||||
|
|
||||||
export const frontendDomain = frontend.cloudfront.domainName;
|
export const frontendDomain = frontend.cloudfront.domainName;
|
||||||
export const backendEndpoint = backend.endpoint;
|
export const backendEndpoint = backend.api.apiEndpoint;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user