Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[개인 미션 - 성능 오답노트] 도담(김민재) 미션 제출합니다. #99

Merged
merged 12 commits into from Sep 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 4 additions & 1 deletion index.html
Expand Up @@ -8,8 +8,11 @@
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="preload"
as="style"
Comment on lines +11 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

폰트에 preload 속성을 사용했네요! 하나 배워갑니다 😊

href="https://fonts.googleapis.com/css2?family=Josefin+Sans:ital,wght@0,400;0,700;1,400;1,700&display=swap"
rel="stylesheet"
onload="this.onload=null; this.rel='stylesheet'"
crossorigin
/>
<title>memegle - gif search engine for you</title>
</head>
Expand Down
23 changes: 16 additions & 7 deletions package.json
Expand Up @@ -8,12 +8,13 @@
"build:prod": "webpack --mode=production --node-env=production",
"watch": "webpack --watch",
"serve": "webpack serve --mode=development",
"serve:prod": "webpack serve --mode=production --node-env=production",
"prettier": "prettier --write .",
"deploy": "npm run build:prod && npx gh-pages -d dist"
},
"keywords": [],
"author": "woowacourse",
"homepage": "https://{username}.github.io/perf-basecamp",
"homepage": "https://d0dam.github.io/perf-basecamp",
"license": "MIT",
"dependencies": {
"@giphy/js-fetch-api": "^4.1.1",
Expand All @@ -33,13 +34,14 @@
"@types/react": "^18.0.17",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/eslint-plugin": "^5.0.0",
"@webpack-cli/generators": "^2.2.0",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^5.0.1",
"dotenv-webpack": "^7.0.3",
"eslint": "^7.32.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard-with-typescript": "^22.0.0",
"eslint-plugin-hooks": "^0.4.3",
Expand All @@ -50,21 +52,28 @@
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"html-webpack-plugin": "^5.3.2",
"mini-css-extract-plugin": "^2.7.6",
"prettier": "^2.3.2",
"style-loader": "^3.2.1",
"ts-loader": "^9.3.1",
"typescript": "^4.8.2",
"webpack": "^5.50.0",
"webpack": "^5.88.2",
"webpack-bundle-analyzer": "^4.9.1",
"webpack-cli": "^4.7.2",
"webpack-dev-server": "^3.11.2"
},
"babel": {
"presets": [
"@babel/preset-env",
"@babel/preset-react"
"@babel/preset-react",
{
"modules": false
}
Comment on lines +67 to +70

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 modules: false 속성을 주면 어떤 효과가 있나요??

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"@babel/preset-env" 프리셋에 속하는 설정입니다~!
"modules": false 를 하게 되면 Babel이 모듈 코드 변환을 하지 않습니다..!
번들러(bundler)를 사용하는 프로젝트에서 번들러는 프로젝트의 모든 모듈을 하나의 번들로 묶어주기 때문에 모듈 코드 변환이 필요하지 않습니다! 그래서 이 역할을 babel 에서 위임해준 역할이라고 보면 좋을 것 같습니다!

],
"plugins": [
"@babel/plugin-transform-runtime"
]
}
},
"sideEffects": [
"*.css"
]
Comment on lines +76 to +78

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sideEffects를 추가했을 때 체감되는 효과도 궁금하네용

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

글쎄요... 체감..? 까지는 모르겠지만 굳이 불필요한 작업을 막을 수 있다는 면에서 한 번 사용해 보면 좋다고 생각했습니다!

}
7 changes: 4 additions & 3 deletions src/App.tsx
@@ -1,7 +1,8 @@
import { lazy } from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';

import Home from './pages/Home/Home';
import Search from './pages/Search/Search';
const Home = lazy(() => import(/* webpackChunkName: "home" */ './pages/Home/Home'));
const Search = lazy(() => import(/* webpackChunkName: "search" */ './pages/Search/Search'));

import NavBar from './components/NavBar/NavBar';
import Footer from './components/Footer/Footer';
Expand All @@ -10,7 +11,7 @@ import './App.css';

const App = () => {
return (
<Router basename={'/perf-basecamp'}>
<Router>
<NavBar />
<Routes>
<Route path="/" element={<Home />} />
Expand Down
Binary file removed src/assets/images/find.gif
Binary file not shown.
Binary file added src/assets/images/find.mp4
Binary file not shown.
Binary file removed src/assets/images/free.gif
Binary file not shown.
Binary file added src/assets/images/free.mp4
Binary file not shown.
Binary file removed src/assets/images/hero.png
Binary file not shown.
Binary file added src/assets/images/hero.webp
Binary file not shown.
Binary file removed src/assets/images/trending.gif
Binary file not shown.
Binary file added src/assets/images/trending.mp4
Binary file not shown.
3 changes: 3 additions & 0 deletions src/data/gifCache.ts
@@ -0,0 +1,3 @@
import type { GifImageModel } from '../models/image/gifImage';

export let gifCache: GifImageModel[] = [];
7 changes: 6 additions & 1 deletion src/index.tsx
@@ -1,5 +1,10 @@
import { createRoot } from 'react-dom/client';
import App from './App';
import { Suspense } from 'react';

const root = createRoot(document.getElementById('app')!);
root.render(<App />);
root.render(
<Suspense fallback={<div>로딩중입니다.</div>}>
<App />
</Suspense>
);
11 changes: 6 additions & 5 deletions src/pages/Home/Home.tsx
Expand Up @@ -2,10 +2,10 @@ import { useRef } from 'react';
import { Link } from 'react-router-dom';
import classNames from 'classnames/bind';

import heroImage from '../../assets/images/hero.png';
import trendingGif from '../../assets/images/trending.gif';
import findGif from '../../assets/images/find.gif';
import freeGif from '../../assets/images/free.gif';
import heroImage from '../../assets/images/hero.webp';
import trendingGif from '../../assets/images/trending.mp4';
import findGif from '../../assets/images/find.mp4';
import freeGif from '../../assets/images/free.mp4';

import FeatureItem from './components/FeatureItem/FeatureItem';
import CustomCursor from './components/CustomCursor/CustomCursor';
Expand All @@ -19,7 +19,8 @@ const Home = () => {
return (
<>
<section className={styles.heroSection}>
<img className={styles.heroImage} src={heroImage} alt="hero image" />
<img className={styles.heroImage} src={heroImage} alt="hero" />

<div className={styles.projectTitle}>
<h1 className={styles.title}>Memegle</h1>
<h3 className={styles.subtitle}>gif search engine for you</h3>
Expand Down
3 changes: 1 addition & 2 deletions src/pages/Home/components/CustomCursor/CustomCursor.tsx
Expand Up @@ -14,8 +14,7 @@ const CustomCursor = ({ text = '' }: CustomCursorProps) => {

useEffect(() => {
if (cursorRef.current) {
cursorRef.current.style.top = `${mousePosition.pageY}px`;
cursorRef.current.style.left = `${mousePosition.pageX}px`;
cursorRef.current.style.transform = `translate(${mousePosition.pageX}px, ${mousePosition.pageY}px)`;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tailwindlabs/tailwindcss#1380
https://abcdqbbq.tistory.com/103
https://stackoverflow.com/questions/22111256/translate3d-vs-translate-performance

translate3d 함수나 will-chage 속성을 사용할 수도 있겠네요. 하지만 위의 글처럼 여러 의견이 있습니다. 도담의 생각은 어떤지 궁금합니다!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이건 잘 몰랐는데, 감사합니다!
저는 아무래도 함수 이름 자체가 translate3d 이다보니 굳이 2d의 움직임을 표현할 때 해당 함수를 사용하지는 않을 것 같아요! 물론 대체적으로 속도 면에서는 우세하다고 이야기 하지만.. 큰 움직임과 그래픽이 들어간 것이 아닌 이상 저는 그냥 translate 함수를 그냥 사용할 것 같아요!

}
}, [mousePosition]);

Expand Down
2 changes: 1 addition & 1 deletion src/pages/Home/components/FeatureItem/FeatureItem.tsx
Expand Up @@ -8,7 +8,7 @@ type FeatureItemProps = {
const FeatureItem = ({ title, imageSrc }: FeatureItemProps) => {
return (
<div className={styles.featureItem}>
<img className={styles.featureImage} src={imageSrc} />
<video src={imageSrc} className={styles.featureImage} autoPlay muted loop playsInline />
<div className={styles.featureTitleBg}></div>
<h4 className={styles.featureTitle}>{title}</h4>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Search/components/GifItem/GifItem.module.css
Expand Up @@ -14,7 +14,7 @@
}

.gifItem:hover {
top: -0.75rem;
transform: translateY(-0.75rem);
}

.gifImage {
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Search/components/GifItem/GifItem.tsx
@@ -1,5 +1,5 @@
import { memo } from 'react';
import { GifImageModel } from '../../../../models/image/gifImage';

import styles from './GifItem.module.css';

type GifItemProps = Omit<GifImageModel, 'id'>;
Expand All @@ -16,4 +16,4 @@ const GifItem = ({ imageUrl = '', title = '' }: GifItemProps) => {
);
};

export default GifItem;
export default memo(GifItem);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

2 changes: 1 addition & 1 deletion src/pages/Search/components/HelpPanel/HelpPanel.module.css
Expand Up @@ -24,7 +24,7 @@
}

.selectedItemContainer.showSheet {
right: 0;
transform: translateX(-320px);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

opacity: 1;
}

Expand Down
16 changes: 12 additions & 4 deletions src/pages/Search/hooks/useGifSearch.tsx
Expand Up @@ -2,6 +2,7 @@ import { ChangeEvent, useEffect, useState } from 'react';

import { gifAPIService } from '../../../apis/gifAPIService';
import { GifImageModel } from '../../../models/image/gifImage';
import { gifCache } from '../../../data/gifCache';

const DEFAULT_PAGE_INDEX = 0;

Expand All @@ -12,7 +13,7 @@ export const SEARCH_STATUS = {
NO_RESULT: 'NO_RESULT'
} as const;

export type SearchStatus = typeof SEARCH_STATUS[keyof typeof SEARCH_STATUS];
export type SearchStatus = (typeof SEARCH_STATUS)[keyof typeof SEARCH_STATUS];

const useGifSearch = () => {
const [status, setStatus] = useState<SearchStatus>(SEARCH_STATUS.BEFORE_SEARCH);
Expand Down Expand Up @@ -57,11 +58,18 @@ const useGifSearch = () => {
useEffect(() => {
const fetch = async () => {
if (status === SEARCH_STATUS.BEFORE_SEARCH) {
const gifs: GifImageModel[] = await gifAPIService.getTrending();

setGifList(gifs);
if (gifCache.length === 0) {
const gifs: GifImageModel[] = await gifAPIService.getTrending();

gifCache.push(...gifs);
setGifList(gifs);
}
if (gifCache.length !== 0) {
setGifList(gifCache);
}
Comment on lines +61 to +69

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 APIService에서 캐싱 작업을 처리했는데, 도담은 사용하는 곳에서 처리를 해주었네요! 저는 커스텀 훅에서는 외부에서 데이터를 받아올 뿐 어디서 받아오는지 몰라야 한다고 생각했습니다. 도담은 이 부분에 대해서 어떻게 생각하나요??

그리고 지금은 새로고침하면 캐싱된 값이 초기화되는데, 캐시를 유지하고 싶으면 어떻게 할 수 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 커스텀 훅에서는 외부에서 데이터를 받아올 뿐 어디서 받아오는지 몰라야 한다고 생각했습니다.

저도 황펭의 의견에 동의합니다! 하지만 이번 미션에서 구현할 때는 내장 메서드에 의존하지 않고 어떻게 캐시를 만들면 좋을 지 고민하다보니 결국 저장을 할만한 공간이 필요하다고 판단하고 좀 특이하게(?) 짜 봤습니다..! ㅎㅎ

새로고침하면 캐싱된 값이 초기화되는데, 캐시를 유지하고 싶으면 어떻게 할 수 있을까요?

프론트 단에서는 쿠키, 웹 스토리지, 캐시 api 정도가 있을 것 같네요!

}
};

fetch();

return () => setStatus(SEARCH_STATUS.LOADING);
Expand Down
2 changes: 2 additions & 0 deletions src/types/images.d.ts
Expand Up @@ -2,3 +2,5 @@ declare module '*.png';
declare module '*.jpg';
declare module '*.gif';
declare module '*.svg';
declare module '*.webp';
declare module '*.mp4';
24 changes: 16 additions & 8 deletions webpack.config.js
@@ -1,13 +1,16 @@
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;

module.exports = {
entry: './src/index.tsx',
resolve: { extensions: ['.ts', '.tsx', '.js', '.jsx'] },
output: {
filename: 'bundle.js',
filename: 'bundle.[chunkhash].js',
path: path.join(__dirname, '/dist'),
clean: true
},
Expand All @@ -18,16 +21,24 @@ module.exports = {
},
devtool: 'source-map',
plugins: [
new BundleAnalyzerPlugin(),
new HtmlWebpackPlugin({
template: './index.html'
}),
new CopyWebpackPlugin({
patterns: [{ from: './public', to: './public' }]
}),
new Dotenv()
new Dotenv(),
new MiniCssExtractPlugin({
filename: '[name].css'
})
Comment on lines +32 to +34

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css에는 hash 값을 부여하지 않은 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 별다른 이유는 없었습니다..! 다만 이번 미션에서 중점적으로 체크했던 파일이 js와 assets 쪽 파일이었고, 한 번 최적화 할 것을 생각해서 캐싱 관리 쪽은 신경을 안 썻던 것 같습니다.🥲

],
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader']
},
{
test: /\.(js|jsx|ts|tsx)$/i,
exclude: /node_modules/,
Expand All @@ -36,11 +47,7 @@ module.exports = {
}
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif|mp4|webm|webp)$/i,
loader: 'file-loader',
options: {
name: 'static/[name].[ext]'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

파일도 hash 값을 부여하지 않은 이유가 있을까요?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css와 이유는 살짝 겹치지만, 추가적으로 파일들은 변경사항이 거의 없다고 판단했습니다!

Expand All @@ -49,6 +56,7 @@ module.exports = {
]
},
optimization: {
minimize: false
splitChunks: { chunks: 'all' },

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all 옵션을 사용해서 비동기, 동기 청크를 공유했을 때 어떤 이점이 있었나요??

Copy link
Author

@D0Dam D0Dam Sep 10, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

비동기, 동기 청크를 공유한다는 것은 로드되는 모듈 간에 공통된 의존성을 가지게 된다는 것이라고 할 수 있습니다. 이 덕분에 중복된 코드가 줄어들고 번들 크기가 더욱 최적화 되는 효과를 얻을 수 있었습니다~!

minimizer: ['...', new CssMinimizerPlugin()]
}
};