Skip to content

Commit

Permalink
[개인 미션 - 성능 오답노트] 솔로스타(추용혁) 미션 제출합니다. (#67)
Browse files Browse the repository at this point in the history
* chore: EOL을 auto로 설정

* feat: 이미지 크기 최적화

* chore: basepath 제거

* build: aws terraform 추가

* chore: 번들링 시 CSS가 별도 파일로 분리되도록 설정

* chore: TerserPlugin 적용하여 js 파일 minify

* chore: gzip compression 적용

* chore: Code Splitting 적용

* chore: CSS Minimization 적용

* chore: react-router-dom 버전 업데이트

* chore: webpack-bundle-analyzer 적용

* chore: gzip compression 제거

* chore: webp 퀄리티 80으로 조정 및 gif width를 300으로 설정

* chore: 불필요한 TerserPlugin 삭제 (webpack에서 기본적으로 사용)

* feat: 이미지 반응형 최적화 적용

* feat: 커스텀 커서에서 리플로우가 발생하지 않도록 수정

* feat: @react-icons/all-files 패키지를 사용하여 트리 쉐이킹 적용

* feat: getTrending API 호출이 session 단에서 캐싱될 수 있도록 구현

* fix: responsive 이미지에 잘못된 loader가 적용되는 오류 수정

* fix: trending gifs가 올바르게 캐싱되지 않는 문제 해결

* feat: GifItem에 React.memo 적용

* feat: 코드 스플리팅을 위한 route 단위의 React.lazy 적용

* build: CloudFront 추가

* chore: webpack serve 시 진행상황을 표시하도록 변경

* chore: npm run build 시 npm run build:prod로 포워딩되도록 설정

* feat: CustomCursor 비제어 방식으로 제어

* build: lighthouse ci 추가

* feat: 도움말 패널에서 레이아웃 시프트가 일어나지 않도록 수정

* feat: Gif 아이템 hover 시 레이아웃 시프트가 일어나지 않도록 수정

* feat: 캐시 버스팅 지원

* build: 인프라 캐시 정책 추가 및 http3 지원

* feat: 커스텀 커서 디바운싱

* feat: 구글 폰트 임베딩

* fix: 빠트린 캐시 버스팅

* feat: 중요 자원을 먼저 로드할 수 있도록 resource hint 추가

* feat: 인덱스 페이지는 분할되지 않도록 설정

* chore: responsive-loader의 outputPath를 static으로 설정

* build: cloudfront의 캐시 정책 min, default ttl을 1h로 설정

* refactor: responsive 이미지가 표시되는 방식 변경

* feat: 고화질 이미지 제거

* feat: 이미지 fetchpriority 설정 (hero를 높게, gif는 낮게)

* chore: css와 폰트 설정 분리

* feat: responsive-loader 에서 로드된 이미지가 캐시 버스팅될 수 있도록 설정

* chore: 파일명에서 불필요한 `..` 제거하도록 설정

* feat: 이미지 로딩 매커니즘 수정

* Revert "feat: 이미지 로딩 매커니즘 수정"

This reverts commit 96cb369.

* fix: fetchpriority 위치 수정

* build: webpack analyzer, sourcemap 제거

* feat: 히어로 이미지 preload 하도록 설정

* build: SPA를 위해 route fail 시 /index.html 서빙
  • Loading branch information
solo5star authored Sep 11, 2023
1 parent cf16a0c commit 9011648
Show file tree
Hide file tree
Showing 36 changed files with 11,050 additions and 4,804 deletions.
33 changes: 33 additions & 0 deletions .github/workflows/lighthouse-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Lighthouse
on: [push]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 18

- uses: actions/cache@v3
id: cache-npm
env:
cache-name: cache-node-modules
with:
# npm cache files are stored in `~/.npm` on Linux/macOS
path: ~/.npm
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-build-${{ env.cache-name }}-
${{ runner.os }}-build-
${{ runner.os }}-
- if: ${{ steps.cache-npm.outputs.cache-hit != 'true' }}
run: npm ci

- run: npm run build

- uses: treosh/lighthouse-ci-action@v10
with:
configPath: './lighthouserc.json'
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
"tabWidth": 2,
"singleQuote": true,
"bracketSpacing": true,
"printWidth": 100
"printWidth": 100,
"endOfLine": "auto"
}
31 changes: 15 additions & 16 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="./public/favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Josefin+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
/>
<title>memegle - gif search engine for you</title>
</head>

<body>
<div id="app"></div>
</body>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="./public/favicon.ico" />
<title>memegle - gif search engine for you</title>

<link rel="preload" as="image" type="image/webp"
imagesrcset="/static/hero.responsive-320.webp 320w,/static/hero.responsive-640.webp 640w,/static/hero.responsive-960.webp 960w" />
</head>

<body>
<div id="app"></div>
</body>

</html>
34 changes: 34 additions & 0 deletions infrastructure/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc
25 changes: 25 additions & 0 deletions infrastructure/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

144 changes: 144 additions & 0 deletions infrastructure/cloudfront.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
resource "aws_cloudfront_origin_access_control" "default" {
name = "CloudFront S3 OAC"
description = "CloudFront S3 OAC"
origin_access_control_origin_type = "s3"
signing_behavior = "always"
signing_protocol = "sigv4"
}

resource "aws_cloudfront_distribution" "default" {
origin {
domain_name = aws_s3_bucket.main.bucket_regional_domain_name
origin_id = aws_s3_bucket.main.id

origin_access_control_id = aws_cloudfront_origin_access_control.default.id
}

enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"

http_version = "http2and3"

custom_error_response {
error_code = 403
response_code = 200
response_page_path = "/index.html"
}

custom_error_response {
error_code = 404
response_code = 200
response_page_path = "/index.html"
}

default_cache_behavior {
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.main.id
compress = true
cache_policy_id = aws_cloudfront_cache_policy.assets.id
response_headers_policy_id = aws_cloudfront_response_headers_policy.assets.id
viewer_protocol_policy = "redirect-to-https"
}

ordered_cache_behavior {
path_pattern = "/index.html"
allowed_methods = ["GET", "HEAD"]
cached_methods = ["GET", "HEAD"]
target_origin_id = aws_s3_bucket.main.id
compress = true
cache_policy_id = aws_cloudfront_cache_policy.html.id
response_headers_policy_id = aws_cloudfront_response_headers_policy.html.id
viewer_protocol_policy = "redirect-to-https"
}

viewer_certificate {
cloudfront_default_certificate = true
}

restrictions {
geo_restriction {
restriction_type = "none"
}
}
}

resource "aws_cloudfront_cache_policy" "assets" {
name = "AssetsCachePolicy"

default_ttl = 31536000 // 365d
min_ttl = 31536000 // 365d
max_ttl = 31536000 // 365d

parameters_in_cache_key_and_forwarded_to_origin {
enable_accept_encoding_brotli = true
enable_accept_encoding_gzip = true

cookies_config {
cookie_behavior = "none"
}
query_strings_config {
query_string_behavior = "none"
}
headers_config {
header_behavior = "none"
}
}
}

resource "aws_cloudfront_cache_policy" "html" {
name = "HtmlCachePolicy"

default_ttl = 3600 // 1h
min_ttl = 3600 // 1h
max_ttl = 2592000 // 30d

parameters_in_cache_key_and_forwarded_to_origin {
enable_accept_encoding_brotli = true
enable_accept_encoding_gzip = true

cookies_config {
cookie_behavior = "none"
}
query_strings_config {
query_string_behavior = "none"
}
headers_config {
header_behavior = "none"
}
}
}

resource "aws_cloudfront_response_headers_policy" "assets" {
name = "Assets"
comment = "Response Headers for assets (includes images, js, css)"

custom_headers_config {
items {
header = "Cache-Control"
override = true
value = format(
"immutable, max-age=%d",
aws_cloudfront_cache_policy.assets.default_ttl
)
}
}
}

resource "aws_cloudfront_response_headers_policy" "html" {
name = "Html"
comment = "Response Headers for html"

custom_headers_config {
items {
header = "Cache-Control"
override = true
// max-age=1h, stale-while-revalidate=15d
value = format(
"max-age=3600, stale-while-revalidate=%d",
aws_cloudfront_cache_policy.html.default_ttl
)
}
}
}
1 change: 1 addition & 0 deletions infrastructure/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aws s3 sync ./dist s3://perf-basecamp-solo5star
12 changes: 12 additions & 0 deletions infrastructure/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}

provider "aws" {
region = "ap-northeast-2"
}
40 changes: 40 additions & 0 deletions infrastructure/s3.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
resource "aws_s3_bucket" "main" {
bucket = "perf-basecamp-solo5star"
}

resource "aws_s3_bucket_public_access_block" "default" {
bucket = aws_s3_bucket.main.id

block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}

resource "aws_s3_bucket_policy" "default" {
bucket = aws_s3_bucket.main.id
depends_on = [aws_s3_bucket_public_access_block.default]
policy = data.aws_iam_policy_document.default.json
}

data "aws_iam_policy_document" "default" {
statement {
sid = "Allow all HTTP from cloudfront"
principals {
type = "Service"
identifiers = ["cloudfront.amazonaws.com"]
}
actions = [
"s3:GetObject"
]
resources = [
"${aws_s3_bucket.main.arn}/*"
]
effect = "Allow"
condition {
test = "StringEquals"
variable = "AWS:SourceArn"
values = [aws_cloudfront_distribution.default.arn]
}
}
}
7 changes: 7 additions & 0 deletions lighthouserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"ci": {
"collect": {
"staticDistDir": "./dist"
}
}
}
Loading

0 comments on commit 9011648

Please sign in to comment.