Skip to content

Commit 2bf6a2b

Browse files
authored
Merge pull request #172 from boostcamp-2020/dev
최적화 적용 및 배포
2 parents 4838f44 + da3a1a4 commit 2bf6a2b

File tree

8 files changed

+105
-37
lines changed

8 files changed

+105
-37
lines changed

client/src/components/ThreadListBox/ThreadListHeader/ChannelModal/ShowUsersModal/ShowUsersModalBody/ShowUsersModalBody.tsx

+7-12
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useChannelState } from '@/hooks';
55
import { JoinedUser } from '@/types';
66
import { CancelButton as CB } from '@/styles/shared';
77
import { USER_DEFAULT_PROFILE_URL } from '@/utils/constants';
8+
import { LazyImage } from '@/components/common';
89

910
const Container = styled.div`
1011
padding: 0 4px;
@@ -23,7 +24,7 @@ const Remove = styled(CB)`
2324
const SearchedUserContainer = styled.div`
2425
width: 100%;
2526
height: 15rem;
26-
overflow-y: scroll;
27+
overflow-y: auto;
2728
padding: 0 24px;
2829
`;
2930

@@ -40,13 +41,6 @@ const SearchedUserBox = styled.div`
4041
}
4142
`;
4243

43-
const ProfileImg = styled.img`
44-
width: 2.25rem;
45-
height: 2.25rem;
46-
object-fit: cover;
47-
border-radius: 5px;
48-
`;
49-
5044
const UserName = styled.div`
5145
font-size: 1rem;
5246
margin: 0 0.7rem;
@@ -65,11 +59,12 @@ const ShowUsersModalBody: React.FC = () => {
6559
<SearchedUserContainer>
6660
{users?.map((user: JoinedUser) => (
6761
<SearchedUserBox key={user.userId}>
68-
<ProfileImg
62+
<LazyImage
63+
width="36"
64+
height="36"
6965
src={user.image}
70-
onError={(e: React.SyntheticEvent<HTMLImageElement, Event>) => {
71-
e.currentTarget.src = USER_DEFAULT_PROFILE_URL;
72-
}}
66+
style={{ objectFit: 'cover', borderRadius: '5px' }}
67+
errorImage={USER_DEFAULT_PROFILE_URL}
7368
/>
7469
<UserName>{user.displayName}</UserName>
7570
</SearchedUserBox>

client/src/components/ThreadListBox/ThreadListHeader/ThreadListHeader.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ const ThreadListHeader = () => {
145145
body={<ShowUsersModalBody />}
146146
visible={showUsersModalVisible}
147147
setVisible={clickShowUsersModal}
148+
bodyScroll={false}
148149
/>
149150
)}
150151
<Container>

client/src/components/common/DimModal/DimModal.tsx

+13-3
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,18 @@ const Title = styled.div`
5353
flex: 1;
5454
`;
5555

56-
const Body = styled.div`
56+
interface BodyProps {
57+
bodyScroll: boolean;
58+
}
59+
60+
const Body = styled.div<BodyProps>`
5761
width: 100%;
5862
border-radius: 0 0 5px 5px;
59-
overflow: auto;
63+
${(props) =>
64+
props.bodyScroll &&
65+
css`
66+
overflow: auto;
67+
`}
6068
`;
6169

6270
const CloseIcon = styled.div`
@@ -70,6 +78,7 @@ interface DimModalProps {
7078
visible: boolean;
7179
setVisible: (a: any) => any;
7280
width?: string;
81+
bodyScroll?: boolean;
7382
}
7483

7584
const DimModal: React.FC<PropsWithChildren<DimModalProps>> = ({
@@ -78,6 +87,7 @@ const DimModal: React.FC<PropsWithChildren<DimModalProps>> = ({
7887
visible,
7988
setVisible,
8089
width,
90+
bodyScroll = true,
8191
}: PropsWithChildren<DimModalProps>) => {
8292
const containerRef = useRef<HTMLDivElement>(null);
8393

@@ -101,7 +111,7 @@ const DimModal: React.FC<PropsWithChildren<DimModalProps>> = ({
101111
<ModalCloseBox handleClose={handleClose} />
102112
</CloseIcon>
103113
</Header>
104-
<Body>{body}</Body>
114+
<Body bodyScroll={bodyScroll}>{body}</Body>
105115
</Container>
106116
</DimLayer>
107117
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React, { useEffect, useRef, useState } from 'react';
2+
import styled from 'styled-components';
3+
4+
interface Props {
5+
src: string;
6+
width: string;
7+
height: string;
8+
style?: any;
9+
errorImage?: string;
10+
}
11+
12+
const Img = styled.img`
13+
object-fit: cover;
14+
border-radius: 5px;
15+
`;
16+
17+
const LazyImage: React.FC<Props> = ({ src, width, height, style, errorImage }: Props) => {
18+
const imgRef = useRef<HTMLImageElement>(null);
19+
const [isLoad, setIsLoad] = useState(false);
20+
21+
function onIntersection(entries: IntersectionObserverEntry[], io: IntersectionObserver) {
22+
entries.forEach((entry) => {
23+
if (entry.isIntersecting) {
24+
io.unobserve(entry.target);
25+
setIsLoad(true);
26+
}
27+
});
28+
}
29+
30+
useEffect(() => {
31+
const observer = new IntersectionObserver(onIntersection, {
32+
threshold: 0,
33+
});
34+
35+
if (imgRef.current) {
36+
observer.observe(imgRef.current);
37+
}
38+
}, [imgRef]);
39+
40+
return (
41+
<Img
42+
ref={imgRef}
43+
src={isLoad ? src : `https://via.placeholder.com/${width}x${height}`}
44+
width={width}
45+
height={height}
46+
style={style}
47+
onError={(e: React.SyntheticEvent<HTMLImageElement, Event>) => {
48+
e.currentTarget.src = errorImage ?? `https://via.placeholder.com/${width}x${height}`;
49+
}}
50+
/>
51+
);
52+
};
53+
54+
LazyImage.defaultProps = {
55+
style: {},
56+
errorImage: undefined,
57+
};
58+
59+
export default LazyImage;

client/src/components/common/ThreadItem/EmojiBox/EmojiBoxItem/EmojiBoxItem.tsx

+19-6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useChannelState, useEmojiState, useUserState } from '@/hooks';
66
import { useDispatch } from 'react-redux';
77
import { SOCKET_MESSAGE_TYPE } from '@/utils/constants';
88
import { sendMessageRequest } from '@/store/modules/socket.slice';
9+
import LazyImage from '@/components/common/LazyImage/LazyImage';
910
import TooltipPopup from './TooltipPopup/TooltipPopup';
1011

1112
interface ContainerProps {
@@ -107,10 +108,12 @@ const EmojiBoxItem: React.FC<EmojiBoxItemProps> = ({ emoji, thread }: EmojiBoxIt
107108
return `${getEmojiName(emojiId)}`;
108109
};
109110

110-
const getEmojiUrl = (emojiId: number) => {
111-
return emojiList?.find((emojiEl) => {
112-
return emojiEl.id === emojiId;
113-
})?.url;
111+
const getEmojiUrl = (emojiId: number): string => {
112+
return (
113+
emojiList?.find((emojiEl) => {
114+
return emojiEl.id === emojiId;
115+
})?.url ?? 'https://via.placeholder.com/40'
116+
);
114117
};
115118

116119
const clickEmojiHandler = () => {
@@ -142,7 +145,17 @@ const EmojiBoxItem: React.FC<EmojiBoxItemProps> = ({ emoji, thread }: EmojiBoxIt
142145
{ref.current && tooltipVisible && (
143146
<TooltipPopup anchorEl={ref.current} top={-10} left={-30}>
144147
<EmojiToolTip>
145-
<TooltipImg src={getEmojiUrl(emoji.id)} />
148+
<LazyImage
149+
src={getEmojiUrl(emoji.id)}
150+
width="36"
151+
height="36"
152+
style={{
153+
marginBottom: '0.4rem',
154+
backgroundColor: 'white',
155+
borderRadius: '8px',
156+
padding: '4px',
157+
}}
158+
/>
146159
<ToolTipDescribe>
147160
{getUserListNameInEmoji(emoji)}
148161
{`reacted with :${getToolTipDescribe(emoji.id)}:`}
@@ -151,7 +164,7 @@ const EmojiBoxItem: React.FC<EmojiBoxItemProps> = ({ emoji, thread }: EmojiBoxIt
151164
</TooltipPopup>
152165
)}
153166
<EmojiItem>
154-
<img src={getEmojiUrl(emoji.id)} alt="emoji url" width="16px" height="16px" />
167+
<LazyImage src={getEmojiUrl(emoji.id)} width="16px" height="16px" />
155168
{emoji.userList && <EmojiCount>{emoji.userList.length}</EmojiCount>}
156169
</EmojiItem>
157170
</Container>

client/src/components/common/ThreadItem/ThreadItem.tsx

+5-5
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,10 @@ import styled, { css } from 'styled-components';
33
import { Thread } from '@/types';
44
import { flex, hoverUnderline } from '@/styles/mixin';
55
import { USER_DEFAULT_PROFILE_URL } from '@/utils/constants';
6+
import { TrashIcon, LazyImage } from '@/components';
67
import ReplyButton from './ReplyButton/ReplyButton';
78
import ThreadPopup from './ThreadPopup/ThreadPopup';
89
import EmojiBox from './EmojiBox/EmojiBox';
9-
import { TrashIcon } from '../Icon';
1010

1111
const Container = styled.div`
1212
position: relative;
@@ -184,11 +184,11 @@ const ThreadItem: React.FC<ThreadItemProps> = ({
184184
</DeletedItemImgBox>
185185
) : (
186186
<UserImgBox>
187-
<UserImg
187+
<LazyImage
188188
src={thread.image}
189-
onError={(e: React.SyntheticEvent<HTMLImageElement, Event>) => {
190-
e.currentTarget.src = USER_DEFAULT_PROFILE_URL;
191-
}}
189+
width="36"
190+
height="36"
191+
errorImage={USER_DEFAULT_PROFILE_URL}
192192
/>
193193
</UserImgBox>
194194
)}

client/src/components/common/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export { default as Popover } from './Popover/Popover';
1010
export { default as CloseIconBox } from './CloseIconBox/CloseIconBox';
1111
export * from './AddUsersModal';
1212
export { default as LogoBox } from './LogoBox/LogoBox';
13+
export { default as LazyImage } from './LazyImage/LazyImage';

client/webpack.config.js

-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ const path = require('path');
22
const HtmlWebpackPlugin = require('html-webpack-plugin');
33
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
44
const Dotenv = require('dotenv-webpack');
5-
const TerserPlugin = require('terser-webpack-plugin');
65

76
module.exports = {
87
devtool: 'source-map',
@@ -99,16 +98,6 @@ module.exports = {
9998
runtimeChunk: {
10099
name: (entrypoint) => `runtime-${entrypoint.name}`,
101100
},
102-
minimize: true,
103-
minimizer: [
104-
new TerserPlugin({
105-
terserOptions: {
106-
compress: {
107-
drop_console: true,
108-
},
109-
},
110-
}),
111-
],
112101
},
113102
devServer: {
114103
contentBase: path.join(__dirname, './dist'),

0 commit comments

Comments
 (0)