diff --git a/frontend/lecture/src/components/StackBadge/index.tsx b/frontend/lecture/src/components/StackBadge/index.tsx new file mode 100644 index 0000000..1ef4ffa --- /dev/null +++ b/frontend/lecture/src/components/StackBadge/index.tsx @@ -0,0 +1,54 @@ +export const StackBadge = ({ + stack, +}: { + stack: + | 'Zustand' + | 'Jotai' + | 'Redux' + | 'Tanstack Query' + | 'SWR' + | 'Recoil' + | 'MobX' + | 'Sangte' + | 'Redux Toolkit' + | 'React' + | 'Claude Sonnet' + | 'v0' + | 'CSS' + | 'styled-components' + | 'emotion' + | 'Tailwind CSS'; +}) => { + const image = { + Zustand: + 'https://user-images.githubusercontent.com/958486/218346783-72be5ae3-b953-4dd7-b239-788a882fdad6.svg', + Jotai: 'https://cdn.candycode.com/jotai/jotai-mascot.png', + Redux: 'https://redux.js.org/img/redux.svg', + 'Tanstack Query': + 'https://seeklogo.com/images/R/react-query-logo-1340EA4CE9-seeklogo.com.png', + SWR: null, + Recoil: + 'https://d2eip9sf3oo6c2.cloudfront.net/tags/images/000/001/298/square_480/recoil.png', + MobX: 'https://mobx.js.org/assets/mobx.png', + Sangte: + 'https://www.npmjs.com/npm-avatar/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdmF0YXJVUkwiOiJodHRwczovL3MuZ3JhdmF0YXIuY29tL2F2YXRhci8yYjIzMTU0NTBkZjRmNzc3MmM0NTA5ZWQxNDEwNmI1OD9zaXplPTQ5NiZkZWZhdWx0PXJldHJvIn0.sJRQi6w4lEc74LfDpbf1VwBxVP8KEBuqEz601WqDH1s', + 'Redux Toolkit': 'https://redux.js.org/img/redux.svg', + React: + 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQo8BG6UD3b_Fowh4gtwIjw2GPTWQQ30uBy-w&s', + 'Claude Sonnet': + 'https://qph.cf2.poecdn.net/main-thumb-pb-1019-200-ecyfizaydihfkxfwhwjlruyjdyoxengr.jpeg', + v0: 'https://v0.dev/apple-icon.png?0ef31a19cc582b82', + CSS: 'https://upload.wikimedia.org/wikipedia/commons/thumb/6/62/CSS3_logo.svg/768px-CSS3_logo.svg.png', + 'styled-components': 'https://styled-components.com/logo.png', + emotion: 'https://avatars.githubusercontent.com/u/31557565?s=200&v=4', + 'Tailwind CSS': + 'https://seeklogo.com/images/T/tailwind-css-logo-5AD4175897-seeklogo.com.png', + }[stack]; + + return ( + + {image !== null && } + {stack} + + ); +}; diff --git a/frontend/lecture/src/lectures/Architecture/index.tsx b/frontend/lecture/src/lectures/Architecture/index.tsx index 7d428c3..c112a5e 100644 --- a/frontend/lecture/src/lectures/Architecture/index.tsx +++ b/frontend/lecture/src/lectures/Architecture/index.tsx @@ -6,6 +6,7 @@ import { CodeSnippet } from '@/components/CodeSnippet'; import { Description } from '@/components/Description'; import { ExternalLink } from '@/components/ExternalLink'; import { Slides } from '@/components/Slides'; +import { StackBadge } from '@/components/StackBadge'; import { getLectureItem } from '@/lectures'; export const architectureLecture = getLectureItem({ @@ -46,7 +47,10 @@ export const architectureLecture = getLectureItem({ 특히 요즘은 AI가 굉장히 빠르게 발전하고 있어서, 만드는 건{' '} 진짜 누구나 합니다 -
Claude Sonnet, v0 등등
+
+ , {' '} + 등등 +
(개인 생각) 점점 개발자의 역량은 잘 만드는 것 + 문제를 풀어내는 역량이 중요해질 것 diff --git a/frontend/lecture/src/lectures/Future/index.tsx b/frontend/lecture/src/lectures/Future/index.tsx new file mode 100644 index 0000000..9a9f93a --- /dev/null +++ b/frontend/lecture/src/lectures/Future/index.tsx @@ -0,0 +1,9 @@ +import { Slides } from '@/components/Slides'; +import { getLectureItem } from '@/lectures'; + +export const futureLecture = getLectureItem({ + title: '프론트엔드의 현재와 미래', + description: '기술 동향 파악하기, 생태계에 참여하기', + date: new Date('2024-11-20 20:30:00'), + element: , +}); diff --git a/frontend/lecture/src/lectures/Performance/index.tsx b/frontend/lecture/src/lectures/Performance/index.tsx index 37a71a4..2c6d5b2 100644 --- a/frontend/lecture/src/lectures/Performance/index.tsx +++ b/frontend/lecture/src/lectures/Performance/index.tsx @@ -145,7 +145,22 @@ export const performanceLecture = getLectureItem({ }, { title: '로딩 속도 개선: 용량 줄이기', content:
TBD
}, { title: '로딩 속도 개선: 스켈레톤 ui', content:
TBD
}, - { title: '로딩 속도 개선: 이미지 최적화', content:
TBD
}, + { + title: '로딩 속도 개선: SSR (1) CSR 방식에 대한 이해', + content:
TBD
, + }, + { + title: '로딩 속도 개선: SSR (2) SSR?', + content:
TBD
, + }, + { + title: '로딩 속도 개선: SSR (3) 서버 컴포넌트', + content:
TBD
, + }, + { + title: '로딩 속도 개선: SSR (4) 만능일까?', + content:
비용, 서버 리소스 관리, 프레임워크에 결합
, + }, ]} /> ), diff --git a/frontend/lecture/src/lectures/StateManagement/index.tsx b/frontend/lecture/src/lectures/StateManagement/index.tsx index dfdde58..0b6d7db 100644 --- a/frontend/lecture/src/lectures/StateManagement/index.tsx +++ b/frontend/lecture/src/lectures/StateManagement/index.tsx @@ -1,9 +1,311 @@ +import { Callout } from '@/components/Callout'; +import { CodeSnippet } from '@/components/CodeSnippet'; +import { ExternalLink } from '@/components/ExternalLink'; +import { InlineCode } from '@/components/InlineCode'; import { Slides } from '@/components/Slides'; +import { StackBadge } from '@/components/StackBadge'; import { getLectureItem } from '@/lectures'; export const stateManagementLecture = getLectureItem({ title: '상태 관리', description: '전역 상태 관리, Redux, React Query', date: new Date('2024-10-16 20:30:00'), - element: , + element: ( + +

+ 앞으로 여러 상태 관리 도구들을 만나게 될 텐데, 조금 더 친숙하게 + 공부할 수 있게 배경을 잡는다 +

+

+ 각 상태 관리 도구의 사용법을 다루진 않습니다. 과제에서도 다루지 + 않습니다. +

+

+ 리액트 경험이 충분하지 않다면 다소 뜬구름 잡는 이야기로 들릴 수 + 있습니다만, 그렇다고 안 할 수는 없는 이야기입니다. +

+

역사 얘기라고 생각하고 편하게 들어주세요

+
+ ), + }, + { + title: '상태 관리', + content: ( +
+

+ 세미나 1에서, 상태는 의 핵심 개념 + 중 하나라고 했었음 +

+

+ 따라서 상태를 잘 관리하는 게 중요하고, 사람들이 많이 어려워하는 + 것 중 하나 +

+

+ 이를 돕기 위한 여러 도구들이 존재하며, 사실상 상태관리 도구 없이 + 어플리케이션을 만드는 건 쉽지 않다 +

+

여러분도 토이프로젝트 가시면 뭐 하나는 쓰셔야 할 거예요

+
+ ), + }, + { + title: 'Redux (2015~현재)', + content: ( +
+

+ 2020년까지만 해도, 사실상 를 한다 =={' '} + 를 한다 였다 +

+

+ 그 시절 코드 +

+ `, + `

User Data

`, + `

Username: {username}

`, + `

Email: {email}

`, + ` {`, + ` updateUser({`, + ` username: 'NewUser',`, + ` email: 'new@example.com',`, + ` });`, + ` }}`, + ` >`, + ` Update User`, + ` `, + `
`, + ` );`, + ` }`, + `}`, + ``, + `const mapStateToProps = (state) => ({`, + ` username: state.user.username,`, + ` email: state.user.email`, + `});`, + ``, + `const mapDispatchToProps = (dispatch) => ({`, + ` updateUser: (userData) => dispatch({ type: 'UPDATE_USER', payload: userData })`, + `});`, + ``, + `export default connect(mapStateToProps, mapDispatchToProps)(UserData);`, + ]} + language="jsx" + /> + + ), + }, + { + title: 'Redux (2015~현재)', + content: ( +
+

+ 의 철학 +

+ +
+ state.user);`, + ` const dispatch = useDispatch();`, + ``, + ` return (`, + `
`, + `

User Data

`, + `

Username: {username}

`, + `

Email: {email}

`, + ` {`, + ` dispatch(updateUser({`, + ` username: 'NewUser',`, + ` email: 'new@example.com',`, + ` }));`, + ` }}`, + ` >`, + ` Update User`, + ` `, + `
`, + ` );`, + `}`, + ]} + language="jsx" + /> +
+

하지만 여러 문제점들도 있었는데,

+ +
+ ), + }, + { + title: 'Recoil (2020~현재)', + content: ( +
+

+ 의 철학 +

+ +
+

얘는 또 다른 문제가 있는데,

+ +
+ ), + }, + { + title: '그리고 다른 상태관리 라이브러리들', + content: ( +
+

+ 한때 , {' '} + 과 함께 삼대장이었던 + +

+

+ 가 발전한{' '} + +

+

+ 를 개선한{' '} + +

+

+ 을 개선한{' '} + +

+

+ 벨로퍼트님이 만드신 +

+

..등등

+
+ ), + }, + { + title: '그리고 게임 체인저: tanstack query (2020~)', + content: ( +
+ + + +
+

+ 맞는 말입니다. 기존의 를 그냥 + 좀더 이쁘게 감싸놓은 수준인 상태관리 도구들은 서버에서 받아온 + 데이터를 관리하는 문제를 잘 풀지 못했습니다. +

+

캐싱, 로딩, 폴링 등

+

+ 그래서 는 이런 데이터를{' '} + 서버 상태 라고 정의하고,{' '} + 서버 상태 관리 도구라고 자신을 소개합니다. +

+
+
+ ), + }, + { + title: '그리고 게임 체인저: tanstack query (2020~)', + content: ( +
+ {`, + ` const { data, isLoading, error, refetch } = useQuery({`, + ` queryKey: ['userData'],`, + ` queryFn: fetchUserData,`, + ` });`, + ``, + ` if (isLoading) return
Loading...
;`, + ` if (error) return
An error occurred: {error.message}
;`, + ``, + ` return (`, + `
`, + `

User Data

`, + `

Username: {data.username}

`, + `

Email: {data.email}

`, + `
`, + ` );`, + `}`, + ]} + language="jsx" + /> +

+ 이런 식으로, 서버에서 데이터를 가져오는 것을 훨씬 편하게 해 + 줬습니다. +

+

+ 캐싱, 재시도, 무효화 등 서버 데이터를 다루는 데 필수인 기능들도 + 물론 제공합니다. +

+

+ 비슷한 철학을 가진 이라는 + 라이브러리도 있습니다. +

+
+ ), + }, + { + title: '그래서 지금은 뭐가 가장 핫한가요?', + content: ( +
+

자료를 만드는 2024년 9월 16일 기준으로,

+

+ 클라이언트 상태관리 - 서버상태관리를 나누는 철학은 일반적인 + 컨셉이 되었습니다. +

+

+ 클라이언트 상태관리 도구는 사용하지 않거나{' '} + 중에 + 취향껏 쓰고, 서버 상태 관리 도구는{' '} + 를 쓰는 게 일반적입니다. +

+

+ 제 취향은 하나만 쓰고 + 클라이언트 상태관리는 모두 + 로 처리하는 것인데, 프로젝트 + 성격에 따라 다르긴 합니다 +

+
+ ), + }, + ]} + /> + ), }); diff --git a/frontend/lecture/src/lectures/Styling/index.tsx b/frontend/lecture/src/lectures/Styling/index.tsx index b0b9d0c..f33b76d 100644 --- a/frontend/lecture/src/lectures/Styling/index.tsx +++ b/frontend/lecture/src/lectures/Styling/index.tsx @@ -4,6 +4,7 @@ import { CodeSnippet } from '@/components/CodeSnippet'; import { ExternalLink } from '@/components/ExternalLink'; import { InlineCode } from '@/components/InlineCode'; import { Slides } from '@/components/Slides'; +import { StackBadge } from '@/components/StackBadge'; import { getLectureItem } from '@/lectures'; import cssIsAwesome from './cssisawesome.gif'; @@ -45,7 +46,7 @@ export const stylingLecture = getLectureItem({ content: (
- CSS (Cascading Style Sheets) + (Cascading Style Sheets)
브라우저 DOM 요소들에 스타일을 먹이는 언어
@@ -190,7 +191,10 @@ export const stylingLecture = getLectureItem({ title: 'CSS 생산성 - CSS in JS (2014~)', content: (
-
styled-components, emotion 등 라이브러리를 사용
+
+ ,{' '} + 등 라이브러리를 사용 +
취향에 맞는 걸 잘 찾아서 사용하자!
- 저는 Tailwind 를 가장 선호합니다 + 저는 를 가장 선호합니다
왜 Tailwind 가 제일 괜찮은지 30분 정도 떠들 수 있긴 한데 diff --git a/frontend/lecture/src/lectures/WrapUp/index.tsx b/frontend/lecture/src/lectures/WrapUp/index.tsx new file mode 100644 index 0000000..c2ffff6 --- /dev/null +++ b/frontend/lecture/src/lectures/WrapUp/index.tsx @@ -0,0 +1,9 @@ +import { Slides } from '@/components/Slides'; +import { getLectureItem } from '@/lectures'; + +export const wrapupLecture = getLectureItem({ + title: '마무리', + description: '', + date: new Date('2024-11-20 20:30:00'), + element: , +}); diff --git a/frontend/lecture/src/pages.tsx b/frontend/lecture/src/pages.tsx index 89eeadc..79a9414 100644 --- a/frontend/lecture/src/pages.tsx +++ b/frontend/lecture/src/pages.tsx @@ -11,6 +11,7 @@ import { architectureLecture } from '@/lectures/Architecture'; import { asyncLecture } from '@/lectures/Async/lecture'; import { dataFetchingLecture } from '@/lectures/DataFetching/lecture'; import { environmentLecture } from '@/lectures/Environment'; +import { futureLecture } from '@/lectures/Future'; import { infrastructureLecture } from '@/lectures/Infrastructure'; import { initializeProjectLecture } from '@/lectures/InitializeProject'; import { otLecture } from '@/lectures/OT'; @@ -21,6 +22,7 @@ import { stateManagementLecture } from '@/lectures/StateManagement'; import { stylingLecture } from '@/lectures/Styling'; import { typescriptLecture } from '@/lectures/TypeScript'; import { webBasicLecture } from '@/lectures/WebBasic/lecture'; +import { wrapupLecture } from '@/lectures/WrapUp'; import { Home } from '@/pages/home'; export const pages: ( @@ -56,22 +58,8 @@ export const pages: ( { path: '/state-management', ...stateManagementLecture }, { path: '/performance', ...performanceLecture }, { path: '/infrastructure', ...infrastructureLecture }, - { - type: 'lecture', - title: '생태계', - description: 'Next.js', - date: new Date('2024-11-20 20:30:00'), - path: '/meta-framework', - element:
TBD
, - }, - { - type: 'lecture', - title: '마무리', - description: '', - date: new Date('2024-11-20 20:30:00'), - path: '/end', - element:
TBD
, - }, + { path: '/future', ...futureLecture }, + { path: '/wrapup', ...wrapupLecture }, { path: '/como-0', ...getComoAssignment({ seminar: 0, due: new Date('2024-09-10 23:59:59') }),