diff --git a/package.json b/package.json index ad3b405..69f969f 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "lint-staged": "^15.5.1", "prettier": "^3.5.3", "prettier-plugin-tailwindcss": "^0.6.11", + "react-youtube": "^10.1.0", "tailwindcss": "^4", "tw-animate-css": "^1.2.9", "typescript": "^5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 54f3340..837076b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,6 +96,9 @@ importers: '@types/react-dom': specifier: ^19 version: 19.1.3(@types/react@19.1.3) + '@types/react-youtube': + specifier: ^7.10.0 + version: 7.10.0(react@19.1.0) '@typescript-eslint/eslint-plugin': specifier: ^8.32.0 version: 8.32.0(@typescript-eslint/parser@8.32.0(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.26.0(jiti@2.4.2))(typescript@5.8.3) @@ -123,6 +126,9 @@ importers: prettier-plugin-tailwindcss: specifier: ^0.6.11 version: 0.6.11(@trivago/prettier-plugin-sort-imports@5.2.2(prettier@3.5.3))(prettier@3.5.3) + react-youtube: + specifier: ^10.1.0 + version: 10.1.0(react@19.1.0) tailwindcss: specifier: ^4 version: 4.1.5 @@ -929,6 +935,10 @@ packages: peerDependencies: '@types/react': ^19.0.0 + '@types/react-youtube@7.10.0': + resolution: {integrity: sha512-RtEyYn9kze525y1DIpNByvKCj2mwqAuPIAZx+HVJMsK7cXIWbOLemYNsBHSInMhjeGRiKDEz4pIgLX1mAGbDqQ==} + deprecated: This is a stub types definition. react-youtube provides its own type definitions, so you do not need this installed. + '@types/react@19.1.3': resolution: {integrity: sha512-dLWQ+Z0CkIvK1J8+wrDPwGxEYFA4RAyHoZPxHVGspYmFVnwGSNT24cGIhFJrtfRnWVuW8X7NO52gCXmhkVUWGQ==} @@ -1350,6 +1360,14 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@3.2.7: resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} peerDependencies: @@ -2233,6 +2251,9 @@ packages: resolution: {integrity: sha512-vsBzcU4oE+v0lj4FhVLzr9dBTv4/fHIa57l+GCwovP8MoFNZJTOhGU8PXd4v2VJCbECAaijBiHntiekFMLvo0g==} engines: {node: '>=18.0.0'} + load-script@1.0.0: + resolution: {integrity: sha512-kPEjMFtZvwL9TaZo0uZ2ml+Ye9HUMmPwbYRJ324qF9tqMejwykJ5ggTyvzmrbBeapCAbk98BSbTeovHEEP1uCA==} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -2482,6 +2503,9 @@ packages: minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -2832,6 +2856,12 @@ packages: '@types/react': optional: true + react-youtube@10.1.0: + resolution: {integrity: sha512-ZfGtcVpk0SSZtWCSTYOQKhfx5/1cfyEW1JN/mugGNfAxT3rmVJeMbGpA9+e78yG21ls5nc/5uZJETE3cm3knBg==} + engines: {node: '>= 14.x'} + peerDependencies: + react: '>=0.14.1' + react@19.1.0: resolution: {integrity: sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==} engines: {node: '>=0.10.0'} @@ -3011,6 +3041,9 @@ packages: simple-swizzle@0.2.2: resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + sister@3.0.2: + resolution: {integrity: sha512-p19rtTs+NksBRKW9qn0UhZ8/TUI9BPw9lmtHny+Y3TinWlOa9jWh9xB0AtPSdmOy49NJJJSSe0Ey4C7h0TrcYA==} + slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} @@ -3364,6 +3397,9 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + youtube-player@5.5.2: + resolution: {integrity: sha512-ZGtsemSpXnDky2AUYWgxjaopgB+shFHgXVpiJFeNB5nWEugpW1KWYDaHKuLqh2b67r24GtP6HoSW5swvf0fFIQ==} + zod-to-json-schema@3.24.5: resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} peerDependencies: @@ -4104,6 +4140,13 @@ snapshots: dependencies: '@types/react': 19.1.3 + '@types/react-youtube@7.10.0(react@19.1.0)': + dependencies: + react-youtube: 10.1.0(react@19.1.0) + transitivePeerDependencies: + - react + - supports-color + '@types/react@19.1.3': dependencies: csstype: 3.1.3 @@ -4536,6 +4579,10 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + debug@2.6.9: + dependencies: + ms: 2.0.0 + debug@3.2.7: dependencies: ms: 2.1.3 @@ -5655,6 +5702,8 @@ snapshots: rfdc: 1.4.1 wrap-ansi: 9.0.0 + load-script@1.0.0: {} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -6159,6 +6208,8 @@ snapshots: minimist@1.2.8: {} + ms@2.0.0: {} + ms@2.1.3: {} nanoid@3.3.11: {} @@ -6452,6 +6503,15 @@ snapshots: optionalDependencies: '@types/react': 19.1.3 + react-youtube@10.1.0(react@19.1.0): + dependencies: + fast-deep-equal: 3.1.3 + prop-types: 15.8.1 + react: 19.1.0 + youtube-player: 5.5.2 + transitivePeerDependencies: + - supports-color + react@19.1.0: {} recma-build-jsx@1.0.0: @@ -6765,6 +6825,8 @@ snapshots: is-arrayish: 0.3.2 optional: true + sister@3.0.2: {} + slash@3.0.0: {} slice-ansi@5.0.0: @@ -7190,6 +7252,14 @@ snapshots: yocto-queue@0.1.0: {} + youtube-player@5.5.2: + dependencies: + debug: 2.6.9 + load-script: 1.0.0 + sister: 3.0.2 + transitivePeerDependencies: + - supports-color + zod-to-json-schema@3.24.5(zod@3.24.4): dependencies: zod: 3.24.4 diff --git a/src/features/post/contents/react-compiler.mdx b/src/features/post/contents/react-compiler.mdx index 1baac4a..7b90c33 100644 --- a/src/features/post/contents/react-compiler.mdx +++ b/src/features/post/contents/react-compiler.mdx @@ -16,10 +16,14 @@ thumbnail: '/images/react-compiler-thumbnail.webp' 그러던 중 우연히 유튜브 숏츠를 보다가 제로초 채널에서 React Compiler 1.0에 대해 소개하는 영상을 만나보게 되었다. + + [리액트가 알아서 성능최적화를 해준다...? (React compiler, 리액트 컴파일러 정식 출시)](https://youtube.com/shorts/JVKT7z8w5q0?si=fqdeVTPfRInWCMkY) 대충 React.memo, useMemo, useCallback 등을 사용하지 않아도 React가 알아서 성능 최적화를 해준다는 내용이었다. 조금 더 찾아보니 실제로 코드를 작성해보며 리액트 컴파일러를 사용했을때와 하지 않았을때를 비교하는 영상도 발견할 수 있었다. + + [React Compiler 1.0 완벽 정리|드디어 베타 끝!](https://youtu.be/4WyLSzwRMGg?si=zrW_HlS4vNeAGuHj) 이 영상을 통해 리액트 컴파일러를 사용하게 되면 React 에서 알아서 불필요한 리렌더링을 방지해주고, 메모이제이션 또한 자동으로 처리해준다는 것을 알 수 있었다. diff --git a/src/shared/components/features/mdx/MDXComponents.tsx b/src/shared/components/features/mdx/MDXComponents.tsx index a0591db..5bcf237 100644 --- a/src/shared/components/features/mdx/MDXComponents.tsx +++ b/src/shared/components/features/mdx/MDXComponents.tsx @@ -1,5 +1,7 @@ import type { MDXComponents } from 'mdx/types'; +import { YouTube } from '../youtube'; + export const mdxComponents: MDXComponents = { // 제목 스타일링 (반응형) h1: ({ children }) => ( @@ -121,4 +123,6 @@ export const mdxComponents: MDXComponents = { {children} ), + + YouTube, }; diff --git a/src/shared/components/features/youtube/YouTubeEmbed.tsx b/src/shared/components/features/youtube/YouTubeEmbed.tsx new file mode 100644 index 0000000..bb3be4d --- /dev/null +++ b/src/shared/components/features/youtube/YouTubeEmbed.tsx @@ -0,0 +1,31 @@ +'use client'; + +import YouTube, { YouTubeProps } from 'react-youtube'; + +type Props = { + videoId: string; + title: string; +}; + +export const YouTubeEmbed = ({ videoId, title }: Props) => { + const opts: YouTubeProps['opts'] = { + width: '100%', + height: '100%', + playerVars: { + autoplay: 0, + modestbranding: 1, + rel: 0, + }, + }; + + return ( +
+ +
+ ); +}; diff --git a/src/shared/components/features/youtube/index.ts b/src/shared/components/features/youtube/index.ts new file mode 100644 index 0000000..19418f5 --- /dev/null +++ b/src/shared/components/features/youtube/index.ts @@ -0,0 +1 @@ +export { YouTubeEmbed as YouTube } from './YouTubeEmbed';